mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8155951: VM crash in nsk/jvmti/RedefineClasses/StressRedefine: assert failed: Corrupted constant pool
8151066: assert(0 <= i && i < length()) failed: index out of bounds Lock classes for redefinition because constant pool merging isn't thread safe, use method constant pool because constant pool merging doesn't make equivalent cpCaches because of invokedynamic Reviewed-by: sspitsyn, dholmes
This commit is contained in:
parent
e84506041e
commit
178842d251
7 changed files with 75 additions and 25 deletions
|
@ -69,6 +69,43 @@ VM_RedefineClasses::VM_RedefineClasses(jint class_count,
|
|||
_res = JVMTI_ERROR_NONE;
|
||||
}
|
||||
|
||||
static inline InstanceKlass* get_ik(jclass def) {
|
||||
oop mirror = JNIHandles::resolve_non_null(def);
|
||||
return InstanceKlass::cast(java_lang_Class::as_Klass(mirror));
|
||||
}
|
||||
|
||||
// If any of the classes are being redefined, wait
|
||||
// Parallel constant pool merging leads to indeterminate constant pools.
|
||||
void VM_RedefineClasses::lock_classes() {
|
||||
MutexLocker ml(RedefineClasses_lock);
|
||||
bool has_redefined;
|
||||
do {
|
||||
has_redefined = false;
|
||||
// Go through classes each time until none are being redefined.
|
||||
for (int i = 0; i < _class_count; i++) {
|
||||
if (get_ik(_class_defs[i].klass)->is_being_redefined()) {
|
||||
RedefineClasses_lock->wait();
|
||||
has_redefined = true;
|
||||
break; // for loop
|
||||
}
|
||||
}
|
||||
} while (has_redefined);
|
||||
for (int i = 0; i < _class_count; i++) {
|
||||
get_ik(_class_defs[i].klass)->set_is_being_redefined(true);
|
||||
}
|
||||
RedefineClasses_lock->notify_all();
|
||||
}
|
||||
|
||||
void VM_RedefineClasses::unlock_classes() {
|
||||
MutexLocker ml(RedefineClasses_lock);
|
||||
for (int i = 0; i < _class_count; i++) {
|
||||
assert(get_ik(_class_defs[i].klass)->is_being_redefined(),
|
||||
"should be being redefined to get here");
|
||||
get_ik(_class_defs[i].klass)->set_is_being_redefined(false);
|
||||
}
|
||||
RedefineClasses_lock->notify_all();
|
||||
}
|
||||
|
||||
bool VM_RedefineClasses::doit_prologue() {
|
||||
if (_class_count == 0) {
|
||||
_res = JVMTI_ERROR_NONE;
|
||||
|
@ -91,6 +128,14 @@ bool VM_RedefineClasses::doit_prologue() {
|
|||
_res = JVMTI_ERROR_NULL_POINTER;
|
||||
return false;
|
||||
}
|
||||
|
||||
oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
|
||||
// classes for primitives and arrays cannot be redefined
|
||||
// check here so following code can assume these classes are InstanceKlass
|
||||
if (!is_modifiable_class(mirror)) {
|
||||
_res = JVMTI_ERROR_UNMODIFIABLE_CLASS;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Start timer after all the sanity checks; not quite accurate, but
|
||||
|
@ -99,6 +144,7 @@ bool VM_RedefineClasses::doit_prologue() {
|
|||
_timer_vm_op_prologue.start();
|
||||
}
|
||||
|
||||
lock_classes();
|
||||
// We first load new class versions in the prologue, because somewhere down the
|
||||
// call chain it is required that the current thread is a Java thread.
|
||||
_res = load_new_class_versions(Thread::current());
|
||||
|
@ -115,6 +161,7 @@ bool VM_RedefineClasses::doit_prologue() {
|
|||
// Free os::malloc allocated memory in load_new_class_version.
|
||||
os::free(_scratch_classes);
|
||||
_timer_vm_op_prologue.stop();
|
||||
unlock_classes();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -174,6 +221,8 @@ void VM_RedefineClasses::doit() {
|
|||
}
|
||||
|
||||
void VM_RedefineClasses::doit_epilogue() {
|
||||
unlock_classes();
|
||||
|
||||
// Free os::malloc allocated memory.
|
||||
os::free(_scratch_classes);
|
||||
|
||||
|
@ -959,14 +1008,7 @@ jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {
|
|||
// versions are deleted. Constant pools are deallocated while merging
|
||||
// constant pools
|
||||
HandleMark hm(THREAD);
|
||||
|
||||
oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
|
||||
// classes for primitives cannot be redefined
|
||||
if (!is_modifiable_class(mirror)) {
|
||||
return JVMTI_ERROR_UNMODIFIABLE_CLASS;
|
||||
}
|
||||
Klass* the_class_oop = java_lang_Class::as_Klass(mirror);
|
||||
instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop);
|
||||
instanceKlassHandle the_class(THREAD, get_ik(_class_defs[i].klass));
|
||||
Symbol* the_class_sym = the_class->name();
|
||||
|
||||
log_debug(redefine, class, load)
|
||||
|
@ -3757,22 +3799,19 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
|
|||
_timer_rsc_phase1.start();
|
||||
}
|
||||
|
||||
instanceKlassHandle scratch_class(scratch_class_oop);
|
||||
|
||||
oop the_class_mirror = JNIHandles::resolve_non_null(the_jclass);
|
||||
Klass* the_class_oop = java_lang_Class::as_Klass(the_class_mirror);
|
||||
instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop);
|
||||
instanceKlassHandle scratch_class(THREAD, scratch_class_oop);
|
||||
instanceKlassHandle the_class(THREAD, get_ik(the_jclass));
|
||||
|
||||
// Remove all breakpoints in methods of this class
|
||||
JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints();
|
||||
jvmti_breakpoints.clearall_in_class_at_safepoint(the_class_oop);
|
||||
jvmti_breakpoints.clearall_in_class_at_safepoint(the_class());
|
||||
|
||||
// Deoptimize all compiled code that depends on this class
|
||||
flush_dependent_code(the_class, THREAD);
|
||||
|
||||
_old_methods = the_class->methods();
|
||||
_new_methods = scratch_class->methods();
|
||||
_the_class_oop = the_class_oop;
|
||||
_the_class_oop = the_class();
|
||||
compute_added_deleted_matching_methods();
|
||||
update_jmethod_ids();
|
||||
|
||||
|
@ -4002,10 +4041,10 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
|
|||
increment_class_counter((InstanceKlass *)the_class(), THREAD);
|
||||
log_info(redefine, class, load)
|
||||
("redefined name=%s, count=%d (avail_mem=" UINT64_FORMAT "K)",
|
||||
the_class->external_name(), java_lang_Class::classRedefinedCount(the_class_mirror), os::available_memory() >> 10);
|
||||
the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), os::available_memory() >> 10);
|
||||
Events::log_redefinition(THREAD, "redefined class name=%s, count=%d",
|
||||
the_class->external_name(),
|
||||
java_lang_Class::classRedefinedCount(the_class_mirror));
|
||||
java_lang_Class::classRedefinedCount(the_class->java_mirror()));
|
||||
|
||||
}
|
||||
_timer_rsc_phase2.stop();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue