8340796: Use a consistent order when loading cxq and EntryList

Reviewed-by: dholmes, coleenp, eosterlund
This commit is contained in:
Fredrik Bredberg 2024-10-28 09:02:54 +00:00
parent 0e3fc93dfb
commit eb3669a586
6 changed files with 22 additions and 14 deletions

View File

@ -217,7 +217,7 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe
// StoreLoad achieves this.
membar(StoreLoad);
// Check if the entry lists are empty.
// Check if the entry lists are empty (EntryList first - by convention).
ldr(rscratch1, Address(tmp, ObjectMonitor::EntryList_offset()));
ldr(tmpReg, Address(tmp, ObjectMonitor::cxq_offset()));
orr(rscratch1, rscratch1, tmpReg);
@ -538,7 +538,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Regi
// StoreLoad achieves this.
membar(StoreLoad);
// Check if the entry lists are empty.
// Check if the entry lists are empty (EntryList first - by convention).
ldr(rscratch1, Address(t1_monitor, ObjectMonitor::EntryList_offset()));
ldr(t3_t, Address(t1_monitor, ObjectMonitor::cxq_offset()));
orr(rscratch1, rscratch1, t3_t);

View File

@ -2736,7 +2736,7 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
// StoreLoad achieves this.
membar(StoreLoad);
// Check if the entry lists are empty.
// Check if the entry lists are empty (EntryList first - by convention).
ld(temp, in_bytes(ObjectMonitor::EntryList_offset()), current_header);
ld(displaced_header, in_bytes(ObjectMonitor::cxq_offset()), current_header);
orr(temp, temp, displaced_header); // Will be 0 if both are 0.
@ -3083,7 +3083,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
// StoreLoad achieves this.
membar(StoreLoad);
// Check if the entry lists are empty.
// Check if the entry lists are empty (EntryList first - by convention).
ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor);
ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor);
orr(t, t, t2);

View File

@ -234,7 +234,7 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg,
// StoreLoad achieves this.
membar(StoreLoad);
// Check if the entry lists are empty.
// Check if the entry lists are empty (EntryList first - by convention).
ld(t0, Address(tmp, ObjectMonitor::EntryList_offset()));
ld(tmp1Reg, Address(tmp, ObjectMonitor::cxq_offset()));
orr(t0, t0, tmp1Reg);
@ -566,7 +566,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box,
// StoreLoad achieves this.
membar(StoreLoad);
// Check if the entry lists are empty.
// Check if the entry lists are empty (EntryList first - by convention).
ld(t0, Address(tmp1_monitor, ObjectMonitor::EntryList_offset()));
ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::cxq_offset()));
orr(t0, t0, tmp3_t);

View File

@ -3667,7 +3667,7 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg
// We need a full fence after clearing owner to avoid stranding.
z_fence();
// Check if the entry lists are empty.
// Check if the entry lists are empty (EntryList first - by convention).
load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
z_brne(check_succ);
load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
@ -6510,7 +6510,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis
// We need a full fence after clearing owner to avoid stranding.
z_fence();
// Check if the entry lists are empty.
// Check if the entry lists are empty (EntryList first - by convention).
load_and_test_long(tmp2, EntryList_address);
z_brne(check_succ);
load_and_test_long(tmp2, cxq_address);

View File

@ -477,9 +477,9 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t
// StoreLoad achieves this.
membar(StoreLoad);
// Check if the entry lists are empty.
movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
// Check if the entry lists are empty (EntryList first - by convention).
movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
jccb(Assembler::zero, LSuccess); // If so we are done.
// Check if there is a successor.
@ -806,9 +806,9 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax,
// StoreLoad achieves this.
membar(StoreLoad);
// Check if the entry lists are empty.
movptr(reg_rax, cxq_address);
orptr(reg_rax, EntryList_address);
// Check if the entry lists are empty (EntryList first - by convention).
movptr(reg_rax, EntryList_address);
orptr(reg_rax, cxq_address);
jccb(Assembler::zero, unlocked); // If so we are done.
// Check if there is a successor.

View File

@ -1133,6 +1133,14 @@ void ObjectMonitor::UnlinkAfterAcquire(JavaThread* current, ObjectWaiter* curren
// or drain _cxq, we need to reacquire the lock before we can wake up
// (unpark) a waiting thread.
//
// Note that we read the EntryList and then the cxq after dropping the
// lock, so the values need not form a stable snapshot. In particular,
// after reading the (empty) EntryList, another thread could acquire
// and release the lock, moving any entries in the cxq to the
// EntryList, causing the current thread to see an empty cxq and
// conclude there are no waiters. But this is okay as the thread that
// moved the cxq is responsible for waking the successor.
//
// The CAS() in enter provides for safety and exclusion, while the
// MEMBAR in exit provides for progress and avoids stranding.
//