Skip to content

Commit 468d6a7

Browse files
committed
8222005: ClassRedefinition crashes with: guarantee(false) failed: OLD and/or OBSOLETE method(s) found
Remove optimizations from class redefinition that cause the guarantee hit Reviewed-by: mbaesken Backport-of: 2ff9f53
1 parent 2a5a4d7 commit 468d6a7

File tree

3 files changed

+63
-66
lines changed

3 files changed

+63
-66
lines changed

src/hotspot/share/oops/cpCache.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -562,15 +562,14 @@ oop ConstantPoolCacheEntry::method_type_if_resolved(const constantPoolHandle& cp
562562
#if INCLUDE_JVMTI
563563

564564
void log_adjust(const char* entry_type, Method* old_method, Method* new_method, bool* trace_name_printed) {
565-
if (log_is_enabled(Info, redefine, class, update)) {
566-
ResourceMark rm;
567-
if (!(*trace_name_printed)) {
568-
log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
569-
*trace_name_printed = true;
570-
}
571-
log_debug(redefine, class, update, constantpool)
572-
("cpc %s entry update: %s(%s)", entry_type, new_method->name()->as_C_string(), new_method->signature()->as_C_string());
565+
ResourceMark rm;
566+
567+
if (!(*trace_name_printed)) {
568+
log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
569+
*trace_name_printed = true;
573570
}
571+
log_trace(redefine, class, update, constantpool)
572+
("cpc %s entry update: %s", entry_type, new_method->external_name());
574573
}
575574

576575
// RedefineClasses() API support:
@@ -817,9 +816,13 @@ void ConstantPoolCache::adjust_method_entries(bool * trace_name_printed) {
817816

818817
// the constant pool cache should never contain old or obsolete methods
819818
bool ConstantPoolCache::check_no_old_or_obsolete_entries() {
819+
ResourceMark rm;
820820
for (int i = 1; i < length(); i++) {
821-
if (entry_at(i)->get_interesting_method_entry() != NULL &&
822-
!entry_at(i)->check_no_old_or_obsolete_entries()) {
821+
Method* m = entry_at(i)->get_interesting_method_entry();
822+
if (m != NULL && !entry_at(i)->check_no_old_or_obsolete_entries()) {
823+
log_trace(redefine, class, update, constantpool)
824+
("cpcache check found old method entry: class: %s, old: %d, obsolete: %d, method: %s",
825+
constant_pool()->pool_holder()->external_name(), m->is_old(), m->is_obsolete(), m->external_name());
823826
return false;
824827
}
825828
}

src/hotspot/share/oops/klassVtable.cpp

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,8 @@ bool klassVtable::adjust_default_method(int vtable_index, Method* old_method, Me
966966
// search the vtable for uses of either obsolete or EMCP methods
967967
void klassVtable::adjust_method_entries(bool * trace_name_printed) {
968968
int prn_enabled = 0;
969+
ResourceMark rm;
970+
969971
for (int index = 0; index < length(); index++) {
970972
Method* old_method = unchecked_method_at(index);
971973
if (old_method == NULL || !old_method->is_old()) {
@@ -983,27 +985,29 @@ void klassVtable::adjust_method_entries(bool * trace_name_printed) {
983985
updated_default = adjust_default_method(index, old_method, new_method);
984986
}
985987

986-
if (log_is_enabled(Info, redefine, class, update)) {
987-
ResourceMark rm;
988-
if (!(*trace_name_printed)) {
989-
log_info(redefine, class, update)
990-
("adjust: klassname=%s for methods from name=%s",
991-
_klass->external_name(), old_method->method_holder()->external_name());
992-
*trace_name_printed = true;
993-
}
994-
log_debug(redefine, class, update, vtables)
995-
("vtable method update: %s(%s), updated default = %s",
996-
new_method->name()->as_C_string(), new_method->signature()->as_C_string(), updated_default ? "true" : "false");
988+
if (!(*trace_name_printed)) {
989+
log_info(redefine, class, update)
990+
("adjust: klassname=%s for methods from name=%s",
991+
_klass->external_name(), old_method->method_holder()->external_name());
992+
*trace_name_printed = true;
997993
}
994+
log_trace(redefine, class, update, vtables)
995+
("vtable method update: class: %s method: %s, updated default = %s",
996+
_klass->external_name(), new_method->external_name(), updated_default ? "true" : "false");
998997
}
999998
}
1000999

10011000
// a vtable should never contain old or obsolete methods
10021001
bool klassVtable::check_no_old_or_obsolete_entries() {
1002+
ResourceMark rm;
1003+
10031004
for (int i = 0; i < length(); i++) {
10041005
Method* m = unchecked_method_at(i);
10051006
if (m != NULL &&
10061007
(NOT_PRODUCT(!m->is_valid() ||) m->is_old() || m->is_obsolete())) {
1008+
log_trace(redefine, class, update, vtables)
1009+
("vtable check found old method entry: class: %s old: %d obsolete: %d, method: %s",
1010+
_klass->external_name(), m->is_old(), m->is_obsolete(), m->external_name());
10071011
return false;
10081012
}
10091013
}
@@ -1292,8 +1296,9 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
12921296
#if INCLUDE_JVMTI
12931297
// search the itable for uses of either obsolete or EMCP methods
12941298
void klassItable::adjust_method_entries(bool * trace_name_printed) {
1295-
1299+
ResourceMark rm;
12961300
itableMethodEntry* ime = method_entry(0);
1301+
12971302
for (int i = 0; i < _size_method_table; i++, ime++) {
12981303
Method* old_method = ime->method();
12991304
if (old_method == NULL || !old_method->is_old()) {
@@ -1303,25 +1308,27 @@ void klassItable::adjust_method_entries(bool * trace_name_printed) {
13031308
Method* new_method = old_method->get_new_method();
13041309
ime->initialize(new_method);
13051310

1306-
if (log_is_enabled(Info, redefine, class, update)) {
1307-
ResourceMark rm;
1308-
if (!(*trace_name_printed)) {
1309-
log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
1310-
*trace_name_printed = true;
1311-
}
1312-
log_trace(redefine, class, update, itables)
1313-
("itable method update: %s(%s)", new_method->name()->as_C_string(), new_method->signature()->as_C_string());
1311+
if (!(*trace_name_printed)) {
1312+
log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
1313+
*trace_name_printed = true;
13141314
}
1315+
log_trace(redefine, class, update, itables)
1316+
("itable method update: class: %s method: %s", _klass->external_name(), new_method->external_name());
13151317
}
13161318
}
13171319

13181320
// an itable should never contain old or obsolete methods
13191321
bool klassItable::check_no_old_or_obsolete_entries() {
1322+
ResourceMark rm;
13201323
itableMethodEntry* ime = method_entry(0);
1324+
13211325
for (int i = 0; i < _size_method_table; i++) {
13221326
Method* m = ime->method();
13231327
if (m != NULL &&
13241328
(NOT_PRODUCT(!m->is_valid() ||) m->is_old() || m->is_obsolete())) {
1329+
log_trace(redefine, class, update, itables)
1330+
("itable check found old method entry: class: %s old: %d obsolete: %d, method: %s",
1331+
_klass->external_name(), m->is_old(), m->is_obsolete(), m->external_name());
13251332
return false;
13261333
}
13271334
ime++;

src/hotspot/share/prims/jvmtiRedefineClasses.cpp

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ Method** VM_RedefineClasses::_added_methods = NULL;
6262
int VM_RedefineClasses::_matching_methods_length = 0;
6363
int VM_RedefineClasses::_deleted_methods_length = 0;
6464
int VM_RedefineClasses::_added_methods_length = 0;
65+
66+
// This flag is global as the constructor does not reset it:
6567
bool VM_RedefineClasses::_has_redefined_Object = false;
66-
bool VM_RedefineClasses::_has_null_class_loader = false;
6768

6869

6970
VM_RedefineClasses::VM_RedefineClasses(jint class_count,
@@ -75,8 +76,6 @@ VM_RedefineClasses::VM_RedefineClasses(jint class_count,
7576
_any_class_has_resolved_methods = false;
7677
_res = JVMTI_ERROR_NONE;
7778
_the_class = NULL;
78-
_has_redefined_Object = false;
79-
_has_null_class_loader = false;
8079
}
8180

8281
static inline InstanceKlass* get_ik(jclass def) {
@@ -3439,7 +3438,10 @@ void VM_RedefineClasses::AdjustAndCleanMetadata::do_klass(Klass* k) {
34393438
bool trace_name_printed = false;
34403439

34413440
// If the class being redefined is java.lang.Object, we need to fix all
3442-
// array class vtables also
3441+
// array class vtables also. The _has_redefined_Object flag is global.
3442+
// Once the java.lang.Object has been redefined (by the current or one
3443+
// of the previous VM_RedefineClasses operations) we have to always
3444+
// adjust method entries for array classes.
34433445
if (k->is_array_klass() && _has_redefined_Object) {
34443446
k->vtable().adjust_method_entries(&trace_name_printed);
34453447

@@ -3457,22 +3459,6 @@ void VM_RedefineClasses::AdjustAndCleanMetadata::do_klass(Klass* k) {
34573459
}
34583460
}
34593461

3460-
// HotSpot specific optimization! HotSpot does not currently
3461-
// support delegation from the bootstrap class loader to a
3462-
// user-defined class loader. This means that if the bootstrap
3463-
// class loader is the initiating class loader, then it will also
3464-
// be the defining class loader. This also means that classes
3465-
// loaded by the bootstrap class loader cannot refer to classes
3466-
// loaded by a user-defined class loader. Note: a user-defined
3467-
// class loader can delegate to the bootstrap class loader.
3468-
//
3469-
// If the current class being redefined has a user-defined class
3470-
// loader as its defining class loader, then we can skip all
3471-
// classes loaded by the bootstrap class loader.
3472-
if (!_has_null_class_loader && ik->class_loader() == NULL) {
3473-
return;
3474-
}
3475-
34763462
// Adjust all vtables, default methods and itables, to clean out old methods.
34773463
ResourceMark rm(_thread);
34783464
if (ik->vtable_length() > 0) {
@@ -3491,22 +3477,24 @@ void VM_RedefineClasses::AdjustAndCleanMetadata::do_klass(Klass* k) {
34913477
// constant pool cache holds the Method*s for non-virtual
34923478
// methods and for virtual, final methods.
34933479
//
3494-
// Special case: if the current class being redefined, then new_cp
3495-
// has already been attached to the_class and old_cp has already
3496-
// been added as a previous version. The new_cp doesn't have any
3497-
// cached references to old methods so it doesn't need to be
3498-
// updated. We can simply start with the previous version(s) in
3499-
// that case.
3500-
constantPoolHandle other_cp;
3480+
// Special case: if the current class is being redefined by the current
3481+
// VM_RedefineClasses operation, then new_cp has already been attached
3482+
// to the_class and old_cp has already been added as a previous version.
3483+
// The new_cp doesn't have any cached references to old methods so it
3484+
// doesn't need to be updated and we could optimize by skipping it.
3485+
// However, the current class can be marked as being redefined by another
3486+
// VM_RedefineClasses operation which has already executed its doit_prologue
3487+
// and needs cpcache method entries adjusted. For simplicity, the cpcache
3488+
// update is done unconditionally. It should result in doing nothing for
3489+
// classes being redefined by the current VM_RedefineClasses operation.
3490+
// Method entries in the previous version(s) are adjusted as well.
35013491
ConstantPoolCache* cp_cache;
35023492

3503-
if (!ik->is_being_redefined()) {
3504-
// this klass' constant pool cache may need adjustment
3505-
other_cp = constantPoolHandle(ik->constants());
3506-
cp_cache = other_cp->cache();
3507-
if (cp_cache != NULL) {
3508-
cp_cache->adjust_method_entries(&trace_name_printed);
3509-
}
3493+
// this klass' constant pool cache may need adjustment
3494+
ConstantPool* other_cp = ik->constants();
3495+
cp_cache = other_cp->cache();
3496+
if (cp_cache != NULL) {
3497+
cp_cache->adjust_method_entries(&trace_name_printed);
35103498
}
35113499

35123500
// the previous versions' constant pool caches may need adjustment
@@ -3947,9 +3935,8 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
39473935

39483936
InstanceKlass* the_class = get_ik(the_jclass);
39493937

3950-
// Set some flags to control and optimize adjusting method entries
3938+
// Set a flag to control and optimize adjusting method entries
39513939
_has_redefined_Object |= the_class == SystemDictionary::Object_klass();
3952-
_has_null_class_loader |= the_class->class_loader() == NULL;
39533940

39543941
// Remove all breakpoints in methods of this class
39553942
JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints();

0 commit comments

Comments
 (0)