diff -r caf5eb7dd4a7 -r 882756847a04 hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Aug 31 16:39:35 2012 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Sat Sep 01 13:25:18 2012 -0400 @@ -26,9 +26,12 @@ #include "classfile/systemDictionary.hpp" #include "classfile/verifier.hpp" #include "code/codeCache.hpp" +#include "compiler/compileBroker.hpp" #include "interpreter/oopMapCache.hpp" #include "interpreter/rewriter.hpp" #include "memory/gcLocker.hpp" +#include "memory/metadataFactory.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/universe.inline.hpp" #include "oops/fieldStreams.hpp" #include "oops/klassVtable.hpp" @@ -40,16 +43,16 @@ #include "utilities/bitMap.inline.hpp" -objArrayOop VM_RedefineClasses::_old_methods = NULL; -objArrayOop VM_RedefineClasses::_new_methods = NULL; -methodOop* VM_RedefineClasses::_matching_old_methods = NULL; -methodOop* VM_RedefineClasses::_matching_new_methods = NULL; -methodOop* VM_RedefineClasses::_deleted_methods = NULL; -methodOop* VM_RedefineClasses::_added_methods = NULL; +Array* VM_RedefineClasses::_old_methods = NULL; +Array* VM_RedefineClasses::_new_methods = NULL; +Method** VM_RedefineClasses::_matching_old_methods = NULL; +Method** VM_RedefineClasses::_matching_new_methods = NULL; +Method** VM_RedefineClasses::_deleted_methods = NULL; +Method** VM_RedefineClasses::_added_methods = NULL; int VM_RedefineClasses::_matching_methods_length = 0; int VM_RedefineClasses::_deleted_methods_length = 0; int VM_RedefineClasses::_added_methods_length = 0; -klassOop VM_RedefineClasses::_the_class_oop = NULL; +Klass* VM_RedefineClasses::_the_class_oop = NULL; VM_RedefineClasses::VM_RedefineClasses(jint class_count, @@ -93,6 +96,15 @@ // call chain it is required that the current thread is a Java thread. _res = load_new_class_versions(Thread::current()); if (_res != JVMTI_ERROR_NONE) { + // free any successfully created classes, since none are redefined + for (int i = 0; i < _class_count; i++) { + if (_scratch_classes[i] != NULL) { + ClassLoaderData* cld = _scratch_classes[i]->class_loader_data(); + // Free the memory for this class at class unloading time. Not before + // because CMS might think this is still live. + cld->add_to_deallocate_list((InstanceKlass*)_scratch_classes[i]); + } + } // Free os::malloc allocated memory in load_new_class_version. os::free(_scratch_classes); RC_TIMER_STOP(_timer_vm_op_prologue); @@ -103,6 +115,43 @@ return true; } +// Keep track of marked on-stack metadata so it can be cleared. +GrowableArray* _marked_objects = NULL; +NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) + +// Walk metadata on the stack and mark it so that redefinition doesn't delete +// it. Class unloading also walks the previous versions and might try to +// delete it, so this class is used by class unloading also. +MetadataOnStackMark::MetadataOnStackMark() { + assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + NOT_PRODUCT(_is_active = true;) + if (_marked_objects == NULL) { + _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray(1000, true); + } + Threads::metadata_do(Metadata::mark_on_stack); + CodeCache::alive_nmethods_do(nmethod::mark_on_stack); + CompileBroker::mark_on_stack(); +} + +MetadataOnStackMark::~MetadataOnStackMark() { + assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + // Unmark everything that was marked. Can't do the same walk because + // redefine classes messes up the code cache so the set of methods + // might not be the same. + for (int i = 0; i< _marked_objects->length(); i++) { + _marked_objects->at(i)->set_on_stack(false); + } + _marked_objects->clear(); // reuse growable array for next time. + NOT_PRODUCT(_is_active = false;) +} + +// Record which objects are marked so we can unmark the same objects. +void MetadataOnStackMark::record(Metadata* m) { + assert(_is_active, "metadata on stack marking is active"); + _marked_objects->push(m); +} + + void VM_RedefineClasses::doit() { Thread *thread = Thread::current(); @@ -111,7 +160,7 @@ // shared readwrite, private just in case we need to redefine // a shared class. We do the remap during the doit() phase of // the safepoint to be safer. - if (!CompactingPermGenGen::remap_shared_readonly_as_readwrite()) { + if (!MetaspaceShared::remap_shared_readonly_as_readwrite()) { RC_TRACE_WITH_THREAD(0x00000001, thread, ("failed to remap shared readonly space to readwrite, private")); _res = JVMTI_ERROR_INTERNAL; @@ -119,9 +168,21 @@ } } + // Mark methods seen on stack and everywhere else so old methods are not + // cleaned up if they're on the stack. + MetadataOnStackMark md_on_stack; + HandleMark hm(thread); // make sure any handles created are deleted + // before the stack walk again. + for (int i = 0; i < _class_count; i++) { redefine_single_class(_class_defs[i].klass, _scratch_classes[i], thread); + ClassLoaderData* cld = _scratch_classes[i]->class_loader_data(); + // Free the memory for this class at class unloading time. Not before + // because CMS might think this is still live. + cld->add_to_deallocate_list((InstanceKlass*)_scratch_classes[i]); + _scratch_classes[i] = NULL; } + // Disable any dependent concurrent compilations SystemDictionary::notice_modification(); @@ -136,7 +197,6 @@ void VM_RedefineClasses::doit_epilogue() { // Free os::malloc allocated memory. - // The memory allocated in redefine will be free'ed in next VM operation. os::free(_scratch_classes); if (RC_TRACE_ENABLED(0x00000004)) { @@ -160,7 +220,7 @@ if (java_lang_Class::is_primitive(klass_mirror)) { return false; } - klassOop the_class_oop = java_lang_Class::as_klassOop(klass_mirror); + Klass* the_class_oop = java_lang_Class::as_Klass(klass_mirror); // classes for arrays cannot be redefined if (the_class_oop == NULL || !Klass::cast(the_class_oop)->oop_is_instance()) { return false; @@ -215,7 +275,7 @@ case JVM_CONSTANT_Double: // fall through case JVM_CONSTANT_Long: { - constantPoolOopDesc::copy_entry_to(scratch_cp, scratch_i, *merge_cp_p, *merge_cp_length_p, + ConstantPool::copy_entry_to(scratch_cp, scratch_i, *merge_cp_p, *merge_cp_length_p, THREAD); if (scratch_i != *merge_cp_length_p) { @@ -232,15 +292,14 @@ case JVM_CONSTANT_Utf8: // fall through // This was an indirect CP entry, but it has been changed into - // an interned string so this entry can be directly appended. + // Symbol*s so this entry can be directly appended. case JVM_CONSTANT_String: // fall through // These were indirect CP entries, but they have been changed into // Symbol*s so these entries can be directly appended. case JVM_CONSTANT_UnresolvedClass: // fall through - case JVM_CONSTANT_UnresolvedString: { - constantPoolOopDesc::copy_entry_to(scratch_cp, scratch_i, *merge_cp_p, *merge_cp_length_p, + ConstantPool::copy_entry_to(scratch_cp, scratch_i, *merge_cp_p, *merge_cp_length_p, THREAD); if (scratch_i != *merge_cp_length_p) { @@ -467,8 +526,7 @@ // not be seen by itself. case JVM_CONSTANT_Invalid: // fall through - // At this stage, String or UnresolvedString could be here, but not - // StringIndex + // At this stage, String could be here, but not StringIndex case JVM_CONSTANT_StringIndex: // fall through // At this stage JVM_CONSTANT_UnresolvedClassInError should not be @@ -485,20 +543,23 @@ } // end append_entry() -void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class) { - typeArrayOop save; - - save = scratch_class->get_method_annotations_of(i); - scratch_class->set_method_annotations_of(i, scratch_class->get_method_annotations_of(j)); - scratch_class->set_method_annotations_of(j, save); - - save = scratch_class->get_method_parameter_annotations_of(i); - scratch_class->set_method_parameter_annotations_of(i, scratch_class->get_method_parameter_annotations_of(j)); - scratch_class->set_method_parameter_annotations_of(j, save); - - save = scratch_class->get_method_default_annotations_of(i); - scratch_class->set_method_default_annotations_of(i, scratch_class->get_method_default_annotations_of(j)); - scratch_class->set_method_default_annotations_of(j, save); +void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class, TRAPS) { + AnnotationArray* save; + + Annotations* sca = scratch_class->annotations(); + if (sca == NULL) return; + + save = sca->get_method_annotations_of(i); + sca->set_method_annotations_of(scratch_class, i, sca->get_method_annotations_of(j), CHECK); + sca->set_method_annotations_of(scratch_class, j, save, CHECK); + + save = sca->get_method_parameter_annotations_of(i); + sca->set_method_parameter_annotations_of(scratch_class, i, sca->get_method_parameter_annotations_of(j), CHECK); + sca->set_method_parameter_annotations_of(scratch_class, j, save, CHECK); + + save = sca->get_method_default_annotations_of(i); + sca->set_method_default_annotations_of(scratch_class, i, sca->get_method_default_annotations_of(j), CHECK); + sca->set_method_default_annotations_of(scratch_class, j, save, CHECK); } @@ -524,15 +585,15 @@ // technically a bit more difficult, and, more importantly, I am not sure at present that the // order of interfaces does not matter on the implementation level, i.e. that the VM does not // rely on it somewhere. - objArrayOop k_interfaces = the_class->local_interfaces(); - objArrayOop k_new_interfaces = scratch_class->local_interfaces(); + Array* k_interfaces = the_class->local_interfaces(); + Array* k_new_interfaces = scratch_class->local_interfaces(); int n_intfs = k_interfaces->length(); if (n_intfs != k_new_interfaces->length()) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; } for (i = 0; i < n_intfs; i++) { - if (Klass::cast((klassOop) k_interfaces->obj_at(i))->name() != - Klass::cast((klassOop) k_new_interfaces->obj_at(i))->name()) { + if (Klass::cast(k_interfaces->at(i))->name() != + Klass::cast(k_new_interfaces->at(i))->name()) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; } } @@ -591,23 +652,24 @@ // old methods in the same order as the old methods and places // new overloaded methods at the end of overloaded methods of // that name. The code for this order normalization is adapted - // from the algorithm used in instanceKlass::find_method(). + // from the algorithm used in InstanceKlass::find_method(). // Since we are swapping out of order entries as we find them, // we only have to search forward through the overloaded methods. // Methods which are added and have the same name as an existing // method (but different signature) will be put at the end of // the methods with that name, and the name mismatch code will // handle them. - objArrayHandle k_old_methods(the_class->methods()); - objArrayHandle k_new_methods(scratch_class->methods()); + Array* k_old_methods(the_class->methods()); + Array* k_new_methods(scratch_class->methods()); int n_old_methods = k_old_methods->length(); int n_new_methods = k_new_methods->length(); + Thread* thread = Thread::current(); int ni = 0; int oi = 0; while (true) { - methodOop k_old_method; - methodOop k_new_method; + Method* k_old_method; + Method* k_new_method; enum { matched, added, deleted, undetermined } method_was = undetermined; if (oi >= n_old_methods) { @@ -615,16 +677,16 @@ break; // we've looked at everything, done } // New method at the end - k_new_method = (methodOop) k_new_methods->obj_at(ni); + k_new_method = k_new_methods->at(ni); method_was = added; } else if (ni >= n_new_methods) { // Old method, at the end, is deleted - k_old_method = (methodOop) k_old_methods->obj_at(oi); + k_old_method = k_old_methods->at(oi); method_was = deleted; } else { // There are more methods in both the old and new lists - k_old_method = (methodOop) k_old_methods->obj_at(oi); - k_new_method = (methodOop) k_new_methods->obj_at(ni); + k_old_method = k_old_methods->at(oi); + k_new_method = k_new_methods->at(ni); if (k_old_method->name() != k_new_method->name()) { // Methods are sorted by method name, so a mismatch means added // or deleted @@ -641,7 +703,7 @@ // search forward through the new overloaded methods. int nj; // outside the loop for post-loop check for (nj = ni + 1; nj < n_new_methods; nj++) { - methodOop m = (methodOop)k_new_methods->obj_at(nj); + Method* m = k_new_methods->at(nj); if (k_old_method->name() != m->name()) { // reached another method name so no more overloaded methods method_was = deleted; @@ -649,8 +711,8 @@ } if (k_old_method->signature() == m->signature()) { // found a match so swap the methods - k_new_methods->obj_at_put(ni, m); - k_new_methods->obj_at_put(nj, k_new_method); + k_new_methods->at_put(ni, m); + k_new_methods->at_put(nj, k_new_method); k_new_method = m; method_was = matched; break; @@ -676,13 +738,16 @@ u2 new_num = k_new_method->method_idnum(); u2 old_num = k_old_method->method_idnum(); if (new_num != old_num) { - methodOop idnum_owner = scratch_class->method_with_idnum(old_num); + Method* idnum_owner = scratch_class->method_with_idnum(old_num); if (idnum_owner != NULL) { // There is already a method assigned this idnum -- switch them idnum_owner->set_method_idnum(new_num); } k_new_method->set_method_idnum(old_num); - swap_all_method_annotations(old_num, new_num, scratch_class); + swap_all_method_annotations(old_num, new_num, scratch_class, thread); + if (thread->has_pending_exception()) { + return JVMTI_ERROR_OUT_OF_MEMORY; + } } } RC_TRACE(0x00008000, ("Method matched: new: %s [%d] == old: %s [%d]", @@ -704,18 +769,21 @@ } { u2 num = the_class->next_method_idnum(); - if (num == constMethodOopDesc::UNSET_IDNUM) { + if (num == ConstMethod::UNSET_IDNUM) { // cannot add any more methods return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED; } u2 new_num = k_new_method->method_idnum(); - methodOop idnum_owner = scratch_class->method_with_idnum(num); + Method* idnum_owner = scratch_class->method_with_idnum(num); if (idnum_owner != NULL) { // There is already a method assigned this idnum -- switch them idnum_owner->set_method_idnum(new_num); } k_new_method->set_method_idnum(num); - swap_all_method_annotations(new_num, num, scratch_class); + swap_all_method_annotations(new_num, num, scratch_class, thread); + if (thread->has_pending_exception()) { + return JVMTI_ERROR_OUT_OF_MEMORY; + } } RC_TRACE(0x00008000, ("Method added: new: %s [%d]", k_new_method->name_and_sig_as_C_string(), ni)); @@ -799,42 +867,18 @@ } // end is_unresolved_class_mismatch() -// Returns true if the current mismatch is due to a resolved/unresolved -// string pair. Otherwise, returns false. -bool VM_RedefineClasses::is_unresolved_string_mismatch(constantPoolHandle cp1, - int index1, constantPoolHandle cp2, int index2) { - - jbyte t1 = cp1->tag_at(index1).value(); - if (t1 != JVM_CONSTANT_String && t1 != JVM_CONSTANT_UnresolvedString) { - return false; // wrong entry type; not our special case - } - - jbyte t2 = cp2->tag_at(index2).value(); - if (t2 != JVM_CONSTANT_String && t2 != JVM_CONSTANT_UnresolvedString) { - return false; // wrong entry type; not our special case - } - - if (t1 == t2) { - return false; // not a mismatch; not our special case - } - - char *s1 = cp1->string_at_noresolve(index1); - char *s2 = cp2->string_at_noresolve(index2); - if (strcmp(s1, s2) != 0) { - return false; // strings don't match; not our special case - } - - return true; // made it through the gauntlet; this is our special case -} // end is_unresolved_string_mismatch() - - jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) { + // For consistency allocate memory using os::malloc wrapper. - _scratch_classes = (instanceKlassHandle *) - os::malloc(sizeof(instanceKlassHandle) * _class_count, mtInternal); + _scratch_classes = (Klass**) + os::malloc(sizeof(Klass*) * _class_count, mtClass); if (_scratch_classes == NULL) { return JVMTI_ERROR_OUT_OF_MEMORY; } + // Zero initialize the _scratch_classes array. + for (int i = 0; i < _class_count; i++) { + _scratch_classes[i] = NULL; + } ResourceMark rm(THREAD); @@ -843,12 +887,17 @@ // should not happen since we're trying to do a RedefineClasses guarantee(state != NULL, "exiting thread calling load_new_class_versions"); for (int i = 0; i < _class_count; i++) { + // Create HandleMark so that any handles created while loading new class + // 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; } - klassOop the_class_oop = java_lang_Class::as_klassOop(mirror); + Klass* the_class_oop = java_lang_Class::as_Klass(mirror); instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop); Symbol* the_class_sym = the_class->name(); @@ -869,7 +918,7 @@ // load hook event. state->set_class_being_redefined(&the_class, _class_load_kind); - klassOop k = SystemDictionary::parse_stream(the_class_sym, + Klass* k = SystemDictionary::parse_stream(the_class_sym, the_class_loader, protection_domain, &st, @@ -881,8 +930,13 @@ instanceKlassHandle scratch_class (THREAD, k); + // Need to clean up allocated InstanceKlass if there's an error so assign + // the result here. Caller deallocates all the scratch classes in case of + // an error. + _scratch_classes[i] = k; + if (HAS_PENDING_EXCEPTION) { - Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); + Symbol* ex_name = PENDING_EXCEPTION->klass()->name(); // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("parse_stream exception: '%s'", ex_name->as_C_string())); @@ -908,7 +962,7 @@ if (!the_class->is_linked()) { the_class->link_class(THREAD); if (HAS_PENDING_EXCEPTION) { - Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); + Symbol* ex_name = PENDING_EXCEPTION->klass()->name(); // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("link_class exception: '%s'", ex_name->as_C_string())); @@ -946,7 +1000,7 @@ } if (HAS_PENDING_EXCEPTION) { - Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); + Symbol* ex_name = PENDING_EXCEPTION->klass()->name(); // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("verify_byte_codes exception: '%s'", ex_name->as_C_string())); @@ -972,7 +1026,7 @@ } if (HAS_PENDING_EXCEPTION) { - Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); + Symbol* ex_name = PENDING_EXCEPTION->klass()->name(); // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("verify_byte_codes post merge-CP exception: '%s'", @@ -992,7 +1046,7 @@ Rewriter::relocate_and_link(scratch_class, THREAD); } if (HAS_PENDING_EXCEPTION) { - Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); + Symbol* ex_name = PENDING_EXCEPTION->klass()->name(); CLEAR_PENDING_EXCEPTION; if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { return JVMTI_ERROR_OUT_OF_MEMORY; @@ -1001,8 +1055,6 @@ } } - _scratch_classes[i] = scratch_class; - // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark RC_TRACE_WITH_THREAD(0x00000001, THREAD, ("loaded name=%s (avail_mem=" UINT64_FORMAT "K)", @@ -1047,11 +1099,11 @@ int *merge_cp_length_p, TRAPS) { if (merge_cp_p == NULL) { - assert(false, "caller must provide scatch constantPool"); + assert(false, "caller must provide scratch constantPool"); return false; // robustness } if (merge_cp_length_p == NULL) { - assert(false, "caller must provide scatch CP length"); + assert(false, "caller must provide scratch CP length"); return false; // robustness } // Worst case we need old_cp->length() + scratch_cp()->length(), @@ -1070,7 +1122,7 @@ // Pass 0: // The old_cp is copied to *merge_cp_p; this means that any code // using old_cp does not have to change. This work looks like a - // perfect fit for constantPoolOop::copy_cp_to(), but we need to + // perfect fit for ConstantPool*::copy_cp_to(), but we need to // handle one special case: // - revert JVM_CONSTANT_Class to JVM_CONSTANT_UnresolvedClass // This will make verification happy. @@ -1095,13 +1147,13 @@ case JVM_CONSTANT_Long: // just copy the entry to *merge_cp_p, but double and long take // two constant pool entries - constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0); + ConstantPool::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0); old_i++; break; default: // just copy the entry to *merge_cp_p - constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0); + ConstantPool::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0); break; } } // end for each old_cp entry @@ -1151,13 +1203,6 @@ // class entries to unresolved class entries in *merge_cp_p, // we go with the unresolved class entry. continue; - } else if (is_unresolved_string_mismatch(scratch_cp, scratch_i, - *merge_cp_p, scratch_i)) { - // The mismatch in compare_entry_to() above is because of a - // resolved versus unresolved string entry at the same index - // with the same string value. We can live with whichever - // happens to be at scratch_i in *merge_cp_p. - continue; } int found_i = scratch_cp->find_matching_entry(scratch_i, *merge_cp_p, @@ -1233,6 +1278,23 @@ } // end merge_constant_pools() +// Scoped object to clean up the constant pool(s) created for merging +class MergeCPCleaner { + ClassLoaderData* _loader_data; + ConstantPool* _cp; + ConstantPool* _scratch_cp; + public: + MergeCPCleaner(ClassLoaderData* loader_data, ConstantPool* merge_cp) : + _loader_data(loader_data), _cp(merge_cp), _scratch_cp(NULL) {} + ~MergeCPCleaner() { + _loader_data->add_to_deallocate_list(_cp); + if (_scratch_cp != NULL) { + _loader_data->add_to_deallocate_list(_scratch_cp); + } + } + void add_scratch_cp(ConstantPool* scratch_cp) { _scratch_cp = scratch_cp; } +}; + // Merge constant pools between the_class and scratch_class and // potentially rewrite bytecodes in scratch_class to use the merged // constant pool. @@ -1243,19 +1305,35 @@ int merge_cp_length = the_class->constants()->length() + scratch_class->constants()->length(); - constantPoolHandle old_cp(THREAD, the_class->constants()); - constantPoolHandle scratch_cp(THREAD, scratch_class->constants()); - // Constant pools are not easily reused so we allocate a new one // each time. // merge_cp is created unsafe for concurrent GC processing. It // should be marked safe before discarding it. Even though // garbage, if it crosses a card boundary, it may be scanned // in order to find the start of the first complete object on the card. - constantPoolHandle merge_cp(THREAD, - oopFactory::new_constantPool(merge_cp_length, - oopDesc::IsUnsafeConc, - THREAD)); + ClassLoaderData* loader_data = the_class->class_loader_data(); + ConstantPool* merge_cp_oop = + ConstantPool::allocate(loader_data, + merge_cp_length, + THREAD); + MergeCPCleaner cp_cleaner(loader_data, merge_cp_oop); + + HandleMark hm(THREAD); // make sure handles are cleared before + // MergeCPCleaner clears out merge_cp_oop + constantPoolHandle merge_cp(THREAD, merge_cp_oop); + + // Get constants() from the old class because it could have been rewritten + // while we were at a safepoint allocating a new constant pool. + constantPoolHandle old_cp(THREAD, the_class->constants()); + constantPoolHandle scratch_cp(THREAD, scratch_class->constants()); + + // If the length changed, the class was redefined out from under us. Return + // an error. + if (merge_cp_length != the_class->constants()->length() + + scratch_class->constants()->length()) { + return JVMTI_ERROR_INTERNAL; + } + int orig_length = old_cp->orig_length(); if (orig_length == 0) { // This old_cp is an actual original constant pool. We save @@ -1298,8 +1376,7 @@ // rewriting so we can't use the old constant pool with the new // class. - merge_cp()->set_is_conc_safe(true); - merge_cp = constantPoolHandle(); // toss the merged constant pool + // toss the merged constant pool at return } else if (old_cp->length() < scratch_cp->length()) { // The old constant pool has fewer entries than the new constant // pool and the index map is empty. This means the new constant @@ -1308,8 +1385,7 @@ // rewriting so we can't use the new constant pool with the old // class. - merge_cp()->set_is_conc_safe(true); - merge_cp = constantPoolHandle(); // toss the merged constant pool + // toss the merged constant pool at return } else { // The old constant pool has more entries than the new constant // pool and the index map is empty. This means that both the old @@ -1317,13 +1393,11 @@ // pool. // Replace the new constant pool with a shrunken copy of the - // merged constant pool; the previous new constant pool will - // get GCed. - set_new_constant_pool(scratch_class, merge_cp, merge_cp_length, true, - THREAD); - // drop local ref to the merged constant pool - merge_cp()->set_is_conc_safe(true); - merge_cp = constantPoolHandle(); + // merged constant pool + set_new_constant_pool(loader_data, scratch_class, merge_cp, merge_cp_length, THREAD); + // The new constant pool replaces scratch_cp so have cleaner clean it up. + // It can't be cleaned up while there are handles to it. + cp_cleaner.add_scratch_cp(scratch_cp()); } } else { if (RC_TRACE_ENABLED(0x00040000)) { @@ -1350,12 +1424,11 @@ // merged constant pool so now the rewritten bytecodes have // valid references; the previous new constant pool will get // GCed. - set_new_constant_pool(scratch_class, merge_cp, merge_cp_length, true, - THREAD); - merge_cp()->set_is_conc_safe(true); + set_new_constant_pool(loader_data, scratch_class, merge_cp, merge_cp_length, THREAD); + // The new constant pool replaces scratch_cp so have cleaner clean it up. + // It can't be cleaned up while there are handles to it. + cp_cleaner.add_scratch_cp(scratch_cp()); } - assert(old_cp()->is_conc_safe(), "Just checking"); - assert(scratch_cp()->is_conc_safe(), "Just checking"); return JVMTI_ERROR_NONE; } // end merge_cp_and_rewrite() @@ -1411,21 +1484,21 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods( instanceKlassHandle scratch_class, TRAPS) { - objArrayHandle methods(THREAD, scratch_class->methods()); - - if (methods.is_null() || methods->length() == 0) { + Array* methods = scratch_class->methods(); + + if (methods == NULL || methods->length() == 0) { // no methods so nothing to do return true; } // rewrite constant pool references in the methods: for (int i = methods->length() - 1; i >= 0; i--) { - methodHandle method(THREAD, (methodOop)methods->obj_at(i)); + methodHandle method(THREAD, methods->at(i)); methodHandle new_method; rewrite_cp_refs_in_method(method, &new_method, CHECK_false); if (!new_method.is_null()) { // the method has been replaced so save the new method version - methods->obj_at_put(i, new_method()); + methods->at_put(i, new_method()); } } @@ -1441,7 +1514,7 @@ *new_method_p = methodHandle(); // default is no new method // We cache a pointer to the bytecodes here in code_base. If GC - // moves the methodOop, then the bytecodes will also move which + // moves the Method*, then the bytecodes will also move which // will likely cause a crash. We create a No_Safepoint_Verifier // object to detect whether we pass a possible safepoint in this // code block. @@ -1570,9 +1643,8 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_class_annotations( instanceKlassHandle scratch_class, TRAPS) { - typeArrayHandle class_annotations(THREAD, - scratch_class->class_annotations()); - if (class_annotations.is_null() || class_annotations->length() == 0) { + AnnotationArray* class_annotations = scratch_class->class_annotations(); + if (class_annotations == NULL || class_annotations->length() == 0) { // no class_annotations so nothing to do return true; } @@ -1596,7 +1668,7 @@ // } // bool VM_RedefineClasses::rewrite_cp_refs_in_annotations_typeArray( - typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) { + AnnotationArray* annotations_typeArray, int &byte_i_ref, TRAPS) { if ((byte_i_ref + 2) > annotations_typeArray->length()) { // not enough room for num_annotations field @@ -1606,7 +1678,7 @@ } u2 num_annotations = Bytes::get_Java_u2((address) - annotations_typeArray->byte_at_addr(byte_i_ref)); + annotations_typeArray->adr_at(byte_i_ref)); byte_i_ref += 2; RC_TRACE_WITH_THREAD(0x02000000, THREAD, @@ -1642,7 +1714,7 @@ // } // bool VM_RedefineClasses::rewrite_cp_refs_in_annotation_struct( - typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) { + AnnotationArray* annotations_typeArray, int &byte_i_ref, TRAPS) { if ((byte_i_ref + 2 + 2) > annotations_typeArray->length()) { // not enough room for smallest annotation_struct RC_TRACE_WITH_THREAD(0x02000000, THREAD, @@ -1654,8 +1726,7 @@ byte_i_ref, "mapped old type_index=%d", THREAD); u2 num_element_value_pairs = Bytes::get_Java_u2((address) - annotations_typeArray->byte_at_addr( - byte_i_ref)); + annotations_typeArray->adr_at(byte_i_ref)); byte_i_ref += 2; RC_TRACE_WITH_THREAD(0x02000000, THREAD, @@ -1700,11 +1771,11 @@ // pool reference if a rewrite was not needed or the new constant // pool reference if a rewrite was needed. u2 VM_RedefineClasses::rewrite_cp_ref_in_annotation_data( - typeArrayHandle annotations_typeArray, int &byte_i_ref, + AnnotationArray* annotations_typeArray, int &byte_i_ref, const char * trace_mesg, TRAPS) { address cp_index_addr = (address) - annotations_typeArray->byte_at_addr(byte_i_ref); + annotations_typeArray->adr_at(byte_i_ref); u2 old_cp_index = Bytes::get_Java_u2(cp_index_addr); u2 new_cp_index = find_new_index(old_cp_index); if (new_cp_index != 0) { @@ -1739,7 +1810,7 @@ // } // bool VM_RedefineClasses::rewrite_cp_refs_in_element_value( - typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) { + AnnotationArray* annotations_typeArray, int &byte_i_ref, TRAPS) { if ((byte_i_ref + 1) > annotations_typeArray->length()) { // not enough room for a tag let alone the rest of an element_value @@ -1748,7 +1819,7 @@ return false; } - u1 tag = annotations_typeArray->byte_at(byte_i_ref); + u1 tag = annotations_typeArray->at(byte_i_ref); byte_i_ref++; RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("tag='%c'", tag)); @@ -1850,7 +1921,7 @@ // For the above tag value, value.array_value is the right union // field. This is an array of nested element_value. u2 num_values = Bytes::get_Java_u2((address) - annotations_typeArray->byte_at_addr(byte_i_ref)); + annotations_typeArray->adr_at(byte_i_ref)); byte_i_ref += 2; RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("num_values=%d", num_values)); @@ -1880,10 +1951,12 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_fields_annotations( instanceKlassHandle scratch_class, TRAPS) { - objArrayHandle fields_annotations(THREAD, - scratch_class->fields_annotations()); - - if (fields_annotations.is_null() || fields_annotations->length() == 0) { + Annotations* sca = scratch_class->annotations(); + if (sca == NULL) return true; + + Array* fields_annotations = sca->fields_annotations(); + + if (fields_annotations == NULL || fields_annotations->length() == 0) { // no fields_annotations so nothing to do return true; } @@ -1892,9 +1965,8 @@ ("fields_annotations length=%d", fields_annotations->length())); for (int i = 0; i < fields_annotations->length(); i++) { - typeArrayHandle field_annotations(THREAD, - (typeArrayOop)fields_annotations->obj_at(i)); - if (field_annotations.is_null() || field_annotations->length() == 0) { + AnnotationArray* field_annotations = fields_annotations->at(i); + if (field_annotations == NULL || field_annotations->length() == 0) { // this field does not have any annotations so skip it continue; } @@ -1917,10 +1989,12 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_annotations( instanceKlassHandle scratch_class, TRAPS) { - objArrayHandle methods_annotations(THREAD, - scratch_class->methods_annotations()); - - if (methods_annotations.is_null() || methods_annotations->length() == 0) { + Annotations* sca = scratch_class->annotations(); + if (sca == NULL) return true; + + Array* methods_annotations = sca->methods_annotations(); + + if (methods_annotations == NULL || methods_annotations->length() == 0) { // no methods_annotations so nothing to do return true; } @@ -1929,9 +2003,8 @@ ("methods_annotations length=%d", methods_annotations->length())); for (int i = 0; i < methods_annotations->length(); i++) { - typeArrayHandle method_annotations(THREAD, - (typeArrayOop)methods_annotations->obj_at(i)); - if (method_annotations.is_null() || method_annotations->length() == 0) { + AnnotationArray* method_annotations = methods_annotations->at(i); + if (method_annotations == NULL || method_annotations->length() == 0) { // this method does not have any annotations so skip it continue; } @@ -1966,10 +2039,13 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_parameter_annotations( instanceKlassHandle scratch_class, TRAPS) { - objArrayHandle methods_parameter_annotations(THREAD, - scratch_class->methods_parameter_annotations()); - - if (methods_parameter_annotations.is_null() + Annotations* sca = scratch_class->annotations(); + if (sca == NULL) return true; + + Array* methods_parameter_annotations = + sca->methods_parameter_annotations(); + + if (methods_parameter_annotations == NULL || methods_parameter_annotations->length() == 0) { // no methods_parameter_annotations so nothing to do return true; @@ -1980,9 +2056,8 @@ methods_parameter_annotations->length())); for (int i = 0; i < methods_parameter_annotations->length(); i++) { - typeArrayHandle method_parameter_annotations(THREAD, - (typeArrayOop)methods_parameter_annotations->obj_at(i)); - if (method_parameter_annotations.is_null() + AnnotationArray* method_parameter_annotations = methods_parameter_annotations->at(i); + if (method_parameter_annotations == NULL || method_parameter_annotations->length() == 0) { // this method does not have any parameter annotations so skip it continue; @@ -1997,7 +2072,7 @@ int byte_i = 0; // byte index into method_parameter_annotations - u1 num_parameters = method_parameter_annotations->byte_at(byte_i); + u1 num_parameters = method_parameter_annotations->at(byte_i); byte_i++; RC_TRACE_WITH_THREAD(0x02000000, THREAD, @@ -2031,10 +2106,13 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_default_annotations( instanceKlassHandle scratch_class, TRAPS) { - objArrayHandle methods_default_annotations(THREAD, - scratch_class->methods_default_annotations()); - - if (methods_default_annotations.is_null() + Annotations* sca = scratch_class->annotations(); + if (sca == NULL) return true; + + Array* methods_default_annotations = + sca->methods_default_annotations(); + + if (methods_default_annotations == NULL || methods_default_annotations->length() == 0) { // no methods_default_annotations so nothing to do return true; @@ -2045,9 +2123,8 @@ methods_default_annotations->length())); for (int i = 0; i < methods_default_annotations->length(); i++) { - typeArrayHandle method_default_annotations(THREAD, - (typeArrayOop)methods_default_annotations->obj_at(i)); - if (method_default_annotations.is_null() + AnnotationArray* method_default_annotations = methods_default_annotations->at(i); + if (method_default_annotations == NULL || method_default_annotations->length() == 0) { // this method does not have any default annotations so skip it continue; @@ -2086,8 +2163,8 @@ return; } - typeArrayOop stackmap_data = method->stackmap_data(); - address stackmap_p = (address)stackmap_data->byte_at_addr(0); + AnnotationArray* stackmap_data = method->stackmap_data(); + address stackmap_p = (address)stackmap_data->adr_at(0); address stackmap_end = stackmap_p + stackmap_data->length(); assert(stackmap_p + 2 <= stackmap_end, "no room for number_of_entries"); @@ -2335,17 +2412,16 @@ // are copied from scratch_cp to a smaller constant pool and the // smaller constant pool is associated with scratch_class. void VM_RedefineClasses::set_new_constant_pool( + ClassLoaderData* loader_data, instanceKlassHandle scratch_class, constantPoolHandle scratch_cp, - int scratch_cp_length, bool shrink, TRAPS) { - assert(!shrink || scratch_cp->length() >= scratch_cp_length, "sanity check"); - - if (shrink) { + int scratch_cp_length, TRAPS) { + assert(scratch_cp->length() >= scratch_cp_length, "sanity check"); + // scratch_cp is a merged constant pool and has enough space for a // worst case merge situation. We want to associate the minimum // sized constant pool with the klass to save space. constantPoolHandle smaller_cp(THREAD, - oopFactory::new_constantPool(scratch_cp_length, - oopDesc::IsUnsafeConc, + ConstantPool::allocate(loader_data, scratch_cp_length, THREAD)); // preserve orig_length() value in the smaller copy int orig_length = scratch_cp->orig_length(); @@ -2353,8 +2429,6 @@ smaller_cp->set_orig_length(orig_length); scratch_cp->copy_cp_to(1, scratch_cp_length - 1, smaller_cp, 1, THREAD); scratch_cp = smaller_cp; - smaller_cp()->set_is_conc_safe(true); - } // attach new constant pool to klass scratch_cp->set_pool_holder(scratch_class()); @@ -2430,9 +2504,9 @@ // Attach each method in klass to the new constant pool and update // to use new constant pool indices as needed: - objArrayHandle methods(THREAD, scratch_class->methods()); + Array* methods = scratch_class->methods(); for (i = methods->length() - 1; i >= 0; i--) { - methodHandle method(THREAD, (methodOop)methods->obj_at(i)); + methodHandle method(THREAD, methods->at(i)); method->set_constants(scratch_cp()); int new_index = find_new_index(method->name_index()); @@ -2528,10 +2602,18 @@ rewrite_cp_refs_in_stack_map_table(method, THREAD); } // end for each method - assert(scratch_cp()->is_conc_safe(), "Just checking"); } // end set_new_constant_pool() +void VM_RedefineClasses::adjust_array_vtable(Klass* k_oop) { + arrayKlass* ak = arrayKlass::cast(k_oop); + bool trace_name_printed = false; + ak->vtable()->adjust_method_entries(_matching_old_methods, + _matching_new_methods, + _matching_methods_length, + &trace_name_printed); +} + // Unevolving classes may point to methods of the_class directly // from their constant pool caches, itables, and/or vtables. We // use the SystemDictionary::classes_do() facility and this helper @@ -2539,12 +2621,13 @@ // // Note: We currently don't support updating the vtable in // arrayKlassOops. See Open Issues in jvmtiRedefineClasses.hpp. -void VM_RedefineClasses::adjust_cpool_cache_and_vtable(klassOop k_oop, - oop initiating_loader, TRAPS) { - Klass *k = k_oop->klass_part(); +void VM_RedefineClasses::adjust_cpool_cache_and_vtable(Klass* k_oop, + ClassLoaderData* initiating_loader, + TRAPS) { + Klass *k = k_oop; if (k->oop_is_instance()) { HandleMark hm(THREAD); - instanceKlass *ik = (instanceKlass *) k; + InstanceKlass *ik = (InstanceKlass *) k; // HotSpot specific optimization! HotSpot does not currently // support delegation from the bootstrap class loader to a @@ -2559,11 +2642,17 @@ // loader as its defining class loader, then we can skip all // classes loaded by the bootstrap class loader. bool is_user_defined = - instanceKlass::cast(_the_class_oop)->class_loader() != NULL; + InstanceKlass::cast(_the_class_oop)->class_loader() != NULL; if (is_user_defined && ik->class_loader() == NULL) { return; } + // If the class being redefined is java.lang.Object, we need to fix all + // array class vtables also + if (_the_class_oop == SystemDictionary::Object_klass()) { + ik->array_klasses_do(adjust_array_vtable); + } + // This is a very busy routine. We don't want too much tracing // printed out. bool trace_name_printed = false; @@ -2577,9 +2666,9 @@ // Fix the vtable embedded in the_class and subclasses of the_class, // if one exists. We discard scratch_class and we don't keep an - // instanceKlass around to hold obsolete methods so we don't have - // any other instanceKlass embedded vtables to update. The vtable - // holds the methodOops for virtual (but not final) methods. + // InstanceKlass around to hold obsolete methods so we don't have + // any other InstanceKlass embedded vtables to update. The vtable + // holds the Method*s for virtual (but not final) methods. if (ik->vtable_length() > 0 && ik->is_subtype_of(_the_class_oop)) { // ik->vtable() creates a wrapper object; rm cleans it up ResourceMark rm(THREAD); @@ -2593,8 +2682,8 @@ // interface or if the current class is a subclass of the_class, then // we potentially have to fix the itable. If we are redefining an // interface, then we have to call adjust_method_entries() for - // every instanceKlass that has an itable since there isn't a - // subclass relationship between an interface and an instanceKlass. + // every InstanceKlass that has an itable since there isn't a + // subclass relationship between an interface and an InstanceKlass. if (ik->itable_length() > 0 && (Klass::cast(_the_class_oop)->is_interface() || ik->is_subclass_of(_the_class_oop))) { // ik->itable() creates a wrapper object; rm cleans it up @@ -2609,7 +2698,7 @@ // methods in the_class. We have to update method information in // other_cp's cache. If other_cp has a previous version, then we // have to repeat the process for each previous version. The - // constant pool cache holds the methodOops for non-virtual + // constant pool cache holds the Method*s for non-virtual // methods and for virtual, final methods. // // Special case: if the current class is the_class, then new_cp @@ -2619,7 +2708,7 @@ // updated. We can simply start with the previous version(s) in // that case. constantPoolHandle other_cp; - constantPoolCacheOop cp_cache; + ConstantPoolCache* cp_cache; if (k_oop != _the_class_oop) { // this klass' constant pool cache may need adjustment @@ -2659,13 +2748,13 @@ void VM_RedefineClasses::update_jmethod_ids() { for (int j = 0; j < _matching_methods_length; ++j) { - methodOop old_method = _matching_old_methods[j]; + Method* old_method = _matching_old_methods[j]; jmethodID jmid = old_method->find_jmethod_id_or_null(); if (jmid != NULL) { // There is a jmethodID, change it to point to the new method methodHandle new_method_h(_matching_new_methods[j]); - JNIHandles::change_method_associated_with_jmethod_id(jmid, new_method_h); - assert(JNIHandles::resolve_jmethod_id(jmid) == _matching_new_methods[j], + Method::change_method_associated_with_jmethod_id(jmid, new_method_h()); + assert(Method::resolve_jmethod_id(jmid) == _matching_new_methods[j], "should be replaced"); } } @@ -2677,14 +2766,13 @@ int obsolete_count = 0; int old_index = 0; for (int j = 0; j < _matching_methods_length; ++j, ++old_index) { - methodOop old_method = _matching_old_methods[j]; - methodOop new_method = _matching_new_methods[j]; - methodOop old_array_method; + Method* old_method = _matching_old_methods[j]; + Method* new_method = _matching_new_methods[j]; + Method* old_array_method; // Maintain an old_index into the _old_methods array by skipping // deleted methods - while ((old_array_method = (methodOop) _old_methods->obj_at(old_index)) - != old_method) { + while ((old_array_method = _old_methods->at(old_index)) != old_method) { ++old_index; } @@ -2718,29 +2806,29 @@ // methods by new methods will save us space except for those // (hopefully few) old methods that are still executing. // - // A method refers to a constMethodOop and this presents another - // possible avenue to space savings. The constMethodOop in the + // A method refers to a ConstMethod* and this presents another + // possible avenue to space savings. The ConstMethod* in the // new method contains possibly new attributes (LNT, LVT, etc). // At first glance, it seems possible to save space by replacing - // the constMethodOop in the old method with the constMethodOop + // the ConstMethod* in the old method with the ConstMethod* // from the new method. The old and new methods would share the - // same constMethodOop and we would save the space occupied by - // the old constMethodOop. However, the constMethodOop contains + // same ConstMethod* and we would save the space occupied by + // the old ConstMethod*. However, the ConstMethod* contains // a back reference to the containing method. Sharing the - // constMethodOop between two methods could lead to confusion in + // ConstMethod* between two methods could lead to confusion in // the code that uses the back reference. This would lead to // brittle code that could be broken in non-obvious ways now or // in the future. // - // Another possibility is to copy the constMethodOop from the new + // Another possibility is to copy the ConstMethod* from the new // method to the old method and then overwrite the new method with - // the old method. Since the constMethodOop contains the bytecodes + // the old method. Since the ConstMethod* contains the bytecodes // for the method embedded in the oop, this option would change // the bytecodes out from under any threads executing the old // method and make the thread's bcp invalid. Since EMCP requires // that the bytecodes be the same modulo constant pool indices, it // is straight forward to compute the correct new bcp in the new - // constMethodOop from the old bcp in the old constMethodOop. The + // ConstMethod* from the old bcp in the old ConstMethod*. The // time consuming part would be searching all the frames in all // of the threads to find all of the calls to the old method. // @@ -2766,8 +2854,8 @@ obsolete_count++; // obsolete methods need a unique idnum - u2 num = instanceKlass::cast(_the_class_oop)->next_method_idnum(); - if (num != constMethodOopDesc::UNSET_IDNUM) { + u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum(); + if (num != ConstMethod::UNSET_IDNUM) { // u2 old_num = old_method->method_idnum(); old_method->set_method_idnum(num); // TO DO: attach obsolete annotations to obsolete method's new idnum @@ -2782,7 +2870,7 @@ old_method->set_is_old(); } for (int i = 0; i < _deleted_methods_length; ++i) { - methodOop old_method = _deleted_methods[i]; + Method* old_method = _deleted_methods[i]; assert(old_method->vtable_index() < 0, "cannot delete methods with vtable entries");; @@ -2837,11 +2925,11 @@ // (1) without the prefix. // (2) with the prefix. // where 'prefix' is the prefix at that 'depth' (first prefix, second prefix,...) - methodOop search_prefix_name_space(int depth, char* name_str, size_t name_len, + Method* search_prefix_name_space(int depth, char* name_str, size_t name_len, Symbol* signature) { TempNewSymbol name_symbol = SymbolTable::probe(name_str, (int)name_len); if (name_symbol != NULL) { - methodOop method = Klass::cast(the_class())->lookup_method(name_symbol, signature); + Method* method = Klass::cast(the_class())->lookup_method(name_symbol, signature); if (method != NULL) { // Even if prefixed, intermediate methods must exist. if (method->is_native()) { @@ -2877,7 +2965,7 @@ } // Return the method name with old prefixes stripped away. - char* method_name_without_prefixes(methodOop method) { + char* method_name_without_prefixes(Method* method) { Symbol* name = method->name(); char* name_str = name->as_utf8(); @@ -2894,7 +2982,7 @@ // Strip any prefixes off the old native method, then try to find a // (possibly prefixed) new native that matches it. - methodOop strip_and_search_for_new_native(methodOop method) { + Method* strip_and_search_for_new_native(Method* method) { ResourceMark rm; char* name_str = method_name_without_prefixes(method); return search_prefix_name_space(0, name_str, strlen(name_str), @@ -2912,18 +3000,18 @@ } // Attempt to transfer any of the old or deleted methods that are native - void transfer_registrations(methodOop* old_methods, int methods_length) { + void transfer_registrations(Method** old_methods, int methods_length) { for (int j = 0; j < methods_length; j++) { - methodOop old_method = old_methods[j]; + Method* old_method = old_methods[j]; if (old_method->is_native() && old_method->has_native_function()) { - methodOop new_method = strip_and_search_for_new_native(old_method); + Method* new_method = strip_and_search_for_new_native(old_method); if (new_method != NULL) { // Actually set the native function in the new method. // Redefine does not send events (except CFLH), certainly not this // behind the scenes re-registration. new_method->set_native_function(old_method->native_function(), - !methodOopDesc::native_bind_event_is_interesting); + !Method::native_bind_event_is_interesting); } } } @@ -2977,13 +3065,13 @@ } void VM_RedefineClasses::compute_added_deleted_matching_methods() { - methodOop old_method; - methodOop new_method; - - _matching_old_methods = NEW_RESOURCE_ARRAY(methodOop, _old_methods->length()); - _matching_new_methods = NEW_RESOURCE_ARRAY(methodOop, _old_methods->length()); - _added_methods = NEW_RESOURCE_ARRAY(methodOop, _new_methods->length()); - _deleted_methods = NEW_RESOURCE_ARRAY(methodOop, _old_methods->length()); + Method* old_method; + Method* new_method; + + _matching_old_methods = NEW_RESOURCE_ARRAY(Method*, _old_methods->length()); + _matching_new_methods = NEW_RESOURCE_ARRAY(Method*, _old_methods->length()); + _added_methods = NEW_RESOURCE_ARRAY(Method*, _new_methods->length()); + _deleted_methods = NEW_RESOURCE_ARRAY(Method*, _old_methods->length()); _matching_methods_length = 0; _deleted_methods_length = 0; @@ -2997,17 +3085,17 @@ break; // we've looked at everything, done } // New method at the end - new_method = (methodOop) _new_methods->obj_at(nj); + new_method = _new_methods->at(nj); _added_methods[_added_methods_length++] = new_method; ++nj; } else if (nj >= _new_methods->length()) { // Old method, at the end, is deleted - old_method = (methodOop) _old_methods->obj_at(oj); + old_method = _old_methods->at(oj); _deleted_methods[_deleted_methods_length++] = old_method; ++oj; } else { - old_method = (methodOop) _old_methods->obj_at(oj); - new_method = (methodOop) _new_methods->obj_at(nj); + old_method = _old_methods->at(oj); + new_method = _new_methods->at(nj); if (old_method->name() == new_method->name()) { if (old_method->signature() == new_method->signature()) { _matching_old_methods[_matching_methods_length ] = old_method; @@ -3052,12 +3140,15 @@ // that we would like to pass to the helper method are saved in // static global fields in the VM operation. void VM_RedefineClasses::redefine_single_class(jclass the_jclass, - instanceKlassHandle scratch_class, TRAPS) { - + Klass* scratch_class_oop, TRAPS) { + + HandleMark hm(THREAD); // make sure handles from this call are freed RC_TIMER_START(_timer_rsc_phase1); + instanceKlassHandle scratch_class(scratch_class_oop); + oop the_class_mirror = JNIHandles::resolve_non_null(the_jclass); - klassOop the_class_oop = java_lang_Class::as_klassOop(the_class_mirror); + Klass* the_class_oop = java_lang_Class::as_Klass(the_class_mirror); instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop); #ifndef JVMTI_KERNEL @@ -3105,13 +3196,13 @@ // done here since we are past the bytecode verification and // constant pool optimization phases. for (int i = _old_methods->length() - 1; i >= 0; i--) { - methodOop method = (methodOop)_old_methods->obj_at(i); + Method* method = _old_methods->at(i); method->set_constants(scratch_class->constants()); } { // walk all previous versions of the klass - instanceKlass *ik = (instanceKlass *)the_class()->klass_part(); + InstanceKlass *ik = (InstanceKlass *)the_class(); PreviousVersionWalker pvw(ik); instanceKlassHandle ikh; do { @@ -3124,9 +3215,9 @@ // Attach each method in the previous version of klass to the // new constant pool - objArrayOop prev_methods = ik->methods(); + Array* prev_methods = ik->methods(); for (int i = prev_methods->length() - 1; i >= 0; i--) { - methodOop method = (methodOop)prev_methods->obj_at(i); + Method* method = prev_methods->at(i); method->set_constants(scratch_class->constants()); } } @@ -3139,7 +3230,7 @@ scratch_class->set_methods(_old_methods); // To prevent potential GCing of the old methods, // and to be able to undo operation easily. - constantPoolOop old_constants = the_class->constants(); + ConstantPool* old_constants = the_class->constants(); the_class->set_constants(scratch_class->constants()); scratch_class->set_constants(old_constants); // See the previous comment. #if 0 @@ -3166,7 +3257,7 @@ // Miranda methods are a little more complicated. A miranda method is // provided by an interface when the class implementing the interface // does not provide its own method. These interfaces are implemented - // internally as an instanceKlass. These special instanceKlasses + // internally as an InstanceKlass. These special instanceKlasses // share the constant pool of the class that "implements" the // interface. By sharing the constant pool, the method holder of a // miranda method is the class that "implements" the interface. In a @@ -3205,7 +3296,7 @@ #endif // Replace inner_classes - typeArrayOop old_inner_classes = the_class->inner_classes(); + Array* old_inner_classes = the_class->inner_classes(); the_class->set_inner_classes(scratch_class->inner_classes()); scratch_class->set_inner_classes(old_inner_classes); @@ -3247,34 +3338,10 @@ the_class->set_access_flags(flags); } - // Replace class annotation fields values - typeArrayOop old_class_annotations = the_class->class_annotations(); - the_class->set_class_annotations(scratch_class->class_annotations()); - scratch_class->set_class_annotations(old_class_annotations); - - // Replace fields annotation fields values - objArrayOop old_fields_annotations = the_class->fields_annotations(); - the_class->set_fields_annotations(scratch_class->fields_annotations()); - scratch_class->set_fields_annotations(old_fields_annotations); - - // Replace methods annotation fields values - objArrayOop old_methods_annotations = the_class->methods_annotations(); - the_class->set_methods_annotations(scratch_class->methods_annotations()); - scratch_class->set_methods_annotations(old_methods_annotations); - - // Replace methods parameter annotation fields values - objArrayOop old_methods_parameter_annotations = - the_class->methods_parameter_annotations(); - the_class->set_methods_parameter_annotations( - scratch_class->methods_parameter_annotations()); - scratch_class->set_methods_parameter_annotations(old_methods_parameter_annotations); - - // Replace methods default annotation fields values - objArrayOop old_methods_default_annotations = - the_class->methods_default_annotations(); - the_class->set_methods_default_annotations( - scratch_class->methods_default_annotations()); - scratch_class->set_methods_default_annotations(old_methods_default_annotations); + // Replace annotation fields value + Annotations* old_annotations = the_class->annotations(); + the_class->set_annotations(scratch_class->annotations()); + scratch_class->set_annotations(old_annotations); // Replace minor version number of class file u2 old_minor_version = the_class->minor_version(); @@ -3305,6 +3372,9 @@ // that reference methods of the evolved class. SystemDictionary::classes_do(adjust_cpool_cache_and_vtable, THREAD); + // Fix Resolution Error table also to remove old constant pools + SystemDictionary::delete_resolution_error(old_constants); + if (the_class->oop_map_cache() != NULL) { // Flush references to any obsolete methods from the oop map cache // so that obsolete methods are not pinned. @@ -3313,7 +3383,7 @@ // increment the classRedefinedCount field in the_class and in any // direct and indirect subclasses of the_class - increment_class_counter((instanceKlass *)the_class()->klass_part(), THREAD); + increment_class_counter((InstanceKlass *)the_class(), THREAD); // RC_TRACE macro has an embedded ResourceMark RC_TRACE_WITH_THREAD(0x00000001, THREAD, @@ -3326,11 +3396,11 @@ } // end redefine_single_class() -// Increment the classRedefinedCount field in the specific instanceKlass +// Increment the classRedefinedCount field in the specific InstanceKlass // and in all direct and indirect subclasses. -void VM_RedefineClasses::increment_class_counter(instanceKlass *ik, TRAPS) { +void VM_RedefineClasses::increment_class_counter(InstanceKlass *ik, TRAPS) { oop class_mirror = ik->java_mirror(); - klassOop class_oop = java_lang_Class::as_klassOop(class_mirror); + Klass* class_oop = java_lang_Class::as_Klass(class_mirror); int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1; java_lang_Class::set_classRedefinedCount(class_mirror, new_count); @@ -3344,7 +3414,7 @@ subk = subk->next_sibling()) { if (subk->oop_is_instance()) { // Only update instanceKlasses - instanceKlass *subik = (instanceKlass*)subk; + InstanceKlass *subik = (InstanceKlass*)subk; // recursively do subclasses of the current subclass increment_class_counter(subik, THREAD); } @@ -3352,22 +3422,36 @@ } #ifndef PRODUCT -void VM_RedefineClasses::check_class(klassOop k_oop, - oop initiating_loader, TRAPS) { - Klass *k = k_oop->klass_part(); +void VM_RedefineClasses::check_class(Klass* k_oop, + ClassLoaderData* initiating_loader, + TRAPS) { + Klass *k = k_oop; if (k->oop_is_instance()) { HandleMark hm(THREAD); - instanceKlass *ik = (instanceKlass *) k; + InstanceKlass *ik = (InstanceKlass *) k; if (ik->vtable_length() > 0) { ResourceMark rm(THREAD); if (!ik->vtable()->check_no_old_entries()) { tty->print_cr("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); ik->vtable()->dump_vtable(); - dump_methods(); assert(false, "OLD method found"); } } + if (ik->itable_length() > 0) { + ResourceMark rm(THREAD); + if (!ik->itable()->check_no_old_entries()) { + tty->print_cr("klassItable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); + assert(false, "OLD method found"); + } + } + // Check that the constant pool cache has no deleted entries. + if (ik->constants() != NULL && + ik->constants()->cache() != NULL && + !ik->constants()->cache()->check_no_old_entries()) { + tty->print_cr("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); + assert(false, "OLD method found"); + } } } @@ -3375,7 +3459,7 @@ int j; tty->print_cr("_old_methods --"); for (j = 0; j < _old_methods->length(); ++j) { - methodOop m = (methodOop) _old_methods->obj_at(j); + Method* m = _old_methods->at(j); tty->print("%4d (%5d) ", j, m->vtable_index()); m->access_flags().print_on(tty); tty->print(" -- "); @@ -3384,7 +3468,7 @@ } tty->print_cr("_new_methods --"); for (j = 0; j < _new_methods->length(); ++j) { - methodOop m = (methodOop) _new_methods->obj_at(j); + Method* m = _new_methods->at(j); tty->print("%4d (%5d) ", j, m->vtable_index()); m->access_flags().print_on(tty); tty->print(" -- "); @@ -3393,7 +3477,7 @@ } tty->print_cr("_matching_(old/new)_methods --"); for (j = 0; j < _matching_methods_length; ++j) { - methodOop m = _matching_old_methods[j]; + Method* m = _matching_old_methods[j]; tty->print("%4d (%5d) ", j, m->vtable_index()); m->access_flags().print_on(tty); tty->print(" -- "); @@ -3406,7 +3490,7 @@ } tty->print_cr("_deleted_methods --"); for (j = 0; j < _deleted_methods_length; ++j) { - methodOop m = _deleted_methods[j]; + Method* m = _deleted_methods[j]; tty->print("%4d (%5d) ", j, m->vtable_index()); m->access_flags().print_on(tty); tty->print(" -- "); @@ -3415,7 +3499,7 @@ } tty->print_cr("_added_methods --"); for (j = 0; j < _added_methods_length; ++j) { - methodOop m = _added_methods[j]; + Method* m = _added_methods[j]; tty->print("%4d (%5d) ", j, m->vtable_index()); m->access_flags().print_on(tty); tty->print(" -- ");