8302354: InstanceKlass init state/thread should be atomic

Reviewed-by: coleenp, dholmes
This commit is contained in:
Robbin Ehn 2023-02-14 14:38:46 +00:00
parent 2ef001e097
commit 77519e5f4f
5 changed files with 15 additions and 14 deletions

View file

@ -158,8 +158,8 @@
\ \
nonstatic_field(InstanceKlass, _fields, Array<u2>*) \ nonstatic_field(InstanceKlass, _fields, Array<u2>*) \
nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ nonstatic_field(InstanceKlass, _constants, ConstantPool*) \
nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \
nonstatic_field(InstanceKlass, _init_thread, Thread*) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \
nonstatic_field(InstanceKlass, _misc_flags._flags, u2) \ nonstatic_field(InstanceKlass, _misc_flags._flags, u2) \
nonstatic_field(InstanceKlass, _annotations, Annotations*) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \
\ \

View file

@ -251,7 +251,7 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_co
} }
if (invoke_code == Bytecodes::_invokestatic) { if (invoke_code == Bytecodes::_invokestatic) {
assert(method->method_holder()->is_initialized() || assert(method->method_holder()->is_initialized() ||
method->method_holder()->is_init_thread(Thread::current()), method->method_holder()->is_init_thread(JavaThread::current()),
"invalid class initialization state for invoke_static"); "invalid class initialization state for invoke_static");
if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) {

View file

@ -3354,7 +3354,7 @@ static void print_vtable(vtableEntry* start, int len, outputStream* st) {
} }
const char* InstanceKlass::init_state_name() const { const char* InstanceKlass::init_state_name() const {
return state_names[_init_state]; return state_names[init_state()];
} }
void InstanceKlass::print_on(outputStream* st) const { void InstanceKlass::print_on(outputStream* st) const {
@ -3898,7 +3898,7 @@ void InstanceKlass::set_init_state(ClassState state) {
assert(good_state || state == allocated || link_failed, "illegal state transition"); assert(good_state || state == allocated || link_failed, "illegal state transition");
#endif #endif
assert(_init_thread == nullptr, "should be cleared before state change"); assert(_init_thread == nullptr, "should be cleared before state change");
_init_state = state; Atomic::store(&_init_state, state);
} }
#if INCLUDE_JVMTI #if INCLUDE_JVMTI

View file

@ -226,7 +226,7 @@ class InstanceKlass: public Klass {
// _misc_flags right now. // _misc_flags right now.
bool _is_marked_dependent; // used for marking during flushing and deoptimization bool _is_marked_dependent; // used for marking during flushing and deoptimization
ClassState _init_state; // state of class volatile ClassState _init_state; // state of class
u1 _reference_type; // reference type u1 _reference_type; // reference type
@ -234,7 +234,7 @@ class InstanceKlass: public Klass {
InstanceKlassFlags _misc_flags; InstanceKlassFlags _misc_flags;
Monitor* _init_monitor; // mutual exclusion to _init_state and _init_thread. Monitor* _init_monitor; // mutual exclusion to _init_state and _init_thread.
Thread* _init_thread; // Pointer to current thread doing initialization (to handle recursive initialization) JavaThread* volatile _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) 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 JNIid* _jni_ids; // First JNI identifier for static fields in this class
@ -511,7 +511,7 @@ public:
bool is_not_initialized() const { return init_state() < being_initialized; } bool is_not_initialized() const { return init_state() < being_initialized; }
bool is_being_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_in_error_state() const { return init_state() == initialization_error; }
bool is_init_thread(Thread *thread) { return thread == _init_thread; } bool is_init_thread(JavaThread *thread) { return thread == Atomic::load(&_init_thread); }
ClassState init_state() const { return Atomic::load(&_init_state); } ClassState init_state() const { return Atomic::load(&_init_state); }
const char* init_state_name() const; const char* init_state_name() const;
bool is_rewritten() const { return _misc_flags.rewritten(); } bool is_rewritten() const { return _misc_flags.rewritten(); }
@ -1077,9 +1077,10 @@ public:
// initialization state // initialization state
void set_init_state(ClassState state); void set_init_state(ClassState state);
void set_rewritten() { _misc_flags.set_rewritten(true); } void set_rewritten() { _misc_flags.set_rewritten(true); }
void set_init_thread(Thread *thread) { void set_init_thread(JavaThread *thread) {
assert(thread == nullptr || _init_thread == nullptr, "Only one thread is allowed to own initialization"); assert((thread == JavaThread::current() && _init_thread == nullptr) ||
_init_thread = thread; (thread == nullptr && _init_thread == JavaThread::current()), "Only one thread is allowed to own initialization");
Atomic::store(&_init_thread, thread);
} }
// The RedefineClasses() API can cause new method idnums to be needed // The RedefineClasses() API can cause new method idnums to be needed

View file

@ -235,8 +235,8 @@
nonstatic_field(InstanceKlass, _static_oop_field_count, u2) \ nonstatic_field(InstanceKlass, _static_oop_field_count, u2) \
nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \ nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \
nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \ nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \
nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \
nonstatic_field(InstanceKlass, _init_thread, Thread*) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \
nonstatic_field(InstanceKlass, _itable_len, int) \ nonstatic_field(InstanceKlass, _itable_len, int) \
nonstatic_field(InstanceKlass, _reference_type, u1) \ nonstatic_field(InstanceKlass, _reference_type, u1) \
volatile_nonstatic_field(InstanceKlass, _oop_map_cache, OopMapCache*) \ volatile_nonstatic_field(InstanceKlass, _oop_map_cache, OopMapCache*) \