8288064: Class initialization locking

Reviewed-by: rehn, vlivanov
This commit is contained in:
Coleen Phillimore 2022-06-16 12:38:06 +00:00
parent 3d12c0225b
commit cf4a4966a8
14 changed files with 140 additions and 172 deletions

View File

@ -792,7 +792,6 @@ int java_lang_Class::_class_loader_offset;
int java_lang_Class::_module_offset;
int java_lang_Class::_protection_domain_offset;
int java_lang_Class::_component_mirror_offset;
int java_lang_Class::_init_lock_offset;
int java_lang_Class::_signers_offset;
int java_lang_Class::_name_offset;
int java_lang_Class::_source_file_offset;
@ -926,12 +925,6 @@ void java_lang_Class::initialize_mirror_fields(Klass* k,
Handle protection_domain,
Handle classData,
TRAPS) {
// Allocate a simple java object for a lock.
// This needs to be a java object because during class initialization
// it can be held across a java call.
typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK);
set_init_lock(mirror(), r);
// Set protection domain also
set_protection_domain(mirror(), protection_domain());
@ -1270,8 +1263,6 @@ oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror,
// Reset local static fields in the mirror
InstanceKlass::cast(k)->do_local_static_fields(&reset);
set_init_lock(archived_mirror, NULL);
set_protection_domain(archived_mirror, NULL);
set_signers(archived_mirror, NULL);
set_source_file(archived_mirror, NULL);
@ -1353,10 +1344,6 @@ bool java_lang_Class::restore_archived_mirror(Klass *k,
if (!k->is_array_klass()) {
// - local static final fields with initial values were initialized at dump time
// create the init_lock
typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK_(false));
set_init_lock(mirror(), r);
if (protection_domain.not_null()) {
set_protection_domain(mirror(), protection_domain());
}
@ -1421,15 +1408,6 @@ oop java_lang_Class::component_mirror(oop java_class) {
return java_class->obj_field(_component_mirror_offset);
}
oop java_lang_Class::init_lock(oop java_class) {
assert(_init_lock_offset != 0, "must be set");
return java_class->obj_field(_init_lock_offset);
}
void java_lang_Class::set_init_lock(oop java_class, oop init_lock) {
assert(_init_lock_offset != 0, "must be set");
java_class->obj_field_put(_init_lock_offset, init_lock);
}
objArrayOop java_lang_Class::signers(oop java_class) {
assert(_signers_offset != 0, "must be set");
return (objArrayOop)java_class->obj_field(_signers_offset);
@ -1641,18 +1619,12 @@ void java_lang_Class::compute_offsets() {
InstanceKlass* k = vmClasses::Class_klass();
CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET);
// Init lock is a C union with component_mirror. Only instanceKlass mirrors have
// init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops
// GC treats them the same.
_init_lock_offset = _component_mirror_offset;
CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
#if INCLUDE_CDS
void java_lang_Class::serialize_offsets(SerializeClosure* f) {
f->do_bool(&_offsets_computed);
f->do_u4((u4*)&_init_lock_offset);
CLASS_FIELDS_DO(FIELD_SERIALIZE_OFFSET);

View File

@ -285,7 +285,6 @@ class java_lang_Class : AllStatic {
static int _static_oop_field_count_offset;
static int _protection_domain_offset;
static int _init_lock_offset;
static int _signers_offset;
static int _class_loader_offset;
static int _module_offset;
@ -300,7 +299,6 @@ class java_lang_Class : AllStatic {
static GrowableArray<Klass*>* _fixup_mirror_list;
static GrowableArray<Klass*>* _fixup_module_field_list;
static void set_init_lock(oop java_class, oop init_lock);
static void set_protection_domain(oop java_class, oop protection_domain);
static void set_class_loader(oop java_class, oop class_loader);
static void set_component_mirror(oop java_class, oop comp_mirror);
@ -356,10 +354,6 @@ class java_lang_Class : AllStatic {
// Support for embedded per-class oops
static oop protection_domain(oop java_class);
static oop init_lock(oop java_class);
static void clear_init_lock(oop java_class) {
set_init_lock(java_class, NULL);
}
static oop component_mirror(oop java_class);
static objArrayOop signers(oop java_class);
static void set_signers(oop java_class, objArrayOop signers);

View File

@ -1774,7 +1774,7 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHan
// the interpreter or runtime performs a serialized check of
// the relevant CPCE::f1 field. This is done by the caller
// of this method, via CPCE::set_dynamic_call, which uses
// an ObjectLocker to do the final serialization of updates
// a lock to do the final serialization of updates
// to CPCE state, including f1.
// Log dynamic info to CDS classlist.

View File

@ -156,7 +156,7 @@
\
nonstatic_field(InstanceKlass, _fields, Array<u2>*) \
nonstatic_field(InstanceKlass, _constants, ConstantPool*) \
nonstatic_field(InstanceKlass, _init_state, u1) \
nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \
nonstatic_field(InstanceKlass, _init_thread, Thread*) \
nonstatic_field(InstanceKlass, _misc_flags, u2) \
nonstatic_field(InstanceKlass, _annotations, Annotations*) \

View File

@ -266,7 +266,7 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_co
}
if (invoke_code == Bytecodes::_invokestatic) {
assert(method->method_holder()->is_initialized() ||
method->method_holder()->is_reentrant_initialization(Thread::current()),
method->method_holder()->is_init_thread(Thread::current()),
"invalid class initialization state for invoke_static");
if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) {
@ -373,15 +373,9 @@ void ConstantPoolCacheEntry::set_method_handle_common(const constantPoolHandle&
// A losing writer waits on the lock until the winner writes f1 and leaves
// the lock, so that when the losing writer returns, he can use the linked
// cache entry.
// Lock fields to write
MutexLocker ml(cpool->pool_holder()->init_monitor());
JavaThread* current = JavaThread::current();
objArrayHandle resolved_references(current, cpool->resolved_references());
// Use the resolved_references() lock for this cpCache entry.
// resolved_references are created for all classes with Invokedynamic, MethodHandle
// or MethodType constant pool cache entries.
assert(resolved_references() != NULL,
"a resolved_references array should have been created for this class");
ObjectLocker ol(resolved_references, current);
if (!is_f1_null()) {
return;
}
@ -453,6 +447,7 @@ void ConstantPoolCacheEntry::set_method_handle_common(const constantPoolHandle&
// Store appendix, if any.
if (has_appendix) {
const int appendix_index = f2_as_index();
objArrayOop resolved_references = cpool->resolved_references();
assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob");
assert(resolved_references->obj_at(appendix_index) == NULL, "init just once");
resolved_references->obj_at_put(appendix_index, appendix());
@ -480,14 +475,7 @@ bool ConstantPoolCacheEntry::save_and_throw_indy_exc(
assert(PENDING_EXCEPTION->is_a(vmClasses::LinkageError_klass()),
"No LinkageError exception");
// Use the resolved_references() lock for this cpCache entry.
// resolved_references are created for all classes with Invokedynamic, MethodHandle
// or MethodType constant pool cache entries.
JavaThread* current = THREAD;
objArrayHandle resolved_references(current, cpool->resolved_references());
assert(resolved_references() != NULL,
"a resolved_references array should have been created for this class");
ObjectLocker ol(resolved_references, current);
MutexLocker ml(THREAD, cpool->pool_holder()->init_monitor());
// if f1 is not null or the indy_resolution_failed flag is set then another
// thread either succeeded in resolving the method or got a LinkageError

View File

@ -495,6 +495,10 @@ Array<int>* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) {
return vtable_indices;
}
static Monitor* create_init_monitor(const char* name) {
return new Monitor(Mutex::safepoint, name);
}
InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind) :
Klass(kind),
_nest_members(NULL),
@ -507,6 +511,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind) :
_nest_host_index(0),
_init_state(allocated),
_reference_type(parser.reference_type()),
_init_monitor(create_init_monitor("InstanceKlassInitMonitor_lock")),
_init_thread(NULL)
{
set_vtable_length(parser.vtable_size());
@ -724,28 +729,6 @@ objArrayOop InstanceKlass::signers() const {
return java_lang_Class::signers(java_mirror());
}
oop InstanceKlass::init_lock() const {
// return the init lock from the mirror
oop lock = java_lang_Class::init_lock(java_mirror());
// Prevent reordering with any access of initialization state
OrderAccess::loadload();
assert(lock != NULL || !is_not_initialized(), // initialized or in_error state
"only fully initialized state can have a null lock");
return lock;
}
// Set the initialization lock to null so the object can be GC'ed. Any racing
// threads to get this lock will see a null lock and will not lock.
// That's okay because they all check for initialized state after getting
// the lock and return.
void InstanceKlass::fence_and_clear_init_lock() {
// make sure previous stores are all done, notably the init_state.
OrderAccess::storestore();
java_lang_Class::clear_init_lock(java_mirror());
assert(!is_not_initialized(), "class must be initialized now");
}
// See "The Virtual Machine Specification" section 2.16.5 for a detailed explanation of the class initialization
// process. The step comments refers to the procedure described in that section.
// Note: implementation moved to static method to expose the this pointer.
@ -773,6 +756,26 @@ void InstanceKlass::link_class(TRAPS) {
}
}
void InstanceKlass::check_link_state_and_wait(JavaThread* current) {
MonitorLocker ml(current, _init_monitor);
// Another thread is linking this class, wait.
while (is_being_linked() && !is_init_thread(current)) {
ml.wait();
}
// This thread is recursively linking this class, continue
if (is_being_linked() && is_init_thread(current)) {
return;
}
// If this class wasn't linked already, set state to being_linked
if (!is_linked()) {
set_init_state(being_linked);
set_init_thread(current);
}
}
// Called to verify that a class can link during initialization, without
// throwing a VerifyError.
bool InstanceKlass::link_class_or_fail(TRAPS) {
@ -851,9 +854,8 @@ bool InstanceKlass::link_class_impl(TRAPS) {
// verification & rewriting
{
HandleMark hm(THREAD);
Handle h_init_lock(THREAD, init_lock());
ObjectLocker ol(h_init_lock, jt);
LockLinkState init_lock(this, jt);
// rewritten will have been set if loader constraint error found
// on an earlier link attempt
// don't verify or rewrite if already rewritten
@ -911,17 +913,7 @@ bool InstanceKlass::link_class_impl(TRAPS) {
// In case itable verification is ever added.
// itable().verify(tty, true);
#endif
if (UseVtableBasedCHA) {
MutexLocker ml(THREAD, Compile_lock);
set_init_state(linked);
// Now flush all code that assume the class is not linked.
if (Universe::is_fully_initialized()) {
CodeCache::flush_dependents_on(this);
}
} else {
set_init_state(linked);
}
set_initialization_state_and_notify(linked, THREAD);
if (JvmtiExport::should_post_class_prepare()) {
JvmtiExport::post_class_prepare(THREAD, this);
}
@ -1034,28 +1026,25 @@ void InstanceKlass::initialize_impl(TRAPS) {
DTRACE_CLASSINIT_PROBE(required, -1);
bool wait = false;
bool throw_error = false;
JavaThread* jt = THREAD;
// refer to the JVM book page 47 for description of steps
// Step 1
{
Handle h_init_lock(THREAD, init_lock());
ObjectLocker ol(h_init_lock, jt);
MonitorLocker ml(THREAD, _init_monitor);
// Step 2
// If we were to use wait() instead of waitInterruptibly() then
// we might end up throwing IE from link/symbol resolution sites
// that aren't expected to throw. This would wreak havoc. See 6320309.
while (is_being_initialized() && !is_reentrant_initialization(jt)) {
while (is_being_initialized() && !is_init_thread(jt)) {
wait = true;
jt->set_class_to_be_initialized(this);
ol.wait_uninterruptibly(jt);
ml.wait();
jt->set_class_to_be_initialized(NULL);
}
// Step 3
if (is_being_initialized() && is_reentrant_initialization(jt)) {
if (is_being_initialized() && is_init_thread(jt)) {
DTRACE_CLASSINIT_PROBE_WAIT(recursive, -1, wait);
return;
}
@ -1068,23 +1057,29 @@ void InstanceKlass::initialize_impl(TRAPS) {
// Step 5
if (is_in_error_state()) {
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait);
ResourceMark rm(THREAD);
Handle cause(THREAD, get_initialization_error(THREAD));
throw_error = true;
} else {
stringStream ss;
ss.print("Could not initialize class %s", external_name());
if (cause.is_null()) {
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string());
} else {
THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(),
ss.as_string(), cause);
}
// Step 6
set_init_state(being_initialized);
set_init_thread(jt);
}
}
// Step 6
set_init_state(being_initialized);
set_init_thread(jt);
// Throw error outside lock
if (throw_error) {
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait);
ResourceMark rm(THREAD);
Handle cause(THREAD, get_initialization_error(THREAD));
stringStream ss;
ss.print("Could not initialize class %s", external_name());
if (cause.is_null()) {
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string());
} else {
THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(),
ss.as_string(), cause);
}
}
// Step 7
@ -1144,7 +1139,7 @@ void InstanceKlass::initialize_impl(TRAPS) {
// Step 9
if (!HAS_PENDING_EXCEPTION) {
set_initialization_state_and_notify(fully_initialized, CHECK);
set_initialization_state_and_notify(fully_initialized, THREAD);
debug_only(vtable().verify(tty, true);)
}
else {
@ -1177,19 +1172,23 @@ void InstanceKlass::initialize_impl(TRAPS) {
}
void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) {
Handle h_init_lock(THREAD, init_lock());
if (h_init_lock() != NULL) {
ObjectLocker ol(h_init_lock, THREAD);
void InstanceKlass::set_initialization_state_and_notify(ClassState state, JavaThread* current) {
MonitorLocker ml(current, _init_monitor);
// Now flush all code that assume the class is not linked.
// Set state under the Compile_lock also.
if (state == linked && UseVtableBasedCHA && Universe::is_fully_initialized()) {
MutexLocker ml(current, Compile_lock);
set_init_thread(NULL); // reset _init_thread before changing _init_state
set_init_state(state);
fence_and_clear_init_lock();
ol.notify_all(CHECK);
CodeCache::flush_dependents_on(this);
} else {
assert(h_init_lock() != NULL, "The initialization state should never be set twice");
set_init_thread(NULL); // reset _init_thread before changing _init_state
set_init_state(state);
}
ml.notify_all();
}
InstanceKlass* InstanceKlass::implementor() const {
@ -2518,6 +2517,7 @@ void InstanceKlass::remove_unshareable_info() {
_nest_host = NULL;
init_shared_package_entry();
_dep_context_last_cleaned = 0;
_init_monitor = NULL;
}
void InstanceKlass::remove_java_mirror() {
@ -2597,6 +2597,9 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation()) {
set_is_value_based();
}
// restore the monitor
_init_monitor = create_init_monitor("InstanceKlassInitMonitorRestored_lock");
}
// Check if a class or any of its supertypes has a version older than 50.
@ -2704,6 +2707,9 @@ void InstanceKlass::release_C_heap_structures(bool release_constant_pool) {
// Deallocate and call destructors for MDO mutexes
methods_do(method_release_C_heap_structures);
// Destroy the init_monitor
delete _init_monitor;
// Deallocate oop map cache
if (_oop_map_cache != NULL) {
delete _oop_map_cache;
@ -3377,7 +3383,7 @@ nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_le
#define BULLET " - "
static const char* state_names[] = {
"allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
"allocated", "loaded", "being_linked", "linked", "being_initialized", "fully_initialized", "initialization_error"
};
static void print_vtable(intptr_t* start, int len, outputStream* st) {
@ -3931,13 +3937,17 @@ void JNIid::verify(Klass* holder) {
}
void InstanceKlass::set_init_state(ClassState state) {
if (state > loaded) {
assert_lock_strong(_init_monitor);
}
#ifdef ASSERT
bool good_state = is_shared() ? (_init_state <= state)
: (_init_state < state);
assert(good_state || state == allocated, "illegal state transition");
bool link_failed = _init_state == being_linked && state == loaded;
assert(good_state || state == allocated || link_failed, "illegal state transition");
#endif
assert(_init_thread == NULL, "should be cleared before state change");
_init_state = (u1)state;
_init_state = state;
}
#if INCLUDE_JVMTI

View File

@ -143,9 +143,10 @@ class InstanceKlass: public Klass {
// See "The Java Virtual Machine Specification" section 2.16.2-5 for a detailed description
// of the class loading & initialization procedure, and the use of the states.
enum ClassState {
enum ClassState : u1 {
allocated, // allocated (but not yet linked)
loaded, // loaded and inserted in class hierarchy (but not linked yet)
being_linked, // currently running verifier and rewriter
linked, // successfully linked/verified (but not initialized yet)
being_initialized, // currently running class initializer
fully_initialized, // initialized (successful final state)
@ -224,12 +225,9 @@ class InstanceKlass: public Klass {
// _misc_flags.
bool _is_marked_dependent; // used for marking during flushing and deoptimization
// Class states are defined as ClassState (see above).
// Place the _init_state here to utilize the unused 2-byte after
// _idnum_allocated_count.
u1 _init_state; // state of class
ClassState _init_state; // state of class
u1 _reference_type; // reference type
u1 _reference_type; // reference type
enum {
_misc_rewritten = 1 << 0, // methods rewritten.
@ -252,7 +250,9 @@ class InstanceKlass: public Klass {
}
u2 _misc_flags; // There is more space in access_flags for more flags.
Monitor* _init_monitor; // mutual exclusion to _init_state and _init_thread.
Thread* _init_thread; // Pointer to current thread doing initialization (to handle recursive initialization)
OopMapCache* volatile _oop_map_cache; // OopMapCache for all methods in the klass (allocated lazily)
JNIid* _jni_ids; // First JNI identifier for static fields in this class
jmethodID* volatile _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none
@ -536,17 +536,33 @@ public:
TRAPS);
public:
// initialization state
bool is_loaded() const { return _init_state >= loaded; }
bool is_linked() const { return _init_state >= linked; }
bool is_initialized() const { return _init_state == fully_initialized; }
bool is_not_initialized() const { return _init_state < being_initialized; }
bool is_being_initialized() const { return _init_state == being_initialized; }
bool is_in_error_state() const { return _init_state == initialization_error; }
bool is_reentrant_initialization(Thread *thread) { return thread == _init_thread; }
ClassState init_state() { return (ClassState)_init_state; }
bool is_loaded() const { return init_state() >= loaded; }
bool is_linked() const { return init_state() >= linked; }
bool is_being_linked() const { return init_state() == being_linked; }
bool is_initialized() const { return init_state() == fully_initialized; }
bool is_not_initialized() const { return init_state() < being_initialized; }
bool is_being_initialized() const { return init_state() == being_initialized; }
bool is_in_error_state() const { return init_state() == initialization_error; }
bool is_init_thread(Thread *thread) { return thread == _init_thread; }
ClassState init_state() const { return Atomic::load(&_init_state); }
const char* init_state_name() const;
bool is_rewritten() const { return (_misc_flags & _misc_rewritten) != 0; }
class LockLinkState : public StackObj {
InstanceKlass* _ik;
JavaThread* _current;
public:
LockLinkState(InstanceKlass* ik, JavaThread* current) : _ik(ik), _current(current) {
ik->check_link_state_and_wait(current);
}
~LockLinkState() {
if (!_ik->is_linked()) {
// Reset to loaded if linking failed.
_ik->set_initialization_state_and_notify(loaded, _current);
}
}
};
// is this a sealed class
bool is_sealed() const;
@ -911,7 +927,7 @@ public:
// initialization
void call_class_initializer(TRAPS);
void set_initialization_state_and_notify(ClassState state, TRAPS);
void set_initialization_state_and_notify(ClassState state, JavaThread* current);
// OopMapCache support
OopMapCache* oop_map_cache() { return _oop_map_cache; }
@ -1138,11 +1154,14 @@ public:
public:
u2 idnum_allocated_count() const { return _idnum_allocated_count; }
private:
private:
// initialization state
void set_init_state(ClassState state);
void set_rewritten() { _misc_flags |= _misc_rewritten; }
void set_init_thread(Thread *thread) { _init_thread = thread; }
void set_init_thread(Thread *thread) {
assert(thread == nullptr || _init_thread == nullptr, "Only one thread is allowed to own initialization");
_init_thread = thread;
}
// The RedefineClasses() API can cause new method idnums to be needed
// which will cause the caches to grow. Safety requires different
@ -1154,12 +1173,6 @@ private:
// Lock during initialization
public:
// Lock for (1) initialization; (2) access to the ConstantPool of this class.
// Must be one per class and it has to be a VM internal object so java code
// cannot lock it (like the mirror).
// It has to be an object not a Mutex because it's held through java calls.
oop init_lock() const;
// Returns the array class for the n'th dimension
virtual Klass* array_klass(int n, TRAPS);
virtual Klass* array_klass_or_null(int n);
@ -1169,9 +1182,10 @@ public:
virtual Klass* array_klass_or_null();
static void clean_initialization_error_table();
private:
void fence_and_clear_init_lock();
Monitor* init_monitor() const { return _init_monitor; }
private:
void check_link_state_and_wait(JavaThread* current);
bool link_class_impl (TRAPS);
bool verify_code (TRAPS);
void initialize_impl (TRAPS);

View File

@ -1405,7 +1405,7 @@ methodHandle SharedRuntime::resolve_sub_helper(bool is_virtual, bool is_optimize
if (invoke_code == Bytecodes::_invokestatic) {
assert(callee_method->method_holder()->is_initialized() ||
callee_method->method_holder()->is_reentrant_initialization(current),
callee_method->method_holder()->is_init_thread(current),
"invalid class initialization state for invoke_static");
if (!VM_Version::supports_fast_class_init_checks() && callee_method->needs_clinit_barrier()) {
// In order to keep class initialization check, do not patch call

View File

@ -226,9 +226,8 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) {
Klass* k = obj->klass();
st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)", "parking to wait for ", p2i(obj), k->external_name());
}
else if (thread()->osthread()->get_state() == OBJECT_WAIT) {
// We are waiting on an Object monitor but Object.wait() isn't the
// top-frame, so we should be waiting on a Class initialization monitor.
else if (thread()->osthread()->get_state() == CONDVAR_WAIT) {
// We are waiting on the native class initialization monitor.
InstanceKlass* k = thread()->class_to_be_initialized();
if (k != NULL) {
st->print_cr("\t- waiting on the Class initialization monitor for %s", k->external_name());

View File

@ -238,7 +238,7 @@
nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \
nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \
nonstatic_field(InstanceKlass, _misc_flags, u2) \
nonstatic_field(InstanceKlass, _init_state, u1) \
nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \
nonstatic_field(InstanceKlass, _init_thread, Thread*) \
nonstatic_field(InstanceKlass, _itable_len, int) \
nonstatic_field(InstanceKlass, _reference_type, u1) \
@ -2280,6 +2280,7 @@
\
declare_constant(InstanceKlass::allocated) \
declare_constant(InstanceKlass::loaded) \
declare_constant(InstanceKlass::being_linked) \
declare_constant(InstanceKlass::linked) \
declare_constant(InstanceKlass::being_initialized) \
declare_constant(InstanceKlass::fully_initialized) \

View File

@ -1126,14 +1126,6 @@ u4 DumperSupport::get_static_fields_size(InstanceKlass* ik, u2& field_count) {
}
}
// Also provide a pointer to the init_lock if present, so there aren't unreferenced int[0]
// arrays.
oop init_lock = ik->init_lock();
if (init_lock != NULL) {
field_count++;
size += sizeof(address);
}
// We write the value itself plus a name and a one byte type tag per field.
return size + field_count * (sizeof(address) + 1);
}
@ -1171,14 +1163,6 @@ void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) {
prev = prev->previous_versions();
}
}
// Add init lock to the end if the class is not yet initialized
oop init_lock = ik->init_lock();
if (init_lock != NULL) {
writer->write_symbolID(vmSymbols::init_lock_name()); // name
writer->write_u1(sig2tag(vmSymbols::int_array_signature())); // type
writer->write_objectID(init_lock);
}
}
// dump the raw values of the instance fields of the given object

View File

@ -60,6 +60,7 @@ public class InstanceKlass extends Klass {
// ClassState constants
private static int CLASS_STATE_ALLOCATED;
private static int CLASS_STATE_LOADED;
private static int CLASS_STATE_BEING_LINKED;
private static int CLASS_STATE_LINKED;
private static int CLASS_STATE_BEING_INITIALIZED;
private static int CLASS_STATE_FULLY_INITIALIZED;
@ -118,6 +119,7 @@ public class InstanceKlass extends Klass {
// read ClassState constants
CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue();
CLASS_STATE_LOADED = db.lookupIntConstant("InstanceKlass::loaded").intValue();
CLASS_STATE_BEING_LINKED = db.lookupIntConstant("InstanceKlass::being_linked").intValue();
CLASS_STATE_LINKED = db.lookupIntConstant("InstanceKlass::linked").intValue();
CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("InstanceKlass::being_initialized").intValue();
CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue();
@ -184,6 +186,7 @@ public class InstanceKlass extends Klass {
public static class ClassState {
public static final ClassState ALLOCATED = new ClassState("allocated");
public static final ClassState LOADED = new ClassState("loaded");
public static final ClassState BEING_LINKED = new ClassState("beingLinked");
public static final ClassState LINKED = new ClassState("linked");
public static final ClassState BEING_INITIALIZED = new ClassState("beingInitialized");
public static final ClassState FULLY_INITIALIZED = new ClassState("fullyInitialized");
@ -207,6 +210,8 @@ public class InstanceKlass extends Klass {
return ClassState.ALLOCATED;
} else if (state == CLASS_STATE_LOADED) {
return ClassState.LOADED;
} else if (state == CLASS_STATE_BEING_LINKED) {
return ClassState.BEING_LINKED;
} else if (state == CLASS_STATE_LINKED) {
return ClassState.LINKED;
} else if (state == CLASS_STATE_BEING_INITIALIZED) {

View File

@ -97,7 +97,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
final int vtableEntrySize = getFieldValue("CompilerToVM::Data::sizeof_vtableEntry", Integer.class, "int");
final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*");
final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "u1");
final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "InstanceKlass::ClassState");
final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*");
final int instanceKlassFieldsOffset = getFieldOffset("InstanceKlass::_fields", Integer.class, "Array<u2>*");
final int instanceKlassAnnotationsOffset = getFieldOffset("InstanceKlass::_annotations", Integer.class, "Annotations*");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, 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
@ -60,7 +60,8 @@ public class TestThreadDumpClassInitMonitor {
*/
final static String TEST_THREAD = "TestThread";
final static String TEST_THREAD_ENTRY = "\"" + TEST_THREAD;
final static String IN_OBJECT_WAIT = "in Object.wait()";
// final static String IN_OBJECT_WAIT = "in Object.wait()";
final static String IN_CONVAR_WAIT = "waiting on condition";
final static String THREAD_STATE = "java.lang.Thread.State: RUNNABLE";
final static String THREAD_INFO = "Thread:"; // the details are not important
final static String JAVATHREAD_STATE = "JavaThread state: _thread_blocked";
@ -139,7 +140,7 @@ public class TestThreadDumpClassInitMonitor {
continue;
}
foundLines++;
if (!line.contains(IN_OBJECT_WAIT)) {
if (!line.contains(IN_CONVAR_WAIT)) {
throw new Error("Unexpected initial stack line: " + line);
}
continue;