8364141: Remove LockingMode related code from x86

Reviewed-by: aboldtch, dholmes, coleenp
This commit is contained in:
Fredrik Bredberg 2025-08-12 08:45:02 +00:00
parent b81f4faed7
commit f155f7d6e5
10 changed files with 91 additions and 600 deletions

View file

@ -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());
}
__ 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) {

View file

@ -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);
}

View file

@ -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();
}
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();
}
}

View file

@ -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<int32_t>(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);

View file

@ -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);

View file

@ -1024,90 +1024,16 @@ 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 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, obj_offset));
movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset()));
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);
}
// 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);
@ -1117,7 +1043,6 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) {
CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
lock_reg);
bind(done);
}
}
@ -1136,10 +1061,7 @@ 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
@ -1147,41 +1069,13 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) {
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()));
// Free entry
movptr(Address(lock_reg, BasicObjectLock::obj_offset()), NULL_WORD);
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()));
// Test for recursion
testptr(header_reg, header_reg);
// 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);
@ -1192,7 +1086,6 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) {
bind(done);
restore_bcp();
}
}
void InterpreterMacroAssembler::test_method_data_pointer(Register mdp,

View file

@ -59,18 +59,11 @@ 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);
}
// get hash
// Read the header and build a mask to get its hash field.

View file

@ -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);
}
// 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);
}
// slow path re-enters here
__ bind(unlock_done);

View file

@ -1017,7 +1017,6 @@ 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()));
@ -1028,10 +1027,6 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
__ 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);
}
// reset_last_Java_frame
__ reset_last_Java_frame(true);

View file

@ -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);