From f155f7d6e50c702f65858774cfd02ef60aa9cad5 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Tue, 12 Aug 2025 08:45:02 +0000 Subject: [PATCH] 8364141: Remove LockingMode related code from x86 Reviewed-by: aboldtch, dholmes, coleenp --- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 16 +- src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 2 +- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 79 +---- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 272 +++--------------- src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 7 +- src/hotspot/cpu/x86/interp_masm_x86.cpp | 169 ++--------- src/hotspot/cpu/x86/sharedRuntime_x86.cpp | 15 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 79 +---- .../x86/templateInterpreterGenerator_x86.cpp | 25 +- src/hotspot/cpu/x86/x86_64.ad | 27 -- 10 files changed, 91 insertions(+), 600 deletions(-) diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 0176ff967ce..a30bbe08c55 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -413,11 +413,7 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::rax_opr); stub = new MonitorExitStub(FrameMap::rax_opr, true, 0); - if (LockingMode == LM_MONITOR) { - __ jmp(*stub->entry()); - } else { - __ unlock_object(rdi, rsi, rax, *stub->entry()); - } + __ unlock_object(rdi, rsi, rax, *stub->entry()); __ bind(*stub->continuation()); } @@ -2733,15 +2729,9 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register obj = op->obj_opr()->as_register(); // may not be an oop Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); - if (LockingMode == LM_MONITOR) { - if (op->info() != nullptr) { - add_debug_info_for_null_check_here(op->info()); - __ null_check(obj); - } - __ jmp(*op->stub()->entry()); - } else if (op->code() == lir_lock) { + if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - Register tmp = LockingMode == LM_LIGHTWEIGHT ? op->scratch_opr()->as_register() : noreg; + Register tmp = op->scratch_opr()->as_register(); // add debug info for NullPointerException only if one is possible int null_check_offset = __ lock_object(hdr, obj, lock, tmp, *op->stub()->entry()); if (op->info() != nullptr) { diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 3bd86d9b7e5..1fdfcc4f9cd 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -289,7 +289,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { // this CodeEmitInfo must not have the xhandlers because here the // object is already locked (xhandlers expect object to be unlocked) CodeEmitInfo* info = state_for(x, x->state(), true); - LIR_Opr tmp = LockingMode == LM_LIGHTWEIGHT ? new_register(T_ADDRESS) : LIR_OprFact::illegalOpr; + LIR_Opr tmp = new_register(T_ADDRESS); monitor_enter(obj.result(), lock, syncTempOpr(), tmp, x->monitor_no(), info_for_exception, info); } diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index c9d103768b8..36efeafa940 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -42,8 +42,6 @@ #include "utilities/globalDefinitions.hpp" int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case) { - const int aligned_mask = BytesPerWord -1; - const int hdr_offset = oopDesc::mark_offset_in_bytes(); assert(hdr == rax, "hdr must be rax, for the cmpxchg instruction"); assert_different_registers(hdr, obj, disp_hdr, tmp); int null_check_offset = -1; @@ -55,93 +53,20 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); - } else if (LockingMode == LM_LEGACY) { - Label done; - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj, rscratch1); - testb(Address(hdr, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, slow_case); - } - - // Load object header - movptr(hdr, Address(obj, hdr_offset)); - // and mark it as unlocked - orptr(hdr, markWord::unlocked_value); - // save unlocked object header into the displaced header location on the stack - movptr(Address(disp_hdr, 0), hdr); - // test if object header is still the same (i.e. unlocked), and if so, store the - // displaced header address in the object header - if it is not the same, get the - // object header instead - MacroAssembler::lock(); // must be immediately before cmpxchg! - cmpxchgptr(disp_hdr, Address(obj, hdr_offset)); - // if the object header was the same, we're done - jcc(Assembler::equal, done); - // if the object header was not the same, it is now in the hdr register - // => test if it is a stack pointer into the same stack (recursive locking), i.e.: - // - // 1) (hdr & aligned_mask) == 0 - // 2) rsp <= hdr - // 3) hdr <= rsp + page_size - // - // these 3 tests can be done by evaluating the following expression: - // - // (hdr - rsp) & (aligned_mask - page_size) - // - // assuming both the stack pointer and page_size have their least - // significant 2 bits cleared and page_size is a power of 2 - subptr(hdr, rsp); - andptr(hdr, aligned_mask - (int)os::vm_page_size()); - // for recursive locking, the result is zero => save it in the displaced header - // location (null in the displaced hdr location indicates recursive locking) - movptr(Address(disp_hdr, 0), hdr); - // otherwise we don't care about the result and handle locking via runtime call - jcc(Assembler::notZero, slow_case); - // done - bind(done); - inc_held_monitor_count(); - } + lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); return null_check_offset; } void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { - const int aligned_mask = BytesPerWord -1; - const int hdr_offset = oopDesc::mark_offset_in_bytes(); assert(disp_hdr == rax, "disp_hdr must be rax, for the cmpxchg instruction"); assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); - Label done; - - if (LockingMode != LM_LIGHTWEIGHT) { - // load displaced header - movptr(hdr, Address(disp_hdr, 0)); - // if the loaded hdr is null we had recursive locking - testptr(hdr, hdr); - // if we had recursive locking, we are done - jcc(Assembler::zero, done); - } // load object movptr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); verify_oop(obj); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj, disp_hdr, hdr, slow_case); - } else if (LockingMode == LM_LEGACY) { - // test if object header is pointing to the displaced header, and if so, restore - // the displaced header in the object - if the object header is not pointing to - // the displaced header, get the object header instead - MacroAssembler::lock(); // must be immediately before cmpxchg! - cmpxchgptr(hdr, Address(obj, hdr_offset)); - // if the object header was not pointing to the displaced header, - // we do unlocking via runtime call - jcc(Assembler::notEqual, slow_case); - // done - bind(done); - dec_held_monitor_count(); - } + lightweight_unlock(obj, disp_hdr, hdr, slow_case); } diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index b5b65171e32..8c3f33e0aca 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -219,244 +219,11 @@ inline Assembler::AvxVectorLen C2_MacroAssembler::vector_length_encoding(int vle // obj: object to lock -// box: on-stack box address (displaced header location) - KILLED -// rax,: tmp -- KILLED -// scr: tmp -- KILLED -void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg, - Register scrReg, Register cx1Reg, Register cx2Reg, Register thread, - Metadata* method_data) { - assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_lock_lightweight"); - // Ensure the register assignments are disjoint - assert(tmpReg == rax, ""); - assert(cx1Reg == noreg, ""); - assert(cx2Reg == noreg, ""); - assert_different_registers(objReg, boxReg, tmpReg, scrReg); - - // Possible cases that we'll encounter in fast_lock - // ------------------------------------------------ - // * Inflated - // -- unlocked - // -- Locked - // = by self - // = by other - // * neutral - // * stack-locked - // -- by self - // = sp-proximity test hits - // = sp-proximity test generates false-negative - // -- by other - // - - Label IsInflated, DONE_LABEL, NO_COUNT, COUNT; - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmpReg, objReg, scrReg); - testb(Address(tmpReg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, DONE_LABEL); - } - - movptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // [FETCH] - testptr(tmpReg, markWord::monitor_value); // inflated vs stack-locked|neutral - jcc(Assembler::notZero, IsInflated); - - if (LockingMode == LM_MONITOR) { - // Clear ZF so that we take the slow path at the DONE label. objReg is known to be not 0. - testptr(objReg, objReg); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Attempt stack-locking ... - orptr (tmpReg, markWord::unlocked_value); - movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS - lock(); - cmpxchgptr(boxReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Updates tmpReg - jcc(Assembler::equal, COUNT); // Success - - // Recursive locking. - // The object is stack-locked: markword contains stack pointer to BasicLock. - // Locked by current thread if difference with current SP is less than one page. - subptr(tmpReg, rsp); - // Next instruction set ZFlag == 1 (Success) if difference is less then one page. - andptr(tmpReg, (int32_t) (7 - (int)os::vm_page_size()) ); - movptr(Address(boxReg, 0), tmpReg); - } - jmp(DONE_LABEL); - - bind(IsInflated); - // The object is inflated. tmpReg contains pointer to ObjectMonitor* + markWord::monitor_value - - // Unconditionally set box->_displaced_header = markWord::unused_mark(). - // Without cast to int32_t this style of movptr will destroy r10 which is typically obj. - movptr(Address(boxReg, 0), checked_cast(markWord::unused_mark().value())); - - // It's inflated and we use scrReg for ObjectMonitor* in this section. - movptr(boxReg, Address(r15_thread, JavaThread::monitor_owner_id_offset())); - movq(scrReg, tmpReg); - xorq(tmpReg, tmpReg); - lock(); - cmpxchgptr(boxReg, Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); - - // Propagate ICC.ZF from CAS above into DONE_LABEL. - jccb(Assembler::equal, COUNT); // CAS above succeeded; propagate ZF = 1 (success) - - cmpptr(boxReg, rax); // Check if we are already the owner (recursive lock) - jccb(Assembler::notEqual, NO_COUNT); // If not recursive, ZF = 0 at this point (fail) - incq(Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - xorq(rax, rax); // Set ZF = 1 (success) for recursive lock, denoting locking success - bind(DONE_LABEL); - - // ZFlag == 1 count in fast path - // ZFlag == 0 count in slow path - jccb(Assembler::notZero, NO_COUNT); // jump if ZFlag == 0 - - bind(COUNT); - if (LockingMode == LM_LEGACY) { - // Count monitors in fast path - increment(Address(thread, JavaThread::held_monitor_count_offset())); - } - xorl(tmpReg, tmpReg); // Set ZF == 1 - - bind(NO_COUNT); - - // At NO_COUNT the icc ZFlag is set as follows ... - // fast_unlock uses the same protocol. - // ZFlag == 1 -> Success - // ZFlag == 0 -> Failure - force control through the slow path -} - -// obj: object to unlock -// box: box address (displaced header location), killed. Must be EAX. -// tmp: killed, cannot be obj nor box. -// -// Some commentary on balanced locking: -// -// fast_lock and fast_unlock are emitted only for provably balanced lock sites. -// Methods that don't have provably balanced locking are forced to run in the -// interpreter - such methods won't be compiled to use fast_lock and fast_unlock. -// The interpreter provides two properties: -// I1: At return-time the interpreter automatically and quietly unlocks any -// objects acquired the current activation (frame). Recall that the -// interpreter maintains an on-stack list of locks currently held by -// a frame. -// I2: If a method attempts to unlock an object that is not held by the -// the frame the interpreter throws IMSX. -// -// Lets say A(), which has provably balanced locking, acquires O and then calls B(). -// B() doesn't have provably balanced locking so it runs in the interpreter. -// Control returns to A() and A() unlocks O. By I1 and I2, above, we know that O -// is still locked by A(). -// -// The only other source of unbalanced locking would be JNI. The "Java Native Interface: -// Programmer's Guide and Specification" claims that an object locked by jni_monitorenter -// should not be unlocked by "normal" java-level locking and vice-versa. The specification -// doesn't specify what will occur if a program engages in such mixed-mode locking, however. -// Arguably given that the spec legislates the JNI case as undefined our implementation -// could reasonably *avoid* checking owner in fast_unlock(). -// In the interest of performance we elide m->Owner==Self check in unlock. -// A perfectly viable alternative is to elide the owner check except when -// Xcheck:jni is enabled. - -void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg) { - assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_unlock_lightweight"); - assert(boxReg == rax, ""); - assert_different_registers(objReg, boxReg, tmpReg); - - Label DONE_LABEL, Stacked, COUNT, NO_COUNT; - - if (LockingMode == LM_LEGACY) { - cmpptr(Address(boxReg, 0), NULL_WORD); // Examine the displaced header - jcc (Assembler::zero, COUNT); // 0 indicates recursive stack-lock - } - movptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Examine the object's markword - if (LockingMode != LM_MONITOR) { - testptr(tmpReg, markWord::monitor_value); // Inflated? - jcc(Assembler::zero, Stacked); - } - - // It's inflated. - - // Despite our balanced locking property we still check that m->_owner == Self - // as java routines or native JNI code called by this thread might - // have released the lock. - // - // If there's no contention try a 1-0 exit. That is, exit without - // a costly MEMBAR or CAS. See synchronizer.cpp for details on how - // we detect and recover from the race that the 1-0 exit admits. - // - // Conceptually fast_unlock() must execute a STST|LDST "release" barrier - // before it STs null into _owner, releasing the lock. Updates - // to data protected by the critical section must be visible before - // we drop the lock (and thus before any other thread could acquire - // the lock and observe the fields protected by the lock). - // IA32's memory-model is SPO, so STs are ordered with respect to - // each other and there's no need for an explicit barrier (fence). - // See also http://gee.cs.oswego.edu/dl/jmm/cookbook.html. - Label LSuccess, LNotRecursive; - - cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0); - jccb(Assembler::equal, LNotRecursive); - - // Recursive inflated unlock - decrement(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - jmpb(LSuccess); - - bind(LNotRecursive); - - // Set owner to null. - // Release to satisfy the JMM - movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); - // We need a full fence after clearing owner to avoid stranding. - // StoreLoad achieves this. - membar(StoreLoad); - - // Check if the entry_list is empty. - cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(entry_list)), NULL_WORD); - jccb(Assembler::zero, LSuccess); // If so we are done. - - // Check if there is a successor. - cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); - jccb(Assembler::notZero, LSuccess); // If so we are done. - - // Save the monitor pointer in the current thread, so we can try to - // reacquire the lock in SharedRuntime::monitor_exit_helper(). - andptr(tmpReg, ~(int32_t)markWord::monitor_value); - movptr(Address(r15_thread, JavaThread::unlocked_inflated_monitor_offset()), tmpReg); - - orl (boxReg, 1); // set ICC.ZF=0 to indicate failure - jmpb (DONE_LABEL); - - bind (LSuccess); - testl (boxReg, 0); // set ICC.ZF=1 to indicate success - jmpb (DONE_LABEL); - - if (LockingMode == LM_LEGACY) { - bind (Stacked); - movptr(tmpReg, Address (boxReg, 0)); // re-fetch - lock(); - cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box - // Intentional fall-thru into DONE_LABEL - } - - bind(DONE_LABEL); - - // ZFlag == 1 count in fast path - // ZFlag == 0 count in slow path - jccb(Assembler::notZero, NO_COUNT); - - bind(COUNT); - - if (LockingMode == LM_LEGACY) { - // Count monitors in fast path - decrementq(Address(r15_thread, JavaThread::held_monitor_count_offset())); - } - - xorl(tmpReg, tmpReg); // Set ZF == 1 - - bind(NO_COUNT); -} - +// box: on-stack box address -- KILLED +// rax: tmp -- KILLED +// t : tmp -- KILLED void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register rax_reg, Register t, Register thread) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(rax_reg == rax, "Used for CAS"); assert_different_registers(obj, box, rax_reg, t, thread); @@ -616,8 +383,39 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist // C2 uses the value of ZF to determine the continuation. } +// obj: object to lock +// rax: tmp -- KILLED +// t : tmp - cannot be obj nor rax -- KILLED +// +// Some commentary on balanced locking: +// +// fast_lock and fast_unlock are emitted only for provably balanced lock sites. +// Methods that don't have provably balanced locking are forced to run in the +// interpreter - such methods won't be compiled to use fast_lock and fast_unlock. +// The interpreter provides two properties: +// I1: At return-time the interpreter automatically and quietly unlocks any +// objects acquired in the current activation (frame). Recall that the +// interpreter maintains an on-stack list of locks currently held by +// a frame. +// I2: If a method attempts to unlock an object that is not held by the +// frame the interpreter throws IMSX. +// +// Lets say A(), which has provably balanced locking, acquires O and then calls B(). +// B() doesn't have provably balanced locking so it runs in the interpreter. +// Control returns to A() and A() unlocks O. By I1 and I2, above, we know that O +// is still locked by A(). +// +// The only other source of unbalanced locking would be JNI. The "Java Native Interface +// Specification" states that an object locked by JNI's MonitorEnter should not be +// unlocked by "normal" java-level locking and vice-versa. The specification doesn't +// specify what will occur if a program engages in such mixed-mode locking, however. +// Arguably given that the spec legislates the JNI case as undefined our implementation +// could reasonably *avoid* checking owner in fast_unlock(). +// In the interest of performance we elide m->Owner==Self check in unlock. +// A perfectly viable alternative is to elide the owner check except when +// Xcheck:jni is enabled. + void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(reg_rax == rax, "Used for CAS"); assert_different_registers(obj, reg_rax, t); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index e1652213688..950fcb75290 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -34,12 +34,7 @@ public: Assembler::AvxVectorLen vector_length_encoding(int vlen_in_bytes); // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. - // See full description in macroAssembler_x86.cpp. - void fast_lock(Register obj, Register box, Register tmp, - Register scr, Register cx1, Register cx2, Register thread, - Metadata* method_data); - void fast_unlock(Register obj, Register box, Register tmp); - + // See full description in c2_MacroAssembler_x86.cpp. void fast_lock_lightweight(Register obj, Register box, Register rax_reg, Register t, Register thread); void fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread); diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index 92233ee0d07..a6b4efbe4f2 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1024,100 +1024,25 @@ void InterpreterMacroAssembler::get_method_counters(Register method, void InterpreterMacroAssembler::lock_object(Register lock_reg) { assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); - if (LockingMode == LM_MONITOR) { - call_VM_preemptable(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } else { - Label count_locking, done, slow_case; + Label done, slow_case; - const Register swap_reg = rax; // Must use rax for cmpxchg instruction - const Register tmp_reg = rbx; - const Register obj_reg = c_rarg3; // Will contain the oop - const Register rklass_decode_tmp = rscratch1; + const Register swap_reg = rax; // Must use rax for cmpxchg instruction + const Register tmp_reg = rbx; + const Register obj_reg = c_rarg3; // Will contain the oop - const int obj_offset = in_bytes(BasicObjectLock::obj_offset()); - const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); - const int mark_offset = lock_offset + - BasicLock::displaced_header_offset_in_bytes(); + // Load object pointer into obj_reg + movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); - // Load object pointer into obj_reg - movptr(obj_reg, Address(lock_reg, obj_offset)); + lightweight_lock(lock_reg, obj_reg, swap_reg, tmp_reg, slow_case); + jmp(done); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(lock_reg, obj_reg, swap_reg, tmp_reg, slow_case); - } else if (LockingMode == LM_LEGACY) { - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp_reg, obj_reg, rklass_decode_tmp); - testb(Address(tmp_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, slow_case); - } + bind(slow_case); - // Load immediate 1 into swap_reg %rax - movl(swap_reg, 1); - - // Load (object->mark() | 1) into swap_reg %rax - orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - // Save (object->mark() | 1) into BasicLock's displaced header - movptr(Address(lock_reg, mark_offset), swap_reg); - - assert(lock_offset == 0, - "displaced header must be first word in BasicObjectLock"); - - lock(); - cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - jcc(Assembler::zero, count_locking); - - const int zero_bits = 7; - - // Fast check for recursive lock. - // - // Can apply the optimization only if this is a stack lock - // allocated in this thread. For efficiency, we can focus on - // recently allocated stack locks (instead of reading the stack - // base and checking whether 'mark' points inside the current - // thread stack): - // 1) (mark & zero_bits) == 0, and - // 2) rsp <= mark < mark + os::pagesize() - // - // Warning: rsp + os::pagesize can overflow the stack base. We must - // neither apply the optimization for an inflated lock allocated - // just above the thread stack (this is why condition 1 matters) - // nor apply the optimization if the stack lock is inside the stack - // of another thread. The latter is avoided even in case of overflow - // because we have guard pages at the end of all stacks. Hence, if - // we go over the stack base and hit the stack of another thread, - // this should not be in a writeable area that could contain a - // stack lock allocated by that thread. As a consequence, a stack - // lock less than page size away from rsp is guaranteed to be - // owned by the current thread. - // - // These 3 tests can be done by evaluating the following - // expression: ((mark - rsp) & (zero_bits - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant bits clear. - // NOTE: the mark is in swap_reg %rax as the result of cmpxchg - subptr(swap_reg, rsp); - andptr(swap_reg, zero_bits - (int)os::vm_page_size()); - - // Save the test result, for recursive case, the result is zero - movptr(Address(lock_reg, mark_offset), swap_reg); - jcc(Assembler::notZero, slow_case); - - bind(count_locking); - inc_held_monitor_count(); - } - jmp(done); - - bind(slow_case); - - // Call the runtime routine for slow case - call_VM_preemptable(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - bind(done); - } + // Call the runtime routine for slow case + call_VM_preemptable(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); + bind(done); } @@ -1136,63 +1061,31 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { void InterpreterMacroAssembler::unlock_object(Register lock_reg) { assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); - if (LockingMode == LM_MONITOR) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - } else { - Label count_locking, done, slow_case; + Label done, slow_case; - const Register swap_reg = rax; // Must use rax for cmpxchg instruction - const Register header_reg = c_rarg2; // Will contain the old oopMark - const Register obj_reg = c_rarg3; // Will contain the oop + const Register swap_reg = rax; // Must use rax for cmpxchg instruction + const Register header_reg = c_rarg2; // Will contain the old oopMark + const Register obj_reg = c_rarg3; // Will contain the oop - save_bcp(); // Save in case of exception + save_bcp(); // Save in case of exception - if (LockingMode != LM_LIGHTWEIGHT) { - // Convert from BasicObjectLock structure to object and BasicLock - // structure Store the BasicLock address into %rax - lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset())); - } + // Load oop into obj_reg(%c_rarg3) + movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); - // Load oop into obj_reg(%c_rarg3) - movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); + // Free entry + movptr(Address(lock_reg, BasicObjectLock::obj_offset()), NULL_WORD); - // Free entry - movptr(Address(lock_reg, BasicObjectLock::obj_offset()), NULL_WORD); + lightweight_unlock(obj_reg, swap_reg, header_reg, slow_case); + jmp(done); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj_reg, swap_reg, header_reg, slow_case); - } else if (LockingMode == LM_LEGACY) { - // Load the old header from BasicLock structure - movptr(header_reg, Address(swap_reg, - BasicLock::displaced_header_offset_in_bytes())); + bind(slow_case); + // Call the runtime routine for slow case. + movptr(Address(lock_reg, BasicObjectLock::obj_offset()), obj_reg); // restore obj + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - // Test for recursion - testptr(header_reg, header_reg); + bind(done); - // zero for recursive case - jcc(Assembler::zero, count_locking); - - // Atomic swap back the old header - lock(); - cmpxchgptr(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - // zero for simple unlock of a stack-lock case - jcc(Assembler::notZero, slow_case); - - bind(count_locking); - dec_held_monitor_count(); - } - jmp(done); - - bind(slow_case); - // Call the runtime routine for slow case. - movptr(Address(lock_reg, BasicObjectLock::obj_offset()), obj_reg); // restore obj - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - - bind(done); - - restore_bcp(); - } + restore_bcp(); } void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp index b8a4b829159..17fdfa61d36 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp @@ -59,17 +59,10 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas __ movptr(result, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - if (LockingMode == LM_LIGHTWEIGHT) { - if (!UseObjectMonitorTable) { - // check if monitor - __ testptr(result, markWord::monitor_value); - __ jcc(Assembler::notZero, slowCase); - } - } else { - // check if locked - __ testptr(result, markWord::unlocked_value); - __ jcc(Assembler::zero, slowCase); + if (!UseObjectMonitorTable) { + // check if monitor + __ testptr(result, markWord::monitor_value); + __ jcc(Assembler::notZero, slowCase); } // get hash diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 7c7ca61f1ae..d60f535fefc 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2133,7 +2133,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // We use the same pc/oopMap repeatedly when we call out Label native_return; - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { // For convenience we use the pc we want to resume to in case of preemption on Object.wait. __ set_last_Java_frame(rsp, noreg, native_return, rscratch1); } else { @@ -2174,16 +2174,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, const Register swap_reg = rax; // Must use rax for cmpxchg instruction const Register obj_reg = rbx; // Will contain the oop const Register lock_reg = r13; // Address of compiler lock object (BasicLock) - const Register old_hdr = r13; // value of old header at unlock time Label slow_path_lock; Label lock_done; if (method->is_synchronized()) { - Label count_mon; - - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); - // Get the handle (the 2nd argument) __ mov(oop_handle_reg, c_rarg1); @@ -2194,47 +2189,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Load the oop from the handle __ movptr(obj_reg, Address(oop_handle_reg, 0)); - if (LockingMode == LM_MONITOR) { - __ jmp(slow_path_lock); - } else if (LockingMode == LM_LEGACY) { - // Load immediate 1 into swap_reg %rax - __ movl(swap_reg, 1); - - // Load (object->mark() | 1) into swap_reg %rax - __ orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - // Save (object->mark() | 1) into BasicLock's displaced header - __ movptr(Address(lock_reg, mark_word_offset), swap_reg); - - // src -> dest iff dest == rax else rax <- dest - __ lock(); - __ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ jcc(Assembler::equal, count_mon); - - // Hmm should this move to the slow path code area??? - - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 3) == 0, and - // 2) rsp <= mark < mark + os::pagesize() - // These 3 tests can be done by evaluating the following - // expression: ((mark - rsp) & (3 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 2 bits clear. - // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg - - __ subptr(swap_reg, rsp); - __ andptr(swap_reg, 3 - (int)os::vm_page_size()); - - // Save the test result, for recursive case, the result is zero - __ movptr(Address(lock_reg, mark_word_offset), swap_reg); - __ jcc(Assembler::notEqual, slow_path_lock); - - __ bind(count_mon); - __ inc_held_monitor_count(); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(lock_reg, obj_reg, swap_reg, rscratch1, slow_path_lock); - } + __ lightweight_lock(lock_reg, obj_reg, swap_reg, rscratch1, slow_path_lock); // Slow path will re-enter here __ bind(lock_done); @@ -2322,7 +2277,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // change thread state __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java); - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { // Check preemption for Object.wait() __ movptr(rscratch1, Address(r15_thread, JavaThread::preempt_alternate_return_offset())); __ cmpptr(rscratch1, NULL_WORD); @@ -2354,38 +2309,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Get locked oop from the handle we passed to jni __ movptr(obj_reg, Address(oop_handle_reg, 0)); - if (LockingMode == LM_LEGACY) { - Label not_recur; - // Simple recursive lock? - __ cmpptr(Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size), NULL_WORD); - __ jcc(Assembler::notEqual, not_recur); - __ dec_held_monitor_count(); - __ jmpb(fast_done); - __ bind(not_recur); - } - // Must save rax if it is live now because cmpxchg must use it if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { save_native_result(masm, ret_type, stack_slots); } - if (LockingMode == LM_MONITOR) { - __ jmp(slow_path_unlock); - } else if (LockingMode == LM_LEGACY) { - // get address of the stack lock - __ lea(rax, Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size)); - // get old displaced header - __ movptr(old_hdr, Address(rax, 0)); - - // Atomic swap old header if oop still contains the stack lock - __ lock(); - __ cmpxchgptr(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ jcc(Assembler::notEqual, slow_path_unlock); - __ dec_held_monitor_count(); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); - } + __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); // slow path re-enters here __ bind(unlock_done); diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index bd061d45fbd..47ef0aef2bb 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1017,21 +1017,16 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // change thread state __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java); - if (LockingMode != LM_LEGACY) { - // Check preemption for Object.wait() - Label not_preempted; - __ movptr(rscratch1, Address(r15_thread, JavaThread::preempt_alternate_return_offset())); - __ cmpptr(rscratch1, NULL_WORD); - __ jccb(Assembler::equal, not_preempted); - __ movptr(Address(r15_thread, JavaThread::preempt_alternate_return_offset()), NULL_WORD); - __ jmp(rscratch1); - __ bind(native_return); - __ restore_after_resume(true /* is_native */); - __ bind(not_preempted); - } else { - // any pc will do so just use this one for LM_LEGACY to keep code together. - __ bind(native_return); - } + // Check preemption for Object.wait() + Label not_preempted; + __ movptr(rscratch1, Address(r15_thread, JavaThread::preempt_alternate_return_offset())); + __ cmpptr(rscratch1, NULL_WORD); + __ jccb(Assembler::equal, not_preempted); + __ movptr(Address(r15_thread, JavaThread::preempt_alternate_return_offset()), NULL_WORD); + __ jmp(rscratch1); + __ bind(native_return); + __ restore_after_resume(true /* is_native */); + __ bind(not_preempted); // reset_last_Java_frame __ reset_last_Java_frame(true); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 5b5292fbde2..932dc9e1ca7 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -14073,33 +14073,7 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ // ============================================================================ // inlined locking and unlocking -instruct cmpFastLock(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rRegP scr) %{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set cr (FastLock object box)); - effect(TEMP tmp, TEMP scr, USE_KILL box); - ins_cost(300); - format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr" %} - ins_encode %{ - __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, - $scr$$Register, noreg, noreg, r15_thread, nullptr); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpFastUnlock(rFlagsReg cr, rRegP object, rax_RegP box, rRegP tmp) %{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set cr (FastUnlock object box)); - effect(TEMP tmp, USE_KILL box); - ins_cost(300); - format %{ "fastunlock $object,$box\t! kills $box,$tmp" %} - ins_encode %{ - __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register); - %} - ins_pipe(pipe_slow); -%} - instruct cmpFastLockLightweight(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI rax_reg, rRegP tmp) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set cr (FastLock object box)); effect(TEMP rax_reg, TEMP tmp, USE_KILL box); ins_cost(300); @@ -14111,7 +14085,6 @@ instruct cmpFastLockLightweight(rFlagsReg cr, rRegP object, rbx_RegP box, rax_Re %} instruct cmpFastUnlockLightweight(rFlagsReg cr, rRegP object, rax_RegP rax_reg, rRegP tmp) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set cr (FastUnlock object rax_reg)); effect(TEMP tmp, USE_KILL rax_reg); ins_cost(300);