Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8252182: [JEP 390] Diagnose synchronization on @ValueBased classes #274

Closed
wants to merge 8 commits into from
@@ -3887,10 +3887,10 @@ encode %{
// Load markWord from object into displaced_header.
__ ldr(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes()));

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

@@ -75,10 +75,10 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr

null_check_offset = offset();

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

@@ -741,10 +741,10 @@ 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) {
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, obj_reg);
ldrw(tmp, Address(tmp, Klass::access_flags_offset()));
tstw(tmp, JVM_ACC_IS_BOX_CLASS);
tstw(tmp, JVM_ACC_IS_VALUE_BASED_CLASS);
br(Assembler::NE, slow_case);
}

@@ -204,10 +204,10 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj,

null_check_offset = offset();

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

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

Label fast_lock, done;

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

@@ -883,10 +883,10 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) {
// Load object pointer
ldr(Robj, Address(Rlock, obj_offset));

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

@@ -105,10 +105,10 @@ 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) {
if (DiagnoseSyncOnValueBasedClasses != 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));
testbitdi(CCR0, R0, Rscratch, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
bne(CCR0, slow_int);
}

@@ -910,10 +910,10 @@ 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) {
if (DiagnoseSyncOnValueBasedClasses != 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));
testbitdi(CCR0, R0, tmp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
bne(CCR0, slow_case);
}

@@ -2818,10 +2818,10 @@ 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) {
if (DiagnoseSyncOnValueBasedClasses != 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));
testbitdi(flag, R0, temp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
bne(flag, cont);
}

@@ -91,9 +91,9 @@ 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) {
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(Z_R1_scratch, obj);
testbit(Address(Z_R1_scratch, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_BOX_CLASS));
testbit(Address(Z_R1_scratch, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
z_btrue(slow_case);
}

@@ -999,9 +999,9 @@ 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) {
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(Z_R1_scratch, object);
testbit(Address(Z_R1_scratch, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_BOX_CLASS));
testbit(Address(Z_R1_scratch, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
z_btrue(slow_case);
}

@@ -3326,11 +3326,11 @@ 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) {
if (DiagnoseSyncOnValueBasedClasses != 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);
assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction");
z_nilh(Z_R1_scratch, JVM_ACC_IS_VALUE_BASED_CLASS >> 16);
z_brne(done);
}

@@ -54,10 +54,10 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr

null_check_offset = offset();

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

@@ -485,10 +485,10 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp

Label IsInflated, DONE_LABEL;

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

@@ -1219,10 +1219,10 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) {
// Load object pointer into obj_reg
movptr(obj_reg, Address(lock_reg, obj_offset));

if (DiagnoseSyncOnPrimitiveWrappers != 0) {
if (DiagnoseSyncOnValueBasedClasses != 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);
testl(tmp_reg, JVM_ACC_IS_VALUE_BASED_CLASS);
jcc(Assembler::notZero, slow_case);
}

@@ -1091,6 +1091,7 @@ class AnnotationCollector : public ResourceObj{
_jdk_internal_vm_annotation_Contended,
_field_Stable,
_jdk_internal_vm_annotation_ReservedStackAccess,
_jdk_internal_ValueBased,
_annotation_LIMIT
};
const Location _location;
@@ -2147,6 +2148,11 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
if (RestrictReservedStack && !privileged) break; // honor privileges
return _jdk_internal_vm_annotation_ReservedStackAccess;
}
case VM_SYMBOL_ENUM_NAME(jdk_internal_ValueBased_signature): {
if (_location != _in_class) break; // only allow for classes
if (!privileged) break; // only allow in priviledged code
return _jdk_internal_ValueBased;
}
default: {
break;
}
@@ -2190,7 +2196,16 @@ void MethodAnnotationCollector::apply_to(const methodHandle& m) {

void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
assert(ik != NULL, "invariant");
ik->set_is_contended(is_contended());
if (has_annotation(_jdk_internal_vm_annotation_Contended)) {
ik->set_is_contended(is_contended());
}
if (has_annotation(_jdk_internal_ValueBased)) {
ik->set_has_value_based_class_annotation();
if (DiagnoseSyncOnValueBasedClasses) {
ik->set_is_value_based();
ik->set_prototype_header(markWord::prototype());
}
}
}

#define MAX_ARGS_SIZE 255
@@ -2142,14 +2142,6 @@ void SystemDictionary::resolve_well_known_classes(TRAPS) {
//_box_klasses[T_OBJECT] = 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
if (UseSharedSpaces) {
JVMTI_ONLY(assert(JvmtiExport::is_early_phase(),
@@ -249,6 +249,7 @@
template(java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl") \
template(jdk_internal_vm_annotation_Contended_signature, "Ljdk/internal/vm/annotation/Contended;") \
template(jdk_internal_vm_annotation_ReservedStackAccess_signature, "Ljdk/internal/vm/annotation/ReservedStackAccess;") \
template(jdk_internal_ValueBased_signature, "Ljdk/internal/ValueBased;") \
\
/* class symbols needed by intrinsics */ \
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, template, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \
@@ -66,8 +66,8 @@
<Field type="InflateCause" name="cause" label="Monitor Inflation Cause" description="Cause of inflation" />
</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 name="SyncOnValueBasedClass" category="Java Virtual Machine, Diagnostics" label="Value Based Class Synchronization" thread="true" stackTrace="true" startTime="false" experimental="true">
<Field type="Class" name="valueBasedClass" label="Value Based Class" />
</Event>

<Event name="BiasedLockRevocation" category="Java Virtual Machine, Runtime" label="Biased Lock Revocation" description="Revoked bias of object" thread="true"
@@ -140,7 +140,6 @@
LOG_TAG(plab) \
LOG_TAG(preorder) /* Trace all classes loaded in order referenced (not loaded) */ \
LOG_TAG(preview) /* Trace loading of preview feature types */ \
LOG_TAG(primitivewrappers) \
LOG_TAG(promotion) \
LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \
LOG_TAG(ptrqueue) \
@@ -186,6 +185,7 @@
LOG_TAG(unload) /* Trace unloading of classes */ \
LOG_TAG(unshareable) \
LOG_TAG(update) \
LOG_TAG(valuebasedclasses) \
LOG_TAG(verification) \
LOG_TAG(verify) \
LOG_TAG(vmmutex) \
@@ -2594,6 +2594,12 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
if (UseBiasedLocking && BiasedLocking::enabled()) {
set_prototype_header(markWord::biased_locking_prototype());
}

// Initialize @ValueBased class annotation
if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation()) {
set_is_value_based();
set_prototype_header(markWord::prototype());
}
}

void InstanceKlass::set_shared_class_loader_type(s2 loader_type) {
@@ -176,7 +176,8 @@ class Klass : public Metadata {
// Flags of the current shared class.
u2 _shared_class_flags;
enum {
_archived_lambda_proxy_is_available = 2
_archived_lambda_proxy_is_available = 2,
_has_value_based_class_annotation = 4
};
#endif

@@ -321,6 +322,18 @@ class Klass : public Metadata {
NOT_CDS(return false;)
}

void set_has_value_based_class_annotation() {
CDS_ONLY(_shared_class_flags |= _has_value_based_class_annotation;)
}
void clear_has_value_based_class_annotation() {
CDS_ONLY(_shared_class_flags &= ~_has_value_based_class_annotation;)
}
bool has_value_based_class_annotation() const {
CDS_ONLY(return (_shared_class_flags & _has_value_based_class_annotation) != 0;)
NOT_CDS(return false;)
}


// Obtain the module or package for this class
virtual ModuleEntry* module() const = 0;
virtual PackageEntry* package() const = 0;
@@ -624,8 +637,8 @@ class Klass : public Metadata {
void set_is_hidden() { _access_flags.set_is_hidden_class(); }
bool is_non_strong_hidden() const { return access_flags().is_hidden_class() &&
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_value_based() { return _access_flags.is_value_based_class(); }
void set_is_value_based() { _access_flags.set_is_value_based_class(); }

bool is_cloneable() const;
void set_is_cloneable();
@@ -4251,9 +4251,9 @@ jint Arguments::apply_ergo() {
}
#endif // COMPILER2

if (FLAG_IS_CMDLINE(DiagnoseSyncOnPrimitiveWrappers)) {
if (DiagnoseSyncOnPrimitiveWrappers == ObjectSynchronizer::LOG_WARNING && !log_is_enabled(Info, primitivewrappers)) {
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(primitivewrappers));
if (FLAG_IS_CMDLINE(DiagnoseSyncOnValueBasedClasses)) {
if (DiagnoseSyncOnValueBasedClasses == ObjectSynchronizer::LOG_WARNING && !log_is_enabled(Info, valuebasedclasses)) {
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(valuebasedclasses));
}
}
return JNI_OK;
@@ -851,13 +851,13 @@ const intx ObjectAlignmentInBytes = 8;
range(500, max_intx) \
constraint(BiasedLockingDecayTimeFunc,AfterErgo) \
\
product(intx, DiagnoseSyncOnPrimitiveWrappers, 0, DIAGNOSTIC, \
product(intx, DiagnoseSyncOnValueBasedClasses, 0, DIAGNOSTIC, \
"Detect and take action upon identifying synchronization on " \
"primitive wrappers. Modes: " \
"value based classes. 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 " \
" -Xlog:valuebasedclasses. If JFR is running it will " \
" also generate JFR events.") \
range(0, 2) \
\