Skip to content
Permalink
Browse files
8257845: Integrate JEP 390
8254047: [JEP 390] Revise "value-based class" & apply to wrappers
8252181: [JEP 390] Define & apply annotation jdk.internal.ValueBased
8252183: [JEP 390] Add 'lint' warning for @valuebased classes
8257027: [JEP 390] Diagnose synchronization on @valuebased classes
8252180: [JEP 390] Deprecate wrapper class constructors for removal

Co-authored-by: Roger Riggs <rriggs@openjdk.org>
Co-authored-by: Srikanth Adayapalam <sadayapalam@openjdk.org>
Co-authored-by: Lois Foltan <lfoltan@openjdk.org>
Reviewed-by: rriggs, hseigel, mchung, darcy
  • Loading branch information
4 people committed Dec 8, 2020
1 parent ed4c4ee commit 48d8650ae187821d0e79f7353c2f039518e313b1
Showing 113 changed files with 695 additions and 327 deletions.
@@ -3893,10 +3893,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);
}

@@ -746,10 +746,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"
@@ -141,7 +141,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) \
@@ -187,6 +186,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) \
@@ -2600,6 +2600,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();
@@ -4139,9 +4139,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;