mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
8242263: Diagnose synchronization on primitive wrappers
Added diagnostic flag DiagnoseSyncOnPrimitiveWrappers Reviewed-by: dholmes, mdoerr, dcubed, coleenp, egahlin, mgronlun
This commit is contained in:
parent
fac22ce20c
commit
e56002c7d3
36 changed files with 528 additions and 88 deletions
|
@ -3511,6 +3511,13 @@ encode %{
|
||||||
// Load markWord from object into displaced_header.
|
// Load markWord from object into displaced_header.
|
||||||
__ ldr(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes()));
|
__ 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) {
|
if (UseBiasedLocking && !UseOptoBiasInlining) {
|
||||||
__ biased_locking_enter(box, oop, disp_hdr, tmp, true, cont);
|
__ 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.
|
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* 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
|
// save object being locked into the BasicObjectLock
|
||||||
str(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
|
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) {
|
if (UseBiasedLocking) {
|
||||||
assert(scratch != noreg, "should have scratch register at this point");
|
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);
|
biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);
|
||||||
} else {
|
|
||||||
null_check_offset = offset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load object header
|
// Load object header
|
||||||
|
|
|
@ -725,6 +725,13 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg)
|
||||||
// Load object pointer into obj_reg %c_rarg3
|
// Load object pointer into obj_reg %c_rarg3
|
||||||
ldr(obj_reg, Address(lock_reg, obj_offset));
|
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) {
|
if (UseBiasedLocking) {
|
||||||
biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp, false, done, &slow_case);
|
biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp, false, done, &slow_case);
|
||||||
}
|
}
|
||||||
|
|
|
@ -444,7 +444,7 @@ void MacroAssembler::reserved_stack_check() {
|
||||||
bind(no_reserved_zone_enabling);
|
bind(no_reserved_zone_enabling);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MacroAssembler::biased_locking_enter(Register lock_reg,
|
void MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
Register obj_reg,
|
Register obj_reg,
|
||||||
Register swap_reg,
|
Register swap_reg,
|
||||||
Register tmp_reg,
|
Register tmp_reg,
|
||||||
|
@ -471,9 +471,7 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
// pointers to allow age to be placed into low bits
|
// pointers to allow age to be placed into low bits
|
||||||
// First check to see whether biasing is even enabled for this object
|
// First check to see whether biasing is even enabled for this object
|
||||||
Label cas_label;
|
Label cas_label;
|
||||||
int null_check_offset = -1;
|
|
||||||
if (!swap_reg_contains_mark) {
|
if (!swap_reg_contains_mark) {
|
||||||
null_check_offset = offset();
|
|
||||||
ldr(swap_reg, mark_addr);
|
ldr(swap_reg, mark_addr);
|
||||||
}
|
}
|
||||||
andr(tmp_reg, swap_reg, markWord::biased_lock_mask_in_place);
|
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);
|
bind(cas_label);
|
||||||
|
|
||||||
return null_check_offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {
|
void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {
|
||||||
|
|
|
@ -111,11 +111,7 @@ class MacroAssembler: public Assembler {
|
||||||
// tmp_reg must be supplied and must not be rscratch1 or rscratch2
|
// tmp_reg must be supplied and must not be rscratch1 or rscratch2
|
||||||
// Optional slow case is for implementations (interpreter and C1) which branch to
|
// 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.
|
// slow case directly. Leaves condition codes set for C2's Fast_Lock node.
|
||||||
// Returns offset of first potentially-faulting instruction for null
|
void biased_locking_enter(Register lock_reg, Register obj_reg,
|
||||||
// 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,
|
Register swap_reg, Register tmp_reg,
|
||||||
bool swap_reg_contains_mark,
|
bool swap_reg_contains_mark,
|
||||||
Label& done, Label* slow_case = NULL,
|
Label& done, Label* slow_case = NULL,
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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 obj_offset = BasicObjectLock::obj_offset_in_bytes();
|
||||||
const int mark_offset = BasicLock::displaced_header_offset_in_bytes();
|
const int mark_offset = BasicLock::displaced_header_offset_in_bytes();
|
||||||
|
|
||||||
if (UseBiasedLocking) {
|
|
||||||
// load object
|
|
||||||
str(obj, Address(disp_hdr, obj_offset));
|
str(obj, Address(disp_hdr, obj_offset));
|
||||||
null_check_offset = biased_locking_enter(obj, hdr/*scratched*/, tmp1, false, tmp2, done, slow_case);
|
|
||||||
|
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) {
|
||||||
|
biased_locking_enter(obj, hdr/*scratched*/, tmp1, false, tmp2, done, slow_case);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
|
assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
|
||||||
|
|
||||||
|
|
||||||
if (!UseBiasedLocking) {
|
|
||||||
null_check_offset = offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
|
// 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.
|
// 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
|
// Must be the first instruction here, because implicit null check relies on it
|
||||||
ldr(hdr, Address(obj, oopDesc::mark_offset_in_bytes()));
|
ldr(hdr, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||||
|
|
||||||
str(obj, Address(disp_hdr, obj_offset));
|
|
||||||
tst(hdr, markWord::unlocked_value);
|
tst(hdr, markWord::unlocked_value);
|
||||||
b(fast_lock, ne);
|
b(fast_lock, ne);
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,13 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc
|
||||||
|
|
||||||
Label fast_lock, done;
|
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) {
|
if (UseBiasedLocking && !UseOptoBiasInlining) {
|
||||||
assert(scratch3 != noreg, "need extra temporary for -XX:-UseOptoBiasInlining");
|
assert(scratch3 != noreg, "need extra temporary for -XX:-UseOptoBiasInlining");
|
||||||
biased_locking_enter(Roop, Rmark, Rscratch, false, scratch3, done, done);
|
biased_locking_enter(Roop, Rmark, Rscratch, false, scratch3, done, done);
|
||||||
|
|
|
@ -883,6 +883,13 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) {
|
||||||
// Load object pointer
|
// Load object pointer
|
||||||
ldr(Robj, Address(Rlock, obj_offset));
|
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) {
|
if (UseBiasedLocking) {
|
||||||
biased_locking_enter(Robj, Rmark/*scratched*/, R0, false, Rtemp, done, slow_case);
|
biased_locking_enter(Robj, Rmark/*scratched*/, R0, false, Rtemp, done, slow_case);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1322,7 +1322,7 @@ void MacroAssembler::biased_locking_enter_with_cas(Register obj_reg, Register ol
|
||||||
#endif // !PRODUCT
|
#endif // !PRODUCT
|
||||||
}
|
}
|
||||||
|
|
||||||
int MacroAssembler::biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
|
void MacroAssembler::biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
|
||||||
bool swap_reg_contains_mark,
|
bool swap_reg_contains_mark,
|
||||||
Register tmp2,
|
Register tmp2,
|
||||||
Label& done, Label& slow_case,
|
Label& done, Label& slow_case,
|
||||||
|
@ -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
|
// First check to see whether biasing is even enabled for this object
|
||||||
Label cas_label;
|
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) {
|
if (!swap_reg_contains_mark) {
|
||||||
ldr(swap_reg, mark_addr);
|
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.
|
// removing the bias bit from the object's header.
|
||||||
|
|
||||||
bind(cas_label);
|
bind(cas_label);
|
||||||
|
|
||||||
return null_check_offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -375,14 +375,10 @@ public:
|
||||||
// biased and we acquired it. Slow case label is branched to with
|
// 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
|
// condition code NE set if the lock is biased but we failed to acquire
|
||||||
// it. Otherwise fall through.
|
// 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:
|
// Notes:
|
||||||
// - swap_reg and tmp_reg are scratched
|
// - swap_reg and tmp_reg are scratched
|
||||||
// - Rtemp was (implicitly) scratched and can now be specified as the tmp2
|
// - 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,
|
void biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
|
||||||
bool swap_reg_contains_mark,
|
bool swap_reg_contains_mark,
|
||||||
Register tmp2,
|
Register tmp2,
|
||||||
Label& done, Label& slow_case,
|
Label& done, Label& slow_case,
|
||||||
|
|
|
@ -105,6 +105,13 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox
|
||||||
// Save object being locked into the BasicObjectLock...
|
// Save object being locked into the BasicObjectLock...
|
||||||
std(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox);
|
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) {
|
if (UseBiasedLocking) {
|
||||||
biased_locking_enter(CCR0, Roop, Rmark, Rscratch, R0, done, &slow_int);
|
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.
|
// Load markWord from object into displaced_header.
|
||||||
ld(displaced_header, oopDesc::mark_offset_in_bytes(), object);
|
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) {
|
if (UseBiasedLocking) {
|
||||||
biased_locking_enter(CCR0, object, displaced_header, tmp, current_header, done, &slow_case);
|
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.
|
// Load markWord from object into displaced_header.
|
||||||
ld(displaced_header, oopDesc::mark_offset_in_bytes(), oop);
|
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) {
|
if (try_bias) {
|
||||||
biased_locking_enter(flag, oop, displaced_header, temp, current_header, cont);
|
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...
|
// Save object being locked into the BasicObjectLock...
|
||||||
z_stg(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
|
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) {
|
if (UseBiasedLocking) {
|
||||||
biased_locking_enter(obj, hdr, Z_R1_scratch, Z_R0_scratch, done, &slow_case);
|
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.
|
// Load markWord from object into displaced_header.
|
||||||
z_lg(displaced_header, oopDesc::mark_offset_in_bytes(), object);
|
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) {
|
if (UseBiasedLocking) {
|
||||||
biased_locking_enter(object, displaced_header, Z_R1, Z_R0, done, &slow_case);
|
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.
|
// Load markWord from oop into mark.
|
||||||
z_lg(displacedHeader, 0, oop);
|
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) {
|
if (try_bias) {
|
||||||
biased_locking_enter(oop, displacedHeader, temp, Z_R0, done);
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
#include "runtime/stubRoutines.hpp"
|
#include "runtime/stubRoutines.hpp"
|
||||||
|
|
||||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register scratch, Label& slow_case) {
|
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 aligned_mask = BytesPerWord -1;
|
||||||
const int hdr_offset = oopDesc::mark_offset_in_bytes();
|
const int hdr_offset = oopDesc::mark_offset_in_bytes();
|
||||||
assert(hdr == rax, "hdr must be rax, for the cmpxchg instruction");
|
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
|
// save object being locked into the BasicObjectLock
|
||||||
movptr(Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()), obj);
|
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) {
|
if (UseBiasedLocking) {
|
||||||
assert(scratch != noreg, "should have scratch register at this point");
|
assert(scratch != noreg, "should have scratch register at this point");
|
||||||
Register rklass_decode_tmp = LP64_ONLY(rscratch1) NOT_LP64(noreg);
|
biased_locking_enter(disp_hdr, obj, hdr, scratch, rklass_decode_tmp, false, done, &slow_case);
|
||||||
null_check_offset = biased_locking_enter(disp_hdr, obj, hdr, scratch, rklass_decode_tmp, false, done, &slow_case);
|
|
||||||
} else {
|
|
||||||
null_check_offset = offset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load object header
|
// Load object header
|
||||||
|
|
|
@ -470,6 +470,13 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp
|
||||||
|
|
||||||
Label IsInflated, DONE_LABEL;
|
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
|
// it's stack-locked, biased or neutral
|
||||||
// TODO: optimize away redundant LDs of obj->mark and improve the markword triage
|
// 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.
|
// order to reduce the number of conditional branches in the most common cases.
|
||||||
|
|
|
@ -1186,6 +1186,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) {
|
||||||
const Register tmp_reg = rbx; // Will be passed to biased_locking_enter to avoid a
|
const Register tmp_reg = rbx; // Will be passed to biased_locking_enter to avoid a
|
||||||
// problematic case where tmp_reg = no_reg.
|
// problematic case where tmp_reg = no_reg.
|
||||||
const Register obj_reg = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // Will contain the oop
|
const Register obj_reg = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // Will contain the oop
|
||||||
|
const Register rklass_decode_tmp = LP64_ONLY(rscratch1) NOT_LP64(noreg);
|
||||||
|
|
||||||
const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
|
const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
|
||||||
const int lock_offset = BasicObjectLock::lock_offset_in_bytes ();
|
const int lock_offset = BasicObjectLock::lock_offset_in_bytes ();
|
||||||
|
@ -1197,8 +1198,14 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) {
|
||||||
// Load object pointer into obj_reg
|
// Load object pointer into obj_reg
|
||||||
movptr(obj_reg, Address(lock_reg, obj_offset));
|
movptr(obj_reg, Address(lock_reg, obj_offset));
|
||||||
|
|
||||||
|
if (DiagnoseSyncOnPrimitiveWrappers != 0) {
|
||||||
|
load_klass(tmp_reg, obj_reg, rklass_decode_tmp);
|
||||||
|
movl(tmp_reg, Address(tmp_reg, Klass::access_flags_offset()));
|
||||||
|
testl(tmp_reg, JVM_ACC_IS_BOX_CLASS);
|
||||||
|
jcc(Assembler::notZero, slow_case);
|
||||||
|
}
|
||||||
|
|
||||||
if (UseBiasedLocking) {
|
if (UseBiasedLocking) {
|
||||||
Register rklass_decode_tmp = LP64_ONLY(rscratch1) NOT_LP64(noreg);
|
|
||||||
biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp_reg, rklass_decode_tmp, false, done, &slow_case);
|
biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp_reg, rklass_decode_tmp, false, done, &slow_case);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1081,7 +1081,7 @@ void MacroAssembler::reserved_stack_check() {
|
||||||
bind(no_reserved_zone_enabling);
|
bind(no_reserved_zone_enabling);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MacroAssembler::biased_locking_enter(Register lock_reg,
|
void MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
Register obj_reg,
|
Register obj_reg,
|
||||||
Register swap_reg,
|
Register swap_reg,
|
||||||
Register tmp_reg,
|
Register tmp_reg,
|
||||||
|
@ -1108,9 +1108,7 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
// pointers to allow age to be placed into low bits
|
// pointers to allow age to be placed into low bits
|
||||||
// First check to see whether biasing is even enabled for this object
|
// First check to see whether biasing is even enabled for this object
|
||||||
Label cas_label;
|
Label cas_label;
|
||||||
int null_check_offset = -1;
|
|
||||||
if (!swap_reg_contains_mark) {
|
if (!swap_reg_contains_mark) {
|
||||||
null_check_offset = offset();
|
|
||||||
movptr(swap_reg, mark_addr);
|
movptr(swap_reg, mark_addr);
|
||||||
}
|
}
|
||||||
movptr(tmp_reg, swap_reg);
|
movptr(tmp_reg, swap_reg);
|
||||||
|
@ -1127,9 +1125,6 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
// simpler.
|
// simpler.
|
||||||
movptr(saved_mark_addr, swap_reg);
|
movptr(saved_mark_addr, swap_reg);
|
||||||
#endif
|
#endif
|
||||||
if (swap_reg_contains_mark) {
|
|
||||||
null_check_offset = offset();
|
|
||||||
}
|
|
||||||
load_prototype_header(tmp_reg, obj_reg, tmp_reg2);
|
load_prototype_header(tmp_reg, obj_reg, tmp_reg2);
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
orptr(tmp_reg, r15_thread);
|
orptr(tmp_reg, r15_thread);
|
||||||
|
@ -1263,8 +1258,6 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
}
|
}
|
||||||
|
|
||||||
bind(cas_label);
|
bind(cas_label);
|
||||||
|
|
||||||
return null_check_offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {
|
void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {
|
||||||
|
|
|
@ -661,11 +661,7 @@ class MacroAssembler: public Assembler {
|
||||||
// allocate a temporary (inefficient, avoid if possible).
|
// allocate a temporary (inefficient, avoid if possible).
|
||||||
// Optional slow case is for implementations (interpreter and C1) which branch to
|
// 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.
|
// slow case directly. Leaves condition codes set for C2's Fast_Lock node.
|
||||||
// Returns offset of first potentially-faulting instruction for null
|
void biased_locking_enter(Register lock_reg, Register obj_reg,
|
||||||
// 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,
|
Register swap_reg, Register tmp_reg,
|
||||||
Register tmp_reg2, bool swap_reg_contains_mark,
|
Register tmp_reg2, bool swap_reg_contains_mark,
|
||||||
Label& done, Label* slow_case = NULL,
|
Label& done, Label* slow_case = NULL,
|
||||||
|
|
|
@ -2184,6 +2184,14 @@ void SystemDictionary::resolve_well_known_classes(TRAPS) {
|
||||||
//_box_klasses[T_OBJECT] = WK_KLASS(object_klass);
|
//_box_klasses[T_OBJECT] = WK_KLASS(object_klass);
|
||||||
//_box_klasses[T_ARRAY] = WK_KLASS(object_klass);
|
//_box_klasses[T_ARRAY] = WK_KLASS(object_klass);
|
||||||
|
|
||||||
|
if (DiagnoseSyncOnPrimitiveWrappers != 0) {
|
||||||
|
for (int i = T_BOOLEAN; i < T_LONG + 1; i++) {
|
||||||
|
assert(_box_klasses[i] != NULL, "NULL box class");
|
||||||
|
_box_klasses[i]->set_is_box();
|
||||||
|
_box_klasses[i]->set_prototype_header(markWord::prototype());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if (UseSharedSpaces) {
|
if (UseSharedSpaces) {
|
||||||
JVMTI_ONLY(assert(JvmtiExport::is_early_phase(),
|
JVMTI_ONLY(assert(JvmtiExport::is_early_phase(),
|
||||||
|
|
|
@ -66,6 +66,10 @@
|
||||||
<Field type="InflateCause" name="cause" label="Monitor Inflation Cause" description="Cause of inflation" />
|
<Field type="InflateCause" name="cause" label="Monitor Inflation Cause" description="Cause of inflation" />
|
||||||
</Event>
|
</Event>
|
||||||
|
|
||||||
|
<Event name="SyncOnPrimitiveWrapper" category="Java Virtual Machine, Diagnostics" label="Primitive Wrapper Synchronization" thread="true" stackTrace="true" startTime="false" experimental="true">
|
||||||
|
<Field type="Class" name="boxClass" label="Boxing Class" />
|
||||||
|
</Event>
|
||||||
|
|
||||||
<Event name="BiasedLockRevocation" category="Java Virtual Machine, Runtime" label="Biased Lock Revocation" description="Revoked bias of object" thread="true"
|
<Event name="BiasedLockRevocation" category="Java Virtual Machine, Runtime" label="Biased Lock Revocation" description="Revoked bias of object" thread="true"
|
||||||
stackTrace="true">
|
stackTrace="true">
|
||||||
<Field type="Class" name="lockClass" label="Lock Class" description="Class of object whose biased lock was revoked" />
|
<Field type="Class" name="lockClass" label="Lock Class" description="Class of object whose biased lock was revoked" />
|
||||||
|
|
|
@ -130,6 +130,7 @@
|
||||||
LOG_TAG(phases) \
|
LOG_TAG(phases) \
|
||||||
LOG_TAG(plab) \
|
LOG_TAG(plab) \
|
||||||
LOG_TAG(preview) /* Trace loading of preview feature types */ \
|
LOG_TAG(preview) /* Trace loading of preview feature types */ \
|
||||||
|
LOG_TAG(primitivewrappers) \
|
||||||
LOG_TAG(promotion) \
|
LOG_TAG(promotion) \
|
||||||
LOG_TAG(preorder) /* Trace all classes loaded in order referenced (not loaded) */ \
|
LOG_TAG(preorder) /* Trace all classes loaded in order referenced (not loaded) */ \
|
||||||
LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \
|
LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \
|
||||||
|
|
|
@ -632,6 +632,8 @@ protected:
|
||||||
void set_is_hidden() { _access_flags.set_is_hidden_class(); }
|
void set_is_hidden() { _access_flags.set_is_hidden_class(); }
|
||||||
bool is_non_strong_hidden() const { return access_flags().is_hidden_class() &&
|
bool is_non_strong_hidden() const { return access_flags().is_hidden_class() &&
|
||||||
class_loader_data()->has_class_mirror_holder(); }
|
class_loader_data()->has_class_mirror_holder(); }
|
||||||
|
bool is_box() const { return access_flags().is_box_class(); }
|
||||||
|
void set_is_box() { _access_flags.set_is_box_class(); }
|
||||||
|
|
||||||
bool is_cloneable() const;
|
bool is_cloneable() const;
|
||||||
void set_is_cloneable();
|
void set_is_cloneable();
|
||||||
|
@ -641,6 +643,7 @@ protected:
|
||||||
// prototype markWord. If biased locking is enabled it may further be
|
// prototype markWord. If biased locking is enabled it may further be
|
||||||
// biasable and have an epoch.
|
// biasable and have an epoch.
|
||||||
markWord prototype_header() const { return _prototype_header; }
|
markWord prototype_header() const { return _prototype_header; }
|
||||||
|
|
||||||
// NOTE: once instances of this klass are floating around in the
|
// NOTE: once instances of this klass are floating around in the
|
||||||
// system, this header must only be updated at a safepoint.
|
// system, this header must only be updated at a safepoint.
|
||||||
// NOTE 2: currently we only ever set the prototype header to the
|
// NOTE 2: currently we only ever set the prototype header to the
|
||||||
|
|
|
@ -4193,6 +4193,11 @@ jint Arguments::apply_ergo() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (FLAG_IS_CMDLINE(DiagnoseSyncOnPrimitiveWrappers)) {
|
||||||
|
if (DiagnoseSyncOnPrimitiveWrappers == ObjectSynchronizer::LOG_WARNING && !log_is_enabled(Info, primitivewrappers)) {
|
||||||
|
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(primitivewrappers));
|
||||||
|
}
|
||||||
|
}
|
||||||
return JNI_OK;
|
return JNI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -808,6 +808,16 @@ const size_t minimumSymbolTableSize = 1024;
|
||||||
range(500, max_intx) \
|
range(500, max_intx) \
|
||||||
constraint(BiasedLockingDecayTimeFunc,AfterErgo) \
|
constraint(BiasedLockingDecayTimeFunc,AfterErgo) \
|
||||||
\
|
\
|
||||||
|
diagnostic(intx, DiagnoseSyncOnPrimitiveWrappers, 0, \
|
||||||
|
"Detect and take action upon identifying synchronization on " \
|
||||||
|
"primitive wrappers. Modes: " \
|
||||||
|
"0: off; " \
|
||||||
|
"1: exit with fatal error; " \
|
||||||
|
"2: log message to stdout. Output file can be specified with " \
|
||||||
|
" -Xlog:primitivewrappers. If JFR is running it will " \
|
||||||
|
" also generate JFR events.") \
|
||||||
|
range(0, 2) \
|
||||||
|
\
|
||||||
product(bool, ExitOnOutOfMemoryError, false, \
|
product(bool, ExitOnOutOfMemoryError, false, \
|
||||||
"JVM exits on the first occurrence of an out-of-memory error") \
|
"JVM exits on the first occurrence of an out-of-memory error") \
|
||||||
\
|
\
|
||||||
|
|
|
@ -504,6 +504,10 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread* self,
|
||||||
NoSafepointVerifier nsv;
|
NoSafepointVerifier nsv;
|
||||||
if (obj == NULL) return false; // Need to throw NPE
|
if (obj == NULL) return false; // Need to throw NPE
|
||||||
|
|
||||||
|
if (DiagnoseSyncOnPrimitiveWrappers != 0 && obj->klass()->is_box()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const markWord mark = obj->mark();
|
const markWord mark = obj->mark();
|
||||||
|
|
||||||
if (mark.has_monitor()) {
|
if (mark.has_monitor()) {
|
||||||
|
@ -554,6 +558,52 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread* self,
|
||||||
return false; // revert to slow-path
|
return false; // revert to slow-path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle notifications when synchronizing on primitive wrappers
|
||||||
|
void ObjectSynchronizer::handle_sync_on_primitive_wrapper(Handle obj, Thread* current) {
|
||||||
|
assert(current->is_Java_thread(), "must be for java object synchronization");
|
||||||
|
JavaThread* self = (JavaThread*) current;
|
||||||
|
|
||||||
|
frame last_frame = self->last_frame();
|
||||||
|
if (last_frame.is_interpreted_frame()) {
|
||||||
|
// adjust bcp to point back to monitorenter so that we print the correct line numbers
|
||||||
|
last_frame.interpreter_frame_set_bcp(last_frame.interpreter_frame_bcp() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DiagnoseSyncOnPrimitiveWrappers == FATAL_EXIT) {
|
||||||
|
ResourceMark rm(self);
|
||||||
|
stringStream ss;
|
||||||
|
self->print_stack_on(&ss);
|
||||||
|
char* base = (char*)strstr(ss.base(), "at");
|
||||||
|
char* newline = (char*)strchr(ss.base(), '\n');
|
||||||
|
if (newline != NULL) {
|
||||||
|
*newline = '\0';
|
||||||
|
}
|
||||||
|
fatal("Synchronizing on object " INTPTR_FORMAT " of klass %s %s", p2i(obj()), obj->klass()->external_name(), base);
|
||||||
|
} else {
|
||||||
|
assert(DiagnoseSyncOnPrimitiveWrappers == LOG_WARNING, "invalid value for DiagnoseSyncOnPrimitiveWrappers");
|
||||||
|
ResourceMark rm(self);
|
||||||
|
Log(primitivewrappers) pwlog;
|
||||||
|
|
||||||
|
pwlog.info("Synchronizing on object " INTPTR_FORMAT " of klass %s", p2i(obj()), obj->klass()->external_name());
|
||||||
|
if (self->has_last_Java_frame()) {
|
||||||
|
LogStream info_stream(pwlog.info());
|
||||||
|
self->print_stack_on(&info_stream);
|
||||||
|
} else {
|
||||||
|
pwlog.info("Cannot find the last Java frame");
|
||||||
|
}
|
||||||
|
|
||||||
|
EventSyncOnPrimitiveWrapper event;
|
||||||
|
if (event.should_commit()) {
|
||||||
|
event.set_boxClass(obj->klass());
|
||||||
|
event.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_frame.is_interpreted_frame()) {
|
||||||
|
last_frame.interpreter_frame_set_bcp(last_frame.interpreter_frame_bcp() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Monitor Enter/Exit
|
// Monitor Enter/Exit
|
||||||
// The interpreter and compiler assembly code tries to lock using the fast path
|
// The interpreter and compiler assembly code tries to lock using the fast path
|
||||||
|
@ -561,6 +611,10 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread* self,
|
||||||
// changed. The implementation is extremely sensitive to race condition. Be careful.
|
// changed. The implementation is extremely sensitive to race condition. Be careful.
|
||||||
|
|
||||||
void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, TRAPS) {
|
void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, TRAPS) {
|
||||||
|
if (DiagnoseSyncOnPrimitiveWrappers != 0 && obj->klass()->is_box()) {
|
||||||
|
handle_sync_on_primitive_wrapper(obj, THREAD);
|
||||||
|
}
|
||||||
|
|
||||||
if (UseBiasedLocking) {
|
if (UseBiasedLocking) {
|
||||||
if (!SafepointSynchronize::is_at_safepoint()) {
|
if (!SafepointSynchronize::is_at_safepoint()) {
|
||||||
BiasedLocking::revoke(obj, THREAD);
|
BiasedLocking::revoke(obj, THREAD);
|
||||||
|
@ -704,6 +758,10 @@ void ObjectSynchronizer::reenter(Handle obj, intx recursions, TRAPS) {
|
||||||
// JNI locks on java objects
|
// JNI locks on java objects
|
||||||
// NOTE: must use heavy weight monitor to handle jni monitor enter
|
// NOTE: must use heavy weight monitor to handle jni monitor enter
|
||||||
void ObjectSynchronizer::jni_enter(Handle obj, TRAPS) {
|
void ObjectSynchronizer::jni_enter(Handle obj, TRAPS) {
|
||||||
|
if (DiagnoseSyncOnPrimitiveWrappers != 0 && obj->klass()->is_box()) {
|
||||||
|
handle_sync_on_primitive_wrapper(obj, THREAD);
|
||||||
|
}
|
||||||
|
|
||||||
// the current locking is from JNI instead of Java code
|
// the current locking is from JNI instead of Java code
|
||||||
if (UseBiasedLocking) {
|
if (UseBiasedLocking) {
|
||||||
BiasedLocking::revoke(obj, THREAD);
|
BiasedLocking::revoke(obj, THREAD);
|
||||||
|
|
|
@ -62,6 +62,12 @@ class ObjectSynchronizer : AllStatic {
|
||||||
inflate_cause_nof = 7 // Number of causes
|
inflate_cause_nof = 7 // Number of causes
|
||||||
} InflateCause;
|
} InflateCause;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NOT_ENABLED = 0,
|
||||||
|
FATAL_EXIT = 1,
|
||||||
|
LOG_WARNING = 2
|
||||||
|
} SyncDiagnosticOption;
|
||||||
|
|
||||||
// exit must be implemented non-blocking, since the compiler cannot easily handle
|
// exit must be implemented non-blocking, since the compiler cannot easily handle
|
||||||
// deoptimization at monitor exit. Hence, it does not take a Handle argument.
|
// deoptimization at monitor exit. Hence, it does not take a Handle argument.
|
||||||
|
|
||||||
|
@ -194,6 +200,8 @@ class ObjectSynchronizer : AllStatic {
|
||||||
static u_char* get_gvars_hc_sequence_addr();
|
static u_char* get_gvars_hc_sequence_addr();
|
||||||
static size_t get_gvars_size();
|
static size_t get_gvars_size();
|
||||||
static u_char* get_gvars_stw_random_addr();
|
static u_char* get_gvars_stw_random_addr();
|
||||||
|
|
||||||
|
static void handle_sync_on_primitive_wrapper(Handle obj, Thread* current);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ObjectLocker enforces balanced locking and can never throw an
|
// ObjectLocker enforces balanced locking and can never throw an
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -67,6 +67,7 @@ enum {
|
||||||
JVM_ACC_HAS_FINAL_METHOD = 0x01000000, // True if klass has final method
|
JVM_ACC_HAS_FINAL_METHOD = 0x01000000, // True if klass has final method
|
||||||
JVM_ACC_IS_SHARED_CLASS = 0x02000000, // True if klass is shared
|
JVM_ACC_IS_SHARED_CLASS = 0x02000000, // True if klass is shared
|
||||||
JVM_ACC_IS_HIDDEN_CLASS = 0x04000000, // True if klass is hidden
|
JVM_ACC_IS_HIDDEN_CLASS = 0x04000000, // True if klass is hidden
|
||||||
|
JVM_ACC_IS_BOX_CLASS = 0x08000000, // True if klass is primitive wrapper
|
||||||
|
|
||||||
// Klass* and Method* flags
|
// Klass* and Method* flags
|
||||||
JVM_ACC_HAS_LOCAL_VARIABLE_TABLE= 0x00200000,
|
JVM_ACC_HAS_LOCAL_VARIABLE_TABLE= 0x00200000,
|
||||||
|
@ -151,6 +152,7 @@ class AccessFlags {
|
||||||
bool is_cloneable_fast () const { return (_flags & JVM_ACC_IS_CLONEABLE_FAST ) != 0; }
|
bool is_cloneable_fast () const { return (_flags & JVM_ACC_IS_CLONEABLE_FAST ) != 0; }
|
||||||
bool is_shared_class () const { return (_flags & JVM_ACC_IS_SHARED_CLASS ) != 0; }
|
bool is_shared_class () const { return (_flags & JVM_ACC_IS_SHARED_CLASS ) != 0; }
|
||||||
bool is_hidden_class () const { return (_flags & JVM_ACC_IS_HIDDEN_CLASS ) != 0; }
|
bool is_hidden_class () const { return (_flags & JVM_ACC_IS_HIDDEN_CLASS ) != 0; }
|
||||||
|
bool is_box_class () const { return (_flags & JVM_ACC_IS_BOX_CLASS ) != 0; }
|
||||||
|
|
||||||
// Klass* and Method* flags
|
// Klass* and Method* flags
|
||||||
bool has_localvariable_table () const { return (_flags & JVM_ACC_HAS_LOCAL_VARIABLE_TABLE) != 0; }
|
bool has_localvariable_table () const { return (_flags & JVM_ACC_HAS_LOCAL_VARIABLE_TABLE) != 0; }
|
||||||
|
@ -224,6 +226,7 @@ class AccessFlags {
|
||||||
void set_has_miranda_methods() { atomic_set_bits(JVM_ACC_HAS_MIRANDA_METHODS); }
|
void set_has_miranda_methods() { atomic_set_bits(JVM_ACC_HAS_MIRANDA_METHODS); }
|
||||||
void set_is_shared_class() { atomic_set_bits(JVM_ACC_IS_SHARED_CLASS); }
|
void set_is_shared_class() { atomic_set_bits(JVM_ACC_IS_SHARED_CLASS); }
|
||||||
void set_is_hidden_class() { atomic_set_bits(JVM_ACC_IS_HIDDEN_CLASS); }
|
void set_is_hidden_class() { atomic_set_bits(JVM_ACC_IS_HIDDEN_CLASS); }
|
||||||
|
void set_is_box_class() { atomic_set_bits(JVM_ACC_IS_BOX_CLASS); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// field flags
|
// field flags
|
||||||
|
|
|
@ -91,6 +91,11 @@
|
||||||
<setting name="threshold" control="synchronization-threshold">20 ms</setting>
|
<setting name="threshold" control="synchronization-threshold">20 ms</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
|
<event name="jdk.SyncOnPrimitiveWrapper">
|
||||||
|
<setting name="enabled">true</setting>
|
||||||
|
<setting name="stackTrace">true</setting>
|
||||||
|
</event>
|
||||||
|
|
||||||
<event name="jdk.BiasedLockRevocation">
|
<event name="jdk.BiasedLockRevocation">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
|
|
|
@ -91,6 +91,11 @@
|
||||||
<setting name="threshold" control="synchronization-threshold">10 ms</setting>
|
<setting name="threshold" control="synchronization-threshold">10 ms</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
|
<event name="jdk.SyncOnPrimitiveWrapper">
|
||||||
|
<setting name="enabled">true</setting>
|
||||||
|
<setting name="stackTrace">true</setting>
|
||||||
|
</event>
|
||||||
|
|
||||||
<event name="jdk.BiasedLockRevocation">
|
<event name="jdk.BiasedLockRevocation">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8242263
|
||||||
|
* @summary Exercise DiagnoseSyncOnPrimitiveWrappers diagnostic flag
|
||||||
|
* @library /test/lib
|
||||||
|
* @run driver/timeout=180000 SyncOnPrimitiveWrapperTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class SyncOnPrimitiveWrapperTest {
|
||||||
|
static final int LOOP_COUNT = 3000;
|
||||||
|
static final int THREAD_COUNT = 2;
|
||||||
|
static String[] fatalTests[];
|
||||||
|
static String[] logTests[];
|
||||||
|
static List<Object> testObjects = new ArrayList<Object>();
|
||||||
|
|
||||||
|
private static final String[] specificFlags[] = {
|
||||||
|
{"-Xint", "-XX:+UseBiasedLocking"},
|
||||||
|
{"-Xint", "-XX:-UseBiasedLocking"},
|
||||||
|
{"-Xcomp", "-XX:TieredStopAtLevel=1", "-XX:+UseBiasedLocking"},
|
||||||
|
{"-Xcomp", "-XX:TieredStopAtLevel=1", "-XX:-UseBiasedLocking"},
|
||||||
|
{"-Xcomp", "-XX:-TieredCompilation", "-XX:-UseBiasedLocking"},
|
||||||
|
{"-Xcomp", "-XX:-TieredCompilation", "-XX:+UseBiasedLocking", "-XX:+UseOptoBiasInlining"},
|
||||||
|
{"-Xcomp", "-XX:-TieredCompilation", "-XX:+UseBiasedLocking", "-XX:-UseOptoBiasInlining"}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void initTestObjects() {
|
||||||
|
testObjects.add(Character.valueOf('H'));
|
||||||
|
testObjects.add(Boolean.valueOf(true));
|
||||||
|
testObjects.add(Byte.valueOf((byte)0x40));
|
||||||
|
testObjects.add(Short.valueOf((short)0x4000));
|
||||||
|
testObjects.add(Integer.valueOf(0x40000000));
|
||||||
|
testObjects.add(Long.valueOf(0x4000000000000000L));
|
||||||
|
testObjects.add(Float.valueOf(1.20f));
|
||||||
|
testObjects.add(Double.valueOf(1.2345));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void generateTests() {
|
||||||
|
initTestObjects();
|
||||||
|
String[] commonFatalTestsFlags = {"-XX:+UnlockDiagnosticVMOptions", "-XX:-CreateCoredumpOnCrash", "-XX:DiagnoseSyncOnPrimitiveWrappers=1"};
|
||||||
|
fatalTests = new String[specificFlags.length * testObjects.size()][];
|
||||||
|
for (int i = 0; i < specificFlags.length; i++) {
|
||||||
|
for (int j = 0; j < testObjects.size(); j++) {
|
||||||
|
int index = i * testObjects.size() + j;
|
||||||
|
fatalTests[index] = Stream.of(commonFatalTestsFlags, specificFlags[i], new String[] {"SyncOnPrimitiveWrapperTest$FatalTest", Integer.toString(j)})
|
||||||
|
.flatMap(Stream::of)
|
||||||
|
.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String[] commonLogTestsFlags = {"-XX:+UnlockDiagnosticVMOptions", "-XX:DiagnoseSyncOnPrimitiveWrappers=2"};
|
||||||
|
logTests = new String[specificFlags.length][];
|
||||||
|
for (int i = 0; i < specificFlags.length; i++) {
|
||||||
|
logTests[i] = Stream.of(commonLogTestsFlags, specificFlags[i], new String[] {"SyncOnPrimitiveWrapperTest$LogTest"})
|
||||||
|
.flatMap(Stream::of)
|
||||||
|
.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
generateTests();
|
||||||
|
for (int i = 0; i < fatalTests.length; i++) {
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(fatalTests[i]);
|
||||||
|
OutputAnalyzer output = ProcessTools.executeProcess(pb);
|
||||||
|
output.shouldContain("fatal error: Synchronizing on object");
|
||||||
|
output.shouldNotContain("synchronization on primitive wrapper did not fail");
|
||||||
|
output.shouldNotHaveExitValue(0);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < logTests.length; i++) {
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(logTests[i]);
|
||||||
|
OutputAnalyzer output = ProcessTools.executeProcess(pb);
|
||||||
|
checkOutput(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkOutput(OutputAnalyzer output) {
|
||||||
|
String out = output.getOutput();
|
||||||
|
assertTrue(out.matches("(?s).*Synchronizing on object 0[xX][0-9a-fA-F]+ of klass java\\.lang\\.Character.*"));
|
||||||
|
assertTrue(out.matches("(?s).*Synchronizing on object 0[xX][0-9a-fA-F]+ of klass java\\.lang\\.Boolean.*"));
|
||||||
|
assertTrue(out.matches("(?s).*Synchronizing on object 0[xX][0-9a-fA-F]+ of klass java\\.lang\\.Byte.*"));
|
||||||
|
assertTrue(out.matches("(?s).*Synchronizing on object 0[xX][0-9a-fA-F]+ of klass java\\.lang\\.Short.*"));
|
||||||
|
assertTrue(out.matches("(?s).*Synchronizing on object 0[xX][0-9a-fA-F]+ of klass java\\.lang\\.Integer.*"));
|
||||||
|
assertTrue(out.matches("(?s).*Synchronizing on object 0[xX][0-9a-fA-F]+ of klass java\\.lang\\.Long.*"));
|
||||||
|
String[] res = out.split("Synchronizing on object 0[xX][0-9a-fA-F]+ of klass java\\.lang\\.Float\\R");
|
||||||
|
assertTrue(res.length - 1 == (LOOP_COUNT * THREAD_COUNT + 1), res.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertTrue(boolean condition) {
|
||||||
|
if (!condition) {
|
||||||
|
throw new RuntimeException("No synchronization matches");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertTrue(boolean condition, int count) {
|
||||||
|
if (!condition) {
|
||||||
|
throw new RuntimeException("Synchronization count was " + count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FatalTest {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
initTestObjects();
|
||||||
|
synchronized (testObjects.get(Integer.valueOf(args[0]))) {
|
||||||
|
throw new RuntimeException("synchronization on primitive wrapper did not fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LogTest implements Runnable {
|
||||||
|
private static long sharedCounter = 0L;
|
||||||
|
private static Float sharedLock1 = 0.0f;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
initTestObjects();
|
||||||
|
for (Object obj : testObjects) {
|
||||||
|
synchronized (obj) {
|
||||||
|
sharedCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogTest test = new LogTest();
|
||||||
|
Thread[] threads = new Thread[THREAD_COUNT];
|
||||||
|
for (int i = 0; i < threads.length; i++) {
|
||||||
|
threads[i] = new Thread(test);
|
||||||
|
threads[i].start();
|
||||||
|
}
|
||||||
|
for (Thread t : threads) {
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (int i = 0; i < LOOP_COUNT; i++) {
|
||||||
|
synchronized (sharedLock1) {
|
||||||
|
sharedCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,7 +82,7 @@ public class TestLookForUntestedEvents {
|
||||||
// Experimental events
|
// Experimental events
|
||||||
private static final Set<String> experimentalEvents = new HashSet<>(
|
private static final Set<String> experimentalEvents = new HashSet<>(
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
"Flush")
|
"Flush", "SyncOnPrimitiveWrapper")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.jfr.event.runtime;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import jdk.jfr.Recording;
|
||||||
|
import jdk.jfr.consumer.RecordedEvent;
|
||||||
|
import jdk.jfr.consumer.RecordedThread;
|
||||||
|
import jdk.test.lib.jfr.EventNames;
|
||||||
|
import jdk.test.lib.jfr.Events;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8242263
|
||||||
|
* @requires vm.hasJFR
|
||||||
|
* @key jfr
|
||||||
|
* @library /test/lib
|
||||||
|
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnPrimitiveWrappers=2 jdk.jfr.event.runtime.TestSyncOnPrimitiveWrapperEvent
|
||||||
|
*/
|
||||||
|
public class TestSyncOnPrimitiveWrapperEvent {
|
||||||
|
static final String EVENT_NAME = EventNames.SyncOnPrimitiveWrapper;
|
||||||
|
static String[] classesWanted = {"java/lang/Character", "java/lang/Boolean", "java/lang/Byte", "java/lang/Short",
|
||||||
|
"java/lang/Integer", "java/lang/Long", "java/lang/Float", "java/lang/Double"};
|
||||||
|
static List<Object> testObjects = new ArrayList<Object>();
|
||||||
|
static Integer counter = 0;
|
||||||
|
|
||||||
|
private static void initTestObjects() {
|
||||||
|
testObjects.add(Character.valueOf('H'));
|
||||||
|
testObjects.add(Boolean.valueOf(true));
|
||||||
|
testObjects.add(Byte.valueOf((byte)0x40));
|
||||||
|
testObjects.add(Short.valueOf((short)0x4000));
|
||||||
|
testObjects.add(Integer.valueOf(0x40000000));
|
||||||
|
testObjects.add(Long.valueOf(0x4000000000000000L));
|
||||||
|
testObjects.add(Float.valueOf(1.20f));
|
||||||
|
testObjects.add(Double.valueOf(1.2345));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
initTestObjects();
|
||||||
|
Recording recording = new Recording();
|
||||||
|
recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
|
||||||
|
recording.start();
|
||||||
|
for (Object obj : testObjects) {
|
||||||
|
synchronized (obj) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recording.stop();
|
||||||
|
|
||||||
|
List<String> classesFound = new ArrayList<String>();
|
||||||
|
List<RecordedEvent> events = Events.fromRecording(recording);
|
||||||
|
Events.hasEvents(events);
|
||||||
|
for (RecordedEvent event : Events.fromRecording(recording)) {
|
||||||
|
String className = Events.assertField(event, "boxClass.name").notEmpty().getValue();
|
||||||
|
RecordedThread jt = event.getThread();
|
||||||
|
if (Thread.currentThread().getName().equals(jt.getJavaName())) {
|
||||||
|
classesFound.add(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String classWanted : classesWanted) {
|
||||||
|
if (!classesFound.contains(classWanted)) {
|
||||||
|
throw new AssertionError("No matching event SyncOnPrimitiveWrapper with \"boxClass=" + classWanted + "\" and current thread as caller");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (classesFound.size() != classesWanted.length) {
|
||||||
|
throw new AssertionError("Invalid number of SyncOnPrimitiveWrapper events for current thread");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,6 +61,7 @@ public class EventNames {
|
||||||
public final static String JavaMonitorEnter = PREFIX + "JavaMonitorEnter";
|
public final static String JavaMonitorEnter = PREFIX + "JavaMonitorEnter";
|
||||||
public final static String JavaMonitorWait = PREFIX + "JavaMonitorWait";
|
public final static String JavaMonitorWait = PREFIX + "JavaMonitorWait";
|
||||||
public final static String JavaMonitorInflate = PREFIX + "JavaMonitorInflate";
|
public final static String JavaMonitorInflate = PREFIX + "JavaMonitorInflate";
|
||||||
|
public final static String SyncOnPrimitiveWrapper = PREFIX + "SyncOnPrimitiveWrapper";
|
||||||
public final static String ClassLoad = PREFIX + "ClassLoad";
|
public final static String ClassLoad = PREFIX + "ClassLoad";
|
||||||
public final static String ClassDefine = PREFIX + "ClassDefine";
|
public final static String ClassDefine = PREFIX + "ClassDefine";
|
||||||
public final static String ClassUnload = PREFIX + "ClassUnload";
|
public final static String ClassUnload = PREFIX + "ClassUnload";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue