Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8242263: Diagnose synchronization on primitive wrappers
Added diagnostic flag DiagnoseSyncOnPrimitiveWrappers

Reviewed-by: dholmes, mdoerr, dcubed, coleenp, egahlin, mgronlun
  • Loading branch information
pchilano committed Aug 21, 2020
1 parent f27024b commit d91817e75bd92c7622fd961fbd9e137f17902e13
Showing with 528 additions and 88 deletions.
  1. +7 −0 src/hotspot/cpu/aarch64/aarch64.ad
  2. +11 −4 src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
  3. +7 −0 src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp
  4. +8 −12 src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
  5. +5 −9 src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
  6. +13 −10 src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
  7. +7 −0 src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
  8. +7 −0 src/hotspot/cpu/arm/interp_masm_arm.cpp
  9. +5 −11 src/hotspot/cpu/arm/macroAssembler_arm.cpp
  10. +5 −9 src/hotspot/cpu/arm/macroAssembler_arm.hpp
  11. +7 −0 src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
  12. +7 −0 src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
  13. +6 −0 src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
  14. +6 −0 src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp
  15. +6 −0 src/hotspot/cpu/s390/interp_masm_s390.cpp
  16. +8 −0 src/hotspot/cpu/s390/macroAssembler_s390.cpp
  17. +12 −5 src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
  18. +7 −0 src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
  19. +8 −1 src/hotspot/cpu/x86/interp_masm_x86.cpp
  20. +9 −16 src/hotspot/cpu/x86/macroAssembler_x86.cpp
  21. +5 −9 src/hotspot/cpu/x86/macroAssembler_x86.hpp
  22. +8 −0 src/hotspot/share/classfile/systemDictionary.cpp
  23. +4 −0 src/hotspot/share/jfr/metadata/metadata.xml
  24. +1 −0 src/hotspot/share/logging/logTag.hpp
  25. +3 −0 src/hotspot/share/oops/klass.hpp
  26. +5 −0 src/hotspot/share/runtime/arguments.cpp
  27. +10 −0 src/hotspot/share/runtime/globals.hpp
  28. +58 −0 src/hotspot/share/runtime/synchronizer.cpp
  29. +8 −0 src/hotspot/share/runtime/synchronizer.hpp
  30. +4 −1 src/hotspot/share/utilities/accessFlags.hpp
  31. +5 −0 src/jdk.jfr/share/conf/jfr/default.jfc
  32. +5 −0 src/jdk.jfr/share/conf/jfr/profile.jfc
  33. +167 −0 test/hotspot/jtreg/runtime/Monitor/SyncOnPrimitiveWrapperTest.java
  34. +1 −1 test/jdk/jdk/jfr/event/metadata/TestLookForUntestedEvents.java
  35. +92 −0 test/jdk/jdk/jfr/event/runtime/TestSyncOnPrimitiveWrapperEvent.java
  36. +1 −0 test/lib/jdk/test/lib/jfr/EventNames.java
@@ -3511,6 +3511,13 @@ encode %{
// Load markWord from object into displaced_header.
__ ldr(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes()));

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
__ load_klass(tmp, oop);
__ ldrw(tmp, Address(tmp, Klass::access_flags_offset()));
__ tstw(tmp, JVM_ACC_IS_BOX_CLASS);
__ br(Assembler::NE, cont);
}

if (UseBiasedLocking && !UseOptoBiasInlining) {
__ biased_locking_enter(box, oop, disp_hdr, tmp, true, cont);
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -73,11 +73,18 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
// save object being locked into the BasicObjectLock
str(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));

null_check_offset = offset();

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(hdr, obj);
ldrw(hdr, Address(hdr, Klass::access_flags_offset()));
tstw(hdr, JVM_ACC_IS_BOX_CLASS);
br(Assembler::NE, slow_case);
}

if (UseBiasedLocking) {
assert(scratch != noreg, "should have scratch register at this point");
null_check_offset = biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);
} else {
null_check_offset = offset();
biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);
}

// Load object header
@@ -725,6 +725,13 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg)
// Load object pointer into obj_reg %c_rarg3
ldr(obj_reg, Address(lock_reg, obj_offset));

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(tmp, obj_reg);
ldrw(tmp, Address(tmp, Klass::access_flags_offset()));
tstw(tmp, JVM_ACC_IS_BOX_CLASS);
br(Assembler::NE, slow_case);
}

if (UseBiasedLocking) {
biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp, false, done, &slow_case);
}
@@ -444,14 +444,14 @@ void MacroAssembler::reserved_stack_check() {
bind(no_reserved_zone_enabling);
}

int MacroAssembler::biased_locking_enter(Register lock_reg,
Register obj_reg,
Register swap_reg,
Register tmp_reg,
bool swap_reg_contains_mark,
Label& done,
Label* slow_case,
BiasedLockingCounters* counters) {
void MacroAssembler::biased_locking_enter(Register lock_reg,
Register obj_reg,
Register swap_reg,
Register tmp_reg,
bool swap_reg_contains_mark,
Label& done,
Label* slow_case,
BiasedLockingCounters* counters) {
assert(UseBiasedLocking, "why call this otherwise?");
assert_different_registers(lock_reg, obj_reg, swap_reg);

@@ -471,9 +471,7 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
// pointers to allow age to be placed into low bits
// First check to see whether biasing is even enabled for this object
Label cas_label;
int null_check_offset = -1;
if (!swap_reg_contains_mark) {
null_check_offset = offset();
ldr(swap_reg, mark_addr);
}
andr(tmp_reg, swap_reg, markWord::biased_lock_mask_in_place);
@@ -601,8 +599,6 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
}

bind(cas_label);

return null_check_offset;
}

void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {
@@ -111,15 +111,11 @@ class MacroAssembler: public Assembler {
// tmp_reg must be supplied and must not be rscratch1 or rscratch2
// Optional slow case is for implementations (interpreter and C1) which branch to
// slow case directly. Leaves condition codes set for C2's Fast_Lock node.
// Returns offset of first potentially-faulting instruction for null
// check info (currently consumed only by C1). If
// swap_reg_contains_mark is true then returns -1 as it is assumed
// the calling code has already passed any potential faults.
int biased_locking_enter(Register lock_reg, Register obj_reg,
Register swap_reg, Register tmp_reg,
bool swap_reg_contains_mark,
Label& done, Label* slow_case = NULL,
BiasedLockingCounters* counters = NULL);
void biased_locking_enter(Register lock_reg, Register obj_reg,
Register swap_reg, Register tmp_reg,
bool swap_reg_contains_mark,
Label& done, Label* slow_case = NULL,
BiasedLockingCounters* counters = NULL);
void biased_locking_exit (Register obj_reg, Register temp_reg, Label& done);


@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -200,26 +200,29 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj,
const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
const int mark_offset = BasicLock::displaced_header_offset_in_bytes();

if (UseBiasedLocking) {
// load object
str(obj, Address(disp_hdr, obj_offset));
null_check_offset = biased_locking_enter(obj, hdr/*scratched*/, tmp1, false, tmp2, done, slow_case);
}
str(obj, Address(disp_hdr, obj_offset));

assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
null_check_offset = offset();

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(tmp1, obj);
ldr_u32(tmp1, Address(tmp1, Klass::access_flags_offset()));
tst(tmp1, JVM_ACC_IS_BOX_CLASS);
b(slow_case, ne);
}

if (!UseBiasedLocking) {
null_check_offset = offset();
if (UseBiasedLocking) {
biased_locking_enter(obj, hdr/*scratched*/, tmp1, false, tmp2, done, slow_case);
}

assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");

// On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
// That would be acceptable as ether CAS or slow case path is taken in that case.

// Must be the first instruction here, because implicit null check relies on it
ldr(hdr, Address(obj, oopDesc::mark_offset_in_bytes()));

str(obj, Address(disp_hdr, obj_offset));
tst(hdr, markWord::unlocked_value);
b(fast_lock, ne);

@@ -90,6 +90,13 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc

Label fast_lock, done;

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(Rscratch, Roop);
ldr_u32(Rscratch, Address(Rscratch, Klass::access_flags_offset()));
tst(Rscratch, JVM_ACC_IS_BOX_CLASS);
b(done, ne);
}

if (UseBiasedLocking && !UseOptoBiasInlining) {
assert(scratch3 != noreg, "need extra temporary for -XX:-UseOptoBiasInlining");
biased_locking_enter(Roop, Rmark, Rscratch, false, scratch3, done, done);
@@ -883,6 +883,13 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) {
// Load object pointer
ldr(Robj, Address(Rlock, obj_offset));

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(R0, Robj);
ldr_u32(R0, Address(R0, Klass::access_flags_offset()));
tst(R0, JVM_ACC_IS_BOX_CLASS);
b(slow_case, ne);
}

if (UseBiasedLocking) {
biased_locking_enter(Robj, Rmark/*scratched*/, R0, false, Rtemp, done, slow_case);
}
@@ -1322,11 +1322,11 @@ void MacroAssembler::biased_locking_enter_with_cas(Register obj_reg, Register ol
#endif // !PRODUCT
}

int MacroAssembler::biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
bool swap_reg_contains_mark,
Register tmp2,
Label& done, Label& slow_case,
BiasedLockingCounters* counters) {
void MacroAssembler::biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
bool swap_reg_contains_mark,
Register tmp2,
Label& done, Label& slow_case,
BiasedLockingCounters* counters) {
// obj_reg must be preserved (at least) if the bias locking fails
// tmp_reg is a temporary register
// swap_reg was used as a temporary but contained a value
@@ -1357,10 +1357,6 @@ int MacroAssembler::biased_locking_enter(Register obj_reg, Register swap_reg, Re
// First check to see whether biasing is even enabled for this object
Label cas_label;

// The null check applies to the mark loading, if we need to load it.
// If the mark has already been loaded in swap_reg then it has already
// been performed and the offset is irrelevant.
int null_check_offset = offset();
if (!swap_reg_contains_mark) {
ldr(swap_reg, mark_addr);
}
@@ -1504,8 +1500,6 @@ int MacroAssembler::biased_locking_enter(Register obj_reg, Register swap_reg, Re
// removing the bias bit from the object's header.

bind(cas_label);

return null_check_offset;
}


@@ -375,18 +375,14 @@ class MacroAssembler: public Assembler {
// biased and we acquired it. Slow case label is branched to with
// condition code NE set if the lock is biased but we failed to acquire
// it. Otherwise fall through.
// Returns offset of first potentially-faulting instruction for null
// check info (currently consumed only by C1). If
// swap_reg_contains_mark is true then returns -1 as it is assumed
// the calling code has already passed any potential faults.
// Notes:
// - swap_reg and tmp_reg are scratched
// - Rtemp was (implicitly) scratched and can now be specified as the tmp2
int biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
bool swap_reg_contains_mark,
Register tmp2,
Label& done, Label& slow_case,
BiasedLockingCounters* counters = NULL);
void biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
bool swap_reg_contains_mark,
Register tmp2,
Label& done, Label& slow_case,
BiasedLockingCounters* counters = NULL);
void biased_locking_exit(Register obj_reg, Register temp_reg, Label& done);

// Building block for CAS cases of biased locking: makes CAS and records statistics.
@@ -105,6 +105,13 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox
// Save object being locked into the BasicObjectLock...
std(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox);

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(Rscratch, Roop);
lwz(Rscratch, in_bytes(Klass::access_flags_offset()), Rscratch);
testbitdi(CCR0, R0, Rscratch, exact_log2(JVM_ACC_IS_BOX_CLASS));
bne(CCR0, slow_int);
}

if (UseBiasedLocking) {
biased_locking_enter(CCR0, Roop, Rmark, Rscratch, R0, done, &slow_int);
}
@@ -910,6 +910,13 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
// Load markWord from object into displaced_header.
ld(displaced_header, oopDesc::mark_offset_in_bytes(), object);

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(tmp, object);
lwz(tmp, in_bytes(Klass::access_flags_offset()), tmp);
testbitdi(CCR0, R0, tmp, exact_log2(JVM_ACC_IS_BOX_CLASS));
bne(CCR0, slow_case);
}

if (UseBiasedLocking) {
biased_locking_enter(CCR0, object, displaced_header, tmp, current_header, done, &slow_case);
}
@@ -2836,6 +2836,12 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
// Load markWord from object into displaced_header.
ld(displaced_header, oopDesc::mark_offset_in_bytes(), oop);

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(temp, oop);
lwz(temp, in_bytes(Klass::access_flags_offset()), temp);
testbitdi(flag, R0, temp, exact_log2(JVM_ACC_IS_BOX_CLASS));
bne(flag, cont);
}

if (try_bias) {
biased_locking_enter(flag, oop, displaced_header, temp, current_header, cont);
@@ -91,6 +91,12 @@ void C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hd
// Save object being locked into the BasicObjectLock...
z_stg(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(Z_R1_scratch, obj);
testbit(Address(Z_R1_scratch, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_BOX_CLASS));
z_btrue(slow_case);
}

if (UseBiasedLocking) {
biased_locking_enter(obj, hdr, Z_R1_scratch, Z_R0_scratch, done, &slow_case);
}
@@ -1000,6 +1000,12 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
// Load markWord from object into displaced_header.
z_lg(displaced_header, oopDesc::mark_offset_in_bytes(), object);

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(Z_R1_scratch, object);
testbit(Address(Z_R1_scratch, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_BOX_CLASS));
z_btrue(slow_case);
}

if (UseBiasedLocking) {
biased_locking_enter(object, displaced_header, Z_R1, Z_R0, done, &slow_case);
}
@@ -3358,6 +3358,14 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis
// Load markWord from oop into mark.
z_lg(displacedHeader, 0, oop);

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(Z_R1_scratch, oop);
z_l(Z_R1_scratch, Address(Z_R1_scratch, Klass::access_flags_offset()));
assert((JVM_ACC_IS_BOX_CLASS & 0xFFFF) == 0, "or change following instruction");
z_nilh(Z_R1_scratch, JVM_ACC_IS_BOX_CLASS >> 16);
z_brne(done);
}

if (try_bias) {
biased_locking_enter(oop, displacedHeader, temp, Z_R0, done);
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@
#include "runtime/stubRoutines.hpp"

int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register scratch, Label& slow_case) {
const Register rklass_decode_tmp = LP64_ONLY(rscratch1) NOT_LP64(noreg);
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");
@@ -51,12 +52,18 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
// save object being locked into the BasicObjectLock
movptr(Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()), obj);

null_check_offset = offset();

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(hdr, obj, rklass_decode_tmp);
movl(hdr, Address(hdr, Klass::access_flags_offset()));
testl(hdr, JVM_ACC_IS_BOX_CLASS);
jcc(Assembler::notZero, slow_case);
}

if (UseBiasedLocking) {
assert(scratch != noreg, "should have scratch register at this point");
Register rklass_decode_tmp = LP64_ONLY(rscratch1) NOT_LP64(noreg);
null_check_offset = biased_locking_enter(disp_hdr, obj, hdr, scratch, rklass_decode_tmp, false, done, &slow_case);
} else {
null_check_offset = offset();
biased_locking_enter(disp_hdr, obj, hdr, scratch, rklass_decode_tmp, false, done, &slow_case);
}

// Load object header
@@ -470,6 +470,13 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp

Label IsInflated, DONE_LABEL;

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
load_klass(tmpReg, objReg, cx1Reg);
movl(tmpReg, Address(tmpReg, Klass::access_flags_offset()));
testl(tmpReg, JVM_ACC_IS_BOX_CLASS);
jcc(Assembler::notZero, DONE_LABEL);
}

// it's stack-locked, biased or neutral
// TODO: optimize away redundant LDs of obj->mark and improve the markword triage
// order to reduce the number of conditional branches in the most common cases.

0 comments on commit d91817e

Please sign in to comment.