diff options
author | Ivan Dubrov <idubrov@guidewire.com> | 2014-05-01 10:13:07 -0700 |
---|---|---|
committer | Ivan Dubrov <idubrov@guidewire.com> | 2014-05-01 10:13:07 -0700 |
commit | 993e0595f6fac4411789c49d0f3d1f821682fe64 (patch) | |
tree | dfebba3f9451f727e1ebdc77ec784bdd6971be2b /hotspot | |
parent | 7887b0ca4052d938ca37fae816da2d8b92586ac0 (diff) | |
download | dcevm-993e0595f6fac4411789c49d0f3d1f821682fe64.tar.gz dcevm-993e0595f6fac4411789c49d0f3d1f821682fe64.zip |
hg qrefresh on patches
Diffstat (limited to 'hotspot')
-rw-r--r-- | hotspot/.hg/patches/distro-name.patch | 8 | ||||
-rw-r--r-- | hotspot/.hg/patches/light-jdk7u51-b13.patch | 4780 |
2 files changed, 2352 insertions, 2436 deletions
diff --git a/hotspot/.hg/patches/distro-name.patch b/hotspot/.hg/patches/distro-name.patch index 62e5edca..08f641a0 100644 --- a/hotspot/.hg/patches/distro-name.patch +++ b/hotspot/.hg/patches/distro-name.patch @@ -1,7 +1,8 @@ Changes name of VM. -diff -r 8a6717910608 make/openjdk_distro ---- a/make/openjdk_distro Tue Mar 11 13:02:13 2014 -0700 -+++ b/make/openjdk_distro Wed Apr 30 11:27:18 2014 -0700 + +diff --git a/make/openjdk_distro b/make/openjdk_distro +--- a/make/openjdk_distro ++++ b/make/openjdk_distro @@ -27,6 +27,6 @@ # @@ -10,4 +11,3 @@ diff -r 8a6717910608 make/openjdk_distro +HOTSPOT_VM_DISTRO=Dynamic Code Evolution COMPANY_NAME= PRODUCT_NAME=OpenJDK - diff --git a/hotspot/.hg/patches/light-jdk7u51-b13.patch b/hotspot/.hg/patches/light-jdk7u51-b13.patch index 96049ec2..1708409f 100644 --- a/hotspot/.hg/patches/light-jdk7u51-b13.patch +++ b/hotspot/.hg/patches/light-jdk7u51-b13.patch @@ -1,8 +1,7 @@ diff --git a/src/cpu/x86/vm/interp_masm_x86_32.cpp b/src/cpu/x86/vm/interp_masm_x86_32.cpp -index b0ebcfd..6366d68 100644 --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp -@@ -1364,7 +1364,7 @@ void InterpreterMacroAssembler::notify_method_entry() { +@@ -1364,7 +1364,7 @@ } // RedefineClasses() tracing support for obsolete method entry @@ -12,10 +11,9 @@ index b0ebcfd..6366d68 100644 get_method(rbx); call_VM_leaf( diff --git a/src/cpu/x86/vm/interp_masm_x86_64.cpp b/src/cpu/x86/vm/interp_masm_x86_64.cpp -index 2790c2a..c315b18 100644 --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp -@@ -1427,7 +1427,7 @@ void InterpreterMacroAssembler::notify_method_entry() { +@@ -1427,7 +1427,7 @@ } // RedefineClasses() tracing support for obsolete method entry @@ -25,10 +23,9 @@ index 2790c2a..c315b18 100644 call_VM_leaf( CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), diff --git a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp -index 16958cd..09d6300 100644 --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp -@@ -1976,7 +1976,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, +@@ -1976,7 +1976,7 @@ } // RedefineClasses() tracing support for obsolete method entry @@ -38,10 +35,9 @@ index 16958cd..09d6300 100644 __ call_VM_leaf( CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), diff --git a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp -index 7dc4e62..86c8c95 100644 --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp -@@ -2235,7 +2235,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, +@@ -2235,7 +2235,7 @@ } // RedefineClasses() tracing support for obsolete method entry @@ -51,10 +47,9 @@ index 7dc4e62..86c8c95 100644 save_args(masm, total_c_args, c_arg, out_regs); __ movoop(c_rarg1, JNIHandles::make_local(method())); diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp -index 9a8ca61..83e6f54 100644 --- a/src/share/vm/c1/c1_Compilation.hpp +++ b/src/share/vm/c1/c1_Compilation.hpp -@@ -242,8 +242,9 @@ class Compilation: public StackObj { +@@ -242,8 +242,9 @@ #define BAILOUT(msg) { bailout(msg); return; } #define BAILOUT_(msg, res) { bailout(msg); return res; } @@ -67,10 +62,9 @@ index 9a8ca61..83e6f54 100644 class InstructionMark: public StackObj { diff --git a/src/share/vm/ci/ciObjectFactory.cpp b/src/share/vm/ci/ciObjectFactory.cpp -index e0ab96b..db8e551 100644 --- a/src/share/vm/ci/ciObjectFactory.cpp +++ b/src/share/vm/ci/ciObjectFactory.cpp -@@ -764,3 +764,26 @@ void ciObjectFactory::print() { +@@ -764,3 +764,26 @@ _unloaded_instances->length(), _unloaded_klasses->length()); } @@ -98,10 +92,9 @@ index e0ab96b..db8e551 100644 +} + diff --git a/src/share/vm/ci/ciObjectFactory.hpp b/src/share/vm/ci/ciObjectFactory.hpp -index 26cc2c3..d99d3d6 100644 --- a/src/share/vm/ci/ciObjectFactory.hpp +++ b/src/share/vm/ci/ciObjectFactory.hpp -@@ -88,6 +88,7 @@ private: +@@ -88,6 +88,7 @@ ciInstance* get_unloaded_instance(ciInstanceKlass* klass); @@ -109,7 +102,7 @@ index 26cc2c3..d99d3d6 100644 public: static bool is_initialized() { return _initialized; } -@@ -137,6 +138,8 @@ public: +@@ -137,6 +138,8 @@ void print_contents(); void print(); @@ -119,10 +112,9 @@ index 26cc2c3..d99d3d6 100644 #endif // SHARE_VM_CI_CIOBJECTFACTORY_HPP diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp -index 5ea1d43..8590ad1 100644 --- a/src/share/vm/classfile/classFileParser.cpp +++ b/src/share/vm/classfile/classFileParser.cpp -@@ -795,6 +795,7 @@ objArrayHandle ClassFileParser::parse_interfaces(constantPoolHandle cp, +@@ -795,6 +795,7 @@ Handle class_loader, Handle protection_domain, Symbol* class_name, @@ -130,7 +122,7 @@ index 5ea1d43..8590ad1 100644 TRAPS) { ClassFileStream* cfs = stream(); assert(length > 0, "only called for length>0"); -@@ -813,6 +814,9 @@ objArrayHandle ClassFileParser::parse_interfaces(constantPoolHandle cp, +@@ -813,6 +814,9 @@ interface_index, CHECK_(nullHandle)); if (cp->tag_at(interface_index).is_klass()) { interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index)); @@ -140,7 +132,7 @@ index 5ea1d43..8590ad1 100644 } else { Symbol* unresolved_klass = cp->klass_name_at(interface_index); -@@ -825,6 +829,9 @@ objArrayHandle ClassFileParser::parse_interfaces(constantPoolHandle cp, +@@ -825,6 +829,9 @@ klassOop k = SystemDictionary::resolve_super_or_fail(class_name, unresolved_klass, class_loader, protection_domain, false, CHECK_(nullHandle)); @@ -150,7 +142,7 @@ index 5ea1d43..8590ad1 100644 interf = KlassHandle(THREAD, k); } -@@ -2921,8 +2928,10 @@ typeArrayHandle ClassFileParser::assemble_annotations(u1* runtime_visible_annota +@@ -2921,8 +2928,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, Handle class_loader, Handle protection_domain, @@ -161,7 +153,7 @@ index 5ea1d43..8590ad1 100644 TempNewSymbol& parsed_name, bool verify, TRAPS) { -@@ -2948,7 +2957,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -2948,7 +2957,7 @@ init_parsed_class_attributes(); @@ -170,7 +162,7 @@ index 5ea1d43..8590ad1 100644 // Get the cached class file bytes (if any) from the class that // is being redefined or retransformed. We use jvmti_thread_state() // instead of JvmtiThreadState::state_for(jt) so we don't allocate -@@ -2971,10 +2980,13 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -2971,10 +2980,13 @@ unsigned char* ptr = cfs->buffer(); unsigned char* end_ptr = cfs->buffer() + cfs->length(); @@ -184,7 +176,7 @@ index 5ea1d43..8590ad1 100644 if (ptr != cfs->buffer()) { // JVMTI agent has modified class file data. -@@ -3090,6 +3102,30 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3090,6 +3102,30 @@ CHECK_(nullHandle)); } @@ -215,7 +207,7 @@ index 5ea1d43..8590ad1 100644 klassOop preserve_this_klass; // for storing result across HandleMark // release all handles when parsing is done -@@ -3130,7 +3166,11 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3130,7 +3166,11 @@ // However, make sure it is not an array type. bool is_array = false; if (cp->tag_at(super_class_index).is_klass()) { @@ -228,7 +220,7 @@ index 5ea1d43..8590ad1 100644 if (_need_verify) is_array = super_klass->oop_is_array(); } else if (_need_verify) { -@@ -3148,7 +3188,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3148,7 +3188,7 @@ if (itfs_len == 0) { local_interfaces = objArrayHandle(THREAD, Universe::the_empty_system_obj_array()); } else { @@ -237,7 +229,7 @@ index 5ea1d43..8590ad1 100644 } u2 java_fields_count = 0; -@@ -3202,7 +3242,9 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3202,7 +3242,9 @@ protection_domain, true, CHECK_(nullHandle)); @@ -248,7 +240,7 @@ index 5ea1d43..8590ad1 100644 KlassHandle kh (THREAD, k); super_klass = instanceKlassHandle(THREAD, kh()); } -@@ -3591,6 +3633,19 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3591,6 +3633,19 @@ rt = REF_NONE; } else { rt = super_klass->reference_type(); @@ -268,7 +260,7 @@ index 5ea1d43..8590ad1 100644 } // We can now create the basic klassOop for this klass -@@ -3599,6 +3654,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3599,6 +3654,7 @@ total_oop_map_count, access_flags, rt, host_klass, @@ -276,7 +268,7 @@ index 5ea1d43..8590ad1 100644 CHECK_(nullHandle)); instanceKlassHandle this_klass (THREAD, ik); -@@ -3691,7 +3747,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3691,7 +3747,7 @@ fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts); // Fill in has_finalizer, has_vanilla_constructor, and layout_helper @@ -285,7 +277,7 @@ index 5ea1d43..8590ad1 100644 // reinitialize modifiers, using the InnerClasses attribute int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle)); -@@ -3711,6 +3767,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3711,6 +3767,10 @@ check_illegal_static_method(this_klass, CHECK_(nullHandle)); } @@ -296,7 +288,7 @@ index 5ea1d43..8590ad1 100644 // Allocate mirror and initialize static fields java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle)); -@@ -3856,7 +3916,7 @@ void ClassFileParser::fill_oop_maps(instanceKlassHandle k, +@@ -3856,7 +3916,7 @@ } @@ -305,7 +297,7 @@ index 5ea1d43..8590ad1 100644 klassOop super = k->super(); // Check if this klass has an empty finalize method (i.e. one with return bytecode only), -@@ -3864,7 +3924,9 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) { +@@ -3864,7 +3924,9 @@ if (!_has_empty_finalizer) { if (_has_finalizer || (super != NULL && super->klass_part()->has_finalizer())) { @@ -316,7 +308,7 @@ index 5ea1d43..8590ad1 100644 } } -@@ -3880,7 +3942,7 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) { +@@ -3880,7 +3942,7 @@ // Check if this klass supports the java.lang.Cloneable interface if (SystemDictionary::Cloneable_klass_loaded()) { @@ -326,10 +318,9 @@ index 5ea1d43..8590ad1 100644 } } diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp -index 314ec5e..5fca1da 100644 --- a/src/share/vm/classfile/classFileParser.hpp +++ b/src/share/vm/classfile/classFileParser.hpp -@@ -151,6 +151,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { +@@ -151,6 +151,7 @@ Handle class_loader, Handle protection_domain, Symbol* class_name, @@ -337,7 +328,7 @@ index 314ec5e..5fca1da 100644 TRAPS); // Field parsing -@@ -237,7 +238,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { +@@ -237,7 +238,7 @@ unsigned int nonstatic_oop_map_count, int* nonstatic_oop_offsets, unsigned int* nonstatic_oop_counts); @@ -346,7 +337,7 @@ index 314ec5e..5fca1da 100644 objArrayHandle compute_transitive_interfaces(instanceKlassHandle super, objArrayHandle local_ifs, TRAPS); -@@ -349,17 +350,20 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { +@@ -349,17 +350,20 @@ instanceKlassHandle parseClassFile(Symbol* name, Handle class_loader, Handle protection_domain, @@ -369,10 +360,9 @@ index 314ec5e..5fca1da 100644 bool verify, TRAPS); diff --git a/src/share/vm/classfile/classLoader.cpp b/src/share/vm/classfile/classLoader.cpp -index a2e61a4..450e19f 100644 --- a/src/share/vm/classfile/classLoader.cpp +++ b/src/share/vm/classfile/classLoader.cpp -@@ -915,6 +915,7 @@ instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) { +@@ -915,6 +915,7 @@ instanceKlassHandle result = parser.parseClassFile(h_name, class_loader, protection_domain, @@ -381,10 +371,9 @@ index a2e61a4..450e19f 100644 false, CHECK_(h)); diff --git a/src/share/vm/classfile/dictionary.cpp b/src/share/vm/classfile/dictionary.cpp -index 78e76cc..d167c98 100644 --- a/src/share/vm/classfile/dictionary.cpp +++ b/src/share/vm/classfile/dictionary.cpp -@@ -144,87 +144,10 @@ bool Dictionary::do_unloading(BoolObjectClosure* is_alive) { +@@ -144,87 +144,10 @@ probe = *p; klassOop e = probe->klass(); oop class_loader = probe->loader(); @@ -474,7 +463,7 @@ index 78e76cc..d167c98 100644 // Entry was not visited in phase1 (negated test from phase1) assert(class_loader != NULL, "unloading entry with null class loader"); oop k_def_class_loader = ik->class_loader(); -@@ -326,6 +249,7 @@ void Dictionary::classes_do(void f(klassOop)) { +@@ -326,6 +249,7 @@ } } @@ -482,7 +471,7 @@ index 78e76cc..d167c98 100644 // Added for initialize_itable_for_klass to handle exceptions // Just the classes from defining class loaders void Dictionary::classes_do(void f(klassOop, TRAPS), TRAPS) { -@@ -433,6 +357,33 @@ void Dictionary::add_klass(Symbol* class_name, Handle class_loader, +@@ -433,6 +357,33 @@ add_entry(index, entry); } @@ -516,7 +505,7 @@ index 78e76cc..d167c98 100644 // This routine does not lock the system dictionary. // -@@ -459,12 +410,21 @@ DictionaryEntry* Dictionary::get_entry(int index, unsigned int hash, +@@ -459,12 +410,21 @@ return NULL; } @@ -539,7 +528,7 @@ index 78e76cc..d167c98 100644 } else { return NULL; } -@@ -477,7 +437,7 @@ klassOop Dictionary::find_class(int index, unsigned int hash, +@@ -477,7 +437,7 @@ assert (index == index_for(name, loader), "incorrect index?"); DictionaryEntry* entry = get_entry(index, hash, name, loader); @@ -548,7 +537,7 @@ index 78e76cc..d167c98 100644 } -@@ -489,7 +449,7 @@ klassOop Dictionary::find_shared_class(int index, unsigned int hash, +@@ -489,7 +449,7 @@ assert (index == index_for(name, Handle()), "incorrect index?"); DictionaryEntry* entry = get_entry(index, hash, name, Handle()); @@ -558,10 +547,9 @@ index 78e76cc..d167c98 100644 diff --git a/src/share/vm/classfile/dictionary.hpp b/src/share/vm/classfile/dictionary.hpp -index bd33760..ea1fe3c 100644 --- a/src/share/vm/classfile/dictionary.hpp +++ b/src/share/vm/classfile/dictionary.hpp -@@ -73,6 +73,10 @@ public: +@@ -73,6 +73,10 @@ void add_klass(Symbol* class_name, Handle class_loader,KlassHandle obj); @@ -572,7 +560,7 @@ index bd33760..ea1fe3c 100644 klassOop find_class(int index, unsigned int hash, Symbol* name, Handle loader); -@@ -105,6 +109,7 @@ public: +@@ -105,6 +109,7 @@ bool do_unloading(BoolObjectClosure* is_alive); // Protection domains @@ -581,10 +569,9 @@ index bd33760..ea1fe3c 100644 Handle loader, Handle protection_domain, TRAPS); bool is_valid_protection_domain(int index, unsigned int hash, diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp -index f8b10b3..c417a29 100644 --- a/src/share/vm/classfile/javaClasses.cpp +++ b/src/share/vm/classfile/javaClasses.cpp -@@ -621,6 +621,10 @@ klassOop java_lang_Class::as_klassOop(oop java_class) { +@@ -621,6 +621,10 @@ assert(java_lang_Class::is_instance(java_class), "must be a Class object"); klassOop k = klassOop(java_class->obj_field(_klass_offset)); assert(k == NULL || k->is_klass(), "type check"); @@ -595,7 +582,7 @@ index f8b10b3..c417a29 100644 return k; } -@@ -1541,6 +1545,7 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, methodHandle met +@@ -1541,6 +1545,7 @@ skip_throwableInit_check = true; } } @@ -604,10 +591,9 @@ index f8b10b3..c417a29 100644 if (skip_hidden) continue; } diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp -index b741cfa..5412831 100644 --- a/src/share/vm/classfile/javaClasses.hpp +++ b/src/share/vm/classfile/javaClasses.hpp -@@ -213,6 +213,7 @@ class java_lang_String : AllStatic { +@@ -213,6 +213,7 @@ class java_lang_Class : AllStatic { friend class VMStructs; @@ -615,7 +601,7 @@ index b741cfa..5412831 100644 private: // The fake offsets are added by the class loader when java.lang.Class is loaded -@@ -248,7 +249,7 @@ class java_lang_Class : AllStatic { +@@ -248,7 +249,7 @@ static void print_signature(oop java_class, outputStream *st); // Testing static bool is_instance(oop obj) { @@ -625,10 +611,9 @@ index b741cfa..5412831 100644 static bool is_primitive(oop java_class); static BasicType primitive_type(oop java_class); diff --git a/src/share/vm/classfile/loaderConstraints.cpp b/src/share/vm/classfile/loaderConstraints.cpp -index 8650cd9..965cce2 100644 --- a/src/share/vm/classfile/loaderConstraints.cpp +++ b/src/share/vm/classfile/loaderConstraints.cpp -@@ -449,7 +449,7 @@ void LoaderConstraintTable::verify(Dictionary* dictionary, +@@ -449,7 +449,7 @@ if (k != NULL) { // We found the class in the system dictionary, so we should // make sure that the klassOop matches what we already have. @@ -638,10 +623,9 @@ index 8650cd9..965cce2 100644 // If we don't find the class in the system dictionary, it // has to be in the placeholders table. diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfile/systemDictionary.cpp -index 899153a..3f64268 100644 --- a/src/share/vm/classfile/systemDictionary.cpp +++ b/src/share/vm/classfile/systemDictionary.cpp -@@ -157,6 +157,7 @@ klassOop SystemDictionary::resolve_or_fail(Symbol* class_name, Handle class_load +@@ -157,6 +157,7 @@ // can return a null klass klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD); } @@ -649,7 +633,7 @@ index 899153a..3f64268 100644 return klass; } -@@ -199,7 +200,7 @@ klassOop SystemDictionary::resolve_or_fail(Symbol* class_name, +@@ -199,7 +200,7 @@ // Forwards to resolve_instance_class_or_null klassOop SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { @@ -658,7 +642,7 @@ index 899153a..3f64268 100644 err_msg("can not load classes with compiler thread: class=%s, classloader=%s", class_name->as_C_string(), class_loader.is_null() ? "null" : class_loader->klass()->klass_part()->name()->as_C_string())); -@@ -961,8 +962,10 @@ klassOop SystemDictionary::parse_stream(Symbol* class_name, +@@ -961,8 +962,10 @@ instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, class_loader, protection_domain, @@ -669,7 +653,7 @@ index 899153a..3f64268 100644 parsed_name, true, THREAD); -@@ -1022,7 +1025,15 @@ klassOop SystemDictionary::resolve_from_stream(Symbol* class_name, +@@ -1022,7 +1025,15 @@ Handle protection_domain, ClassFileStream* st, bool verify, @@ -685,7 +669,7 @@ index 899153a..3f64268 100644 // Classloaders that support parallelism, e.g. bootstrap classloader, // or all classloaders with UnsyncloadClass do not acquire lock here bool DoObjectLock = true; -@@ -1050,9 +1061,14 @@ klassOop SystemDictionary::resolve_from_stream(Symbol* class_name, +@@ -1050,9 +1061,14 @@ instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, class_loader, protection_domain, @@ -700,7 +684,7 @@ index 899153a..3f64268 100644 const char* pkg = "java/"; if (!HAS_PENDING_EXCEPTION && -@@ -1087,13 +1103,18 @@ klassOop SystemDictionary::resolve_from_stream(Symbol* class_name, +@@ -1087,13 +1103,18 @@ // Add class just loaded // If a class loader supports parallel classloading handle parallel define requests // find_or_define_instance_class may return a different instanceKlass @@ -721,7 +705,7 @@ index 899153a..3f64268 100644 // If parsing the class file or define_instance_class failed, we // need to remove the placeholder added on our behalf. But we // must make sure parsed_name is valid first (it won't be if we had -@@ -1122,7 +1143,7 @@ klassOop SystemDictionary::resolve_from_stream(Symbol* class_name, +@@ -1122,7 +1143,7 @@ MutexLocker mu(SystemDictionary_lock, THREAD); klassOop check = find_class(parsed_name, class_loader); @@ -730,7 +714,7 @@ index 899153a..3f64268 100644 klassOop check2 = find_class(h_name, h_loader); assert(check == check2, "name inconsistancy in SystemDictionary"); -@@ -1349,7 +1370,11 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha +@@ -1349,7 +1370,11 @@ } } @@ -743,7 +727,7 @@ index 899153a..3f64268 100644 Handle class_loader_h(THREAD, k->class_loader()); -@@ -1376,13 +1401,23 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { +@@ -1376,13 +1401,23 @@ Symbol* name_h = k->name(); unsigned int d_hash = dictionary()->compute_hash(name_h, class_loader_h); int d_index = dictionary()->hash_to_index(d_hash); @@ -769,7 +753,7 @@ index 899153a..3f64268 100644 methodHandle m(THREAD, Universe::loader_addClass_method()); JavaValue result(T_VOID); JavaCallArguments args(class_loader_h); -@@ -1408,8 +1443,9 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { +@@ -1408,8 +1443,9 @@ } k->eager_initialize(THREAD); @@ -780,7 +764,7 @@ index 899153a..3f64268 100644 assert(THREAD->is_Java_thread(), "thread->is_Java_thread()"); JvmtiExport::post_class_load((JavaThread *) THREAD, k()); -@@ -1482,7 +1518,7 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(Symbol* clas +@@ -1482,7 +1518,7 @@ } } @@ -789,7 +773,7 @@ index 899153a..3f64268 100644 Handle linkage_exception = Handle(); // null handle -@@ -1612,6 +1648,14 @@ void SystemDictionary::add_to_hierarchy(instanceKlassHandle k, TRAPS) { +@@ -1612,6 +1648,14 @@ Universe::flush_dependents_on(k); } @@ -804,7 +788,7 @@ index 899153a..3f64268 100644 // ---------------------------------------------------------------------------- // GC support -@@ -1869,9 +1913,12 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { +@@ -1869,9 +1913,12 @@ // Preload ref klasses and set reference types instanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER); @@ -818,7 +802,7 @@ index 899153a..3f64268 100644 instanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT); instanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK); instanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL); -@@ -1955,7 +2002,7 @@ void SystemDictionary::check_constraints(int d_index, unsigned int d_hash, +@@ -1955,7 +2002,7 @@ // also holds array classes assert(check->klass_part()->oop_is_instance(), "noninstance in systemdictionary"); @@ -827,7 +811,7 @@ index 899153a..3f64268 100644 linkage_error = "loader (instance of %s): attempted duplicate class " "definition for name: \"%s\""; } else { -@@ -2602,8 +2649,10 @@ void SystemDictionary::verify_obj_klass_present(Handle obj, +@@ -2602,8 +2649,10 @@ name = find_placeholder(class_name, class_loader); } } @@ -841,10 +825,9 @@ index 899153a..3f64268 100644 // utility function for posting class load event diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp -index adf82e5..00cf392 100644 --- a/src/share/vm/classfile/systemDictionary.hpp +++ b/src/share/vm/classfile/systemDictionary.hpp -@@ -268,7 +268,7 @@ public: +@@ -268,7 +268,7 @@ // Resolve from stream (called by jni_DefineClass and JVM_DefineClass) static klassOop resolve_from_stream(Symbol* class_name, Handle class_loader, Handle protection_domain, @@ -853,7 +836,7 @@ index adf82e5..00cf392 100644 // Lookup an already loaded class. If not found NULL is returned. static klassOop find(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS); -@@ -343,6 +343,8 @@ public: +@@ -343,6 +343,8 @@ // System loader lock static oop system_loader_lock() { return _system_loader_lock_obj; } @@ -862,7 +845,7 @@ index adf82e5..00cf392 100644 private: // Traverses preloaded oops: various system classes. These are // guaranteed to be in the perm gen. -@@ -415,6 +417,8 @@ public: +@@ -415,6 +417,8 @@ initialize_wk_klasses_until((WKID) limit, start_id, THREAD); } @@ -871,7 +854,7 @@ index adf82e5..00cf392 100644 public: #define WK_KLASS_DECLARE(name, symbol, option) \ static klassOop name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); } -@@ -596,7 +600,7 @@ private: +@@ -596,7 +600,7 @@ // after waiting, but before reentering SystemDictionary_lock // to preserve lock order semantics. static void double_lock_wait(Handle lockObject, TRAPS); @@ -881,10 +864,9 @@ index adf82e5..00cf392 100644 Handle class_loader, instanceKlassHandle k, TRAPS); diff --git a/src/share/vm/classfile/verifier.cpp b/src/share/vm/classfile/verifier.cpp -index da188bb..097c50c 100644 --- a/src/share/vm/classfile/verifier.cpp +++ b/src/share/vm/classfile/verifier.cpp -@@ -106,7 +106,7 @@ bool Verifier::relax_verify_for(oop loader) { +@@ -106,7 +106,7 @@ return !need_verify; } @@ -893,7 +875,7 @@ index da188bb..097c50c 100644 HandleMark hm; ResourceMark rm(THREAD); -@@ -117,6 +117,7 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul +@@ -117,6 +117,7 @@ const char* klassName = klass->external_name(); bool can_failover = FailOverToOldVerifier && @@ -901,7 +883,7 @@ index da188bb..097c50c 100644 klass->major_version() < NOFAILOVER_MAJOR_VERSION; // If the class should be verified, first see if we can use the split -@@ -138,6 +139,7 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul +@@ -138,6 +139,7 @@ tty->print_cr( "Fail over class verification to old verifier for: %s", klassName); } @@ -909,7 +891,7 @@ index da188bb..097c50c 100644 exception_name = inference_verify( klass, message_buffer, message_buffer_len, THREAD); } -@@ -145,6 +147,7 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul +@@ -145,6 +147,7 @@ exception_message = split_verifier.exception_message(); } } else { @@ -917,7 +899,7 @@ index da188bb..097c50c 100644 exception_name = inference_verify( klass, message_buffer, message_buffer_len, THREAD); } -@@ -210,7 +213,7 @@ bool Verifier::is_eligible_for_verification(instanceKlassHandle klass, bool shou +@@ -210,7 +213,7 @@ // NOTE: this is called too early in the bootstrapping process to be // guarded by Universe::is_gte_jdk14x_version()/UseNewReflection. (refl_magic_klass == NULL || @@ -926,7 +908,7 @@ index da188bb..097c50c 100644 VerifyReflectionBytecodes) ); } -@@ -517,7 +520,7 @@ void ErrorContext::stackmap_details(outputStream* ss, methodOop method) const { +@@ -517,7 +520,7 @@ ClassVerifier::ClassVerifier( instanceKlassHandle klass, TRAPS) @@ -935,7 +917,7 @@ index da188bb..097c50c 100644 _this_type = VerificationType::reference_type(klass->name()); // Create list to hold symbols in reference area. _symbols = new GrowableArray<Symbol*>(100, 0, NULL); -@@ -547,7 +550,7 @@ void ClassVerifier::verify_class(TRAPS) { +@@ -547,7 +550,7 @@ _klass->external_name()); } @@ -944,7 +926,7 @@ index da188bb..097c50c 100644 int num_methods = methods->length(); for (int index = 0; index < num_methods; index++) { -@@ -2444,7 +2447,8 @@ void ClassVerifier::verify_invoke_instructions( +@@ -2444,7 +2447,8 @@ VerificationType stack_object_type = current_frame->pop_stack(ref_class_type, CHECK_VERIFY(this)); if (current_type() != stack_object_type) { @@ -955,10 +937,9 @@ index da188bb..097c50c 100644 cp->klass_name_at(cp->klass_ref_index_at(index)); // See the comments in verify_field_instructions() for diff --git a/src/share/vm/classfile/verifier.hpp b/src/share/vm/classfile/verifier.hpp -index 4457f4a..b1b96f2 100644 --- a/src/share/vm/classfile/verifier.hpp +++ b/src/share/vm/classfile/verifier.hpp -@@ -47,7 +47,7 @@ class Verifier : AllStatic { +@@ -47,7 +47,7 @@ * Otherwise, no exception is thrown and the return indicates the * error. */ @@ -967,7 +948,7 @@ index 4457f4a..b1b96f2 100644 // Return false if the class is loaded by the bootstrap loader, // or if defineClass was called requesting skipping verification -@@ -256,7 +256,10 @@ class ClassVerifier : public StackObj { +@@ -256,7 +256,10 @@ ErrorContext _error_context; // contains information about an error @@ -978,7 +959,7 @@ index 4457f4a..b1b96f2 100644 char* generate_code_data(methodHandle m, u4 code_length, TRAPS); void verify_exception_handler_table(u4 code_length, char* code_data, int& min, int& max, TRAPS); -@@ -329,6 +332,7 @@ class ClassVerifier : public StackObj { +@@ -329,6 +332,7 @@ VerificationType object_type() const; @@ -987,10 +968,9 @@ index 4457f4a..b1b96f2 100644 methodHandle _method; // current method being verified VerificationType _this_type; // the verification type of the current class diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp -index 21c9413..59f5f7e 100644 --- a/src/share/vm/code/nmethod.cpp +++ b/src/share/vm/code/nmethod.cpp -@@ -2074,15 +2074,14 @@ bool nmethod::is_evol_dependent_on(klassOop dependee) { +@@ -2074,15 +2074,14 @@ methodOop method = deps.method_argument(0); for (int j = 0; j < dependee_methods->length(); j++) { if ((methodOop) dependee_methods->obj_at(j) == method) { @@ -1010,10 +990,9 @@ index 21c9413..59f5f7e 100644 deps.log_dependency(dependee); return true; diff --git a/src/share/vm/compiler/compileBroker.cpp b/src/share/vm/compiler/compileBroker.cpp -index 0feca89..1c4b014 100644 --- a/src/share/vm/compiler/compileBroker.cpp +++ b/src/share/vm/compiler/compileBroker.cpp -@@ -1592,6 +1592,9 @@ void CompileBroker::compiler_thread_loop() { +@@ -1592,6 +1592,9 @@ // Never compile a method if breakpoints are present in it if (method()->number_of_breakpoints() == 0) { @@ -1023,7 +1002,7 @@ index 0feca89..1c4b014 100644 // Compile the method. if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) { #ifdef COMPILER1 -@@ -1615,6 +1618,7 @@ void CompileBroker::compiler_thread_loop() { +@@ -1615,6 +1618,7 @@ // After compilation is disabled, remove remaining methods from queue method->clear_queued_for_compilation(); } @@ -1031,7 +1010,7 @@ index 0feca89..1c4b014 100644 } } } -@@ -1780,7 +1784,11 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { +@@ -1780,7 +1784,11 @@ //assert(false, "compiler should always document failure"); // The compiler elected, without comment, not to register a result. // Do not attempt further compilations of this method. @@ -1045,10 +1024,9 @@ index 0feca89..1c4b014 100644 // Copy this bit to the enclosing block: diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp -index b0c9ec8..7feadf9 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp -@@ -162,6 +162,13 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, +@@ -162,6 +162,13 @@ } } @@ -1062,7 +1040,7 @@ index b0c9ec8..7feadf9 100644 // Like CompactibleSpace forward() but always calls cross_threshold() to // update the block offset table. Removed initialize_threshold call because // CFLS does not use a block offset array for contiguous spaces. -@@ -2118,7 +2125,7 @@ bool CompactibleFreeListSpace::should_concurrent_collect() const { +@@ -2118,7 +2125,7 @@ // Support for compaction void CompactibleFreeListSpace::prepare_for_compaction(CompactPoint* cp) { @@ -1071,7 +1049,7 @@ index b0c9ec8..7feadf9 100644 // prepare_for_compaction() uses the space between live objects // so that later phase can skip dead space quickly. So verification // of the free lists doesn't work after. -@@ -2139,7 +2146,7 @@ void CompactibleFreeListSpace::adjust_pointers() { +@@ -2139,7 +2146,7 @@ } void CompactibleFreeListSpace::compact() { @@ -1081,10 +1059,9 @@ index b0c9ec8..7feadf9 100644 // fragmentation_metric = 1 - [sum of (fbs**2) / (sum of fbs)**2] diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp -index 3b7bb9a..de7e54b 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp -@@ -149,6 +149,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { +@@ -149,6 +149,7 @@ // Support for compacting cms HeapWord* cross_threshold(HeapWord* start, HeapWord* end); @@ -1093,7 +1070,6 @@ index 3b7bb9a..de7e54b 100644 // Initialization helpers. diff --git a/src/share/vm/gc_implementation/shared/markSweep.cpp b/src/share/vm/gc_implementation/shared/markSweep.cpp -index 29841d8..d1386c7 100644 --- a/src/share/vm/gc_implementation/shared/markSweep.cpp +++ b/src/share/vm/gc_implementation/shared/markSweep.cpp @@ -32,6 +32,8 @@ @@ -1105,7 +1081,7 @@ index 29841d8..d1386c7 100644 Stack<oop, mtGC> MarkSweep::_marking_stack; Stack<DataLayout*, mtGC> MarkSweep::_revisit_mdo_stack; Stack<Klass*, mtGC> MarkSweep::_revisit_klass_stack; -@@ -357,3 +359,97 @@ void MarkSweep::trace(const char* msg) { +@@ -357,3 +359,97 @@ } #endif @@ -1204,10 +1180,9 @@ index 29841d8..d1386c7 100644 + } +} diff --git a/src/share/vm/gc_implementation/shared/markSweep.hpp b/src/share/vm/gc_implementation/shared/markSweep.hpp -index eb8252c..40118db 100644 --- a/src/share/vm/gc_implementation/shared/markSweep.hpp +++ b/src/share/vm/gc_implementation/shared/markSweep.hpp -@@ -117,8 +117,12 @@ class MarkSweep : AllStatic { +@@ -117,8 +117,12 @@ friend class AdjustPointerClosure; friend class KeepAliveClosure; friend class VM_MarkSweep; @@ -1220,7 +1195,7 @@ index eb8252c..40118db 100644 // // Vars // -@@ -208,6 +212,9 @@ class MarkSweep : AllStatic { +@@ -208,6 +212,9 @@ template <class T> static inline void mark_and_push(T* p); static inline void push_objarray(oop obj, size_t index); @@ -1231,10 +1206,9 @@ index eb8252c..40118db 100644 static void preserve_mark(oop p, markOop mark); diff --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp -index 32c0bdb..448d673 100644 --- a/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/src/share/vm/interpreter/interpreterRuntime.cpp -@@ -402,7 +402,7 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea +@@ -402,7 +402,7 @@ assert(h_exception.not_null(), "NULL exceptions should be handled by athrow"); assert(h_exception->is_oop(), "just checking"); // Check that exception is a subclass of Throwable, otherwise we have a VerifyError @@ -1244,10 +1218,9 @@ index 32c0bdb..448d673 100644 ShouldNotReachHere(); } diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp -index b17f405..1c96783 100644 --- a/src/share/vm/interpreter/linkResolver.cpp +++ b/src/share/vm/interpreter/linkResolver.cpp -@@ -153,8 +153,8 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass +@@ -153,8 +153,8 @@ // Klass resolution void LinkResolver::check_klass_accessability(KlassHandle ref_klass, KlassHandle sel_klass, TRAPS) { @@ -1258,7 +1231,7 @@ index b17f405..1c96783 100644 true)) { ResourceMark rm(THREAD); Exceptions::fthrow( -@@ -338,7 +338,7 @@ void LinkResolver::check_method_accessability(KlassHandle ref_klass, +@@ -338,7 +338,7 @@ // We'll check for the method name first, as that's most likely // to be false (so we'll short-circuit out of these tests). if (sel_method->name() == vmSymbols::clone_name() && @@ -1267,7 +1240,7 @@ index b17f405..1c96783 100644 resolved_klass->oop_is_array()) { // We need to change "protected" to "public". assert(flags.is_protected(), "clone not protected?"); -@@ -634,7 +634,7 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo +@@ -634,7 +634,7 @@ } // Final fields can only be accessed from its own class. @@ -1276,7 +1249,7 @@ index b17f405..1c96783 100644 THROW(vmSymbols::java_lang_IllegalAccessError()); } -@@ -839,7 +839,7 @@ void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, KlassHand +@@ -839,7 +839,7 @@ bool check_access, bool check_null_and_abstract, TRAPS) { methodHandle resolved_method; linktime_resolve_virtual_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); @@ -1285,7 +1258,7 @@ index b17f405..1c96783 100644 } // throws linktime exceptions -@@ -869,6 +869,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, +@@ -869,6 +869,7 @@ KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, @@ -1293,7 +1266,7 @@ index b17f405..1c96783 100644 bool check_null_and_abstract, TRAPS) { -@@ -917,6 +918,9 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, +@@ -917,6 +918,9 @@ // recv_klass might be an arrayKlassOop but all vtables start at // the same place. The cast is to avoid virtual call and assertion. instanceKlass* inst = (instanceKlass*)recv_klass()->klass_part(); @@ -1304,10 +1277,9 @@ index b17f405..1c96783 100644 } } diff --git a/src/share/vm/interpreter/linkResolver.hpp b/src/share/vm/interpreter/linkResolver.hpp -index dfd74f9..6ca1b54 100644 --- a/src/share/vm/interpreter/linkResolver.hpp +++ b/src/share/vm/interpreter/linkResolver.hpp -@@ -110,7 +110,8 @@ class CallInfo: public LinkInfo { +@@ -110,7 +110,8 @@ // It does all necessary link-time checks & throws exceptions if necessary. class LinkResolver: AllStatic { @@ -1317,7 +1289,7 @@ index dfd74f9..6ca1b54 100644 static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); static void lookup_method_in_interfaces (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); -@@ -133,7 +134,7 @@ class LinkResolver: AllStatic { +@@ -133,7 +134,7 @@ static void linktime_resolve_interface_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); static void runtime_resolve_special_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, bool check_access, TRAPS); @@ -1327,10 +1299,9 @@ index dfd74f9..6ca1b54 100644 static void check_field_accessability (KlassHandle ref_klass, KlassHandle resolved_klass, KlassHandle sel_klass, fieldDescriptor& fd, TRAPS); diff --git a/src/share/vm/interpreter/oopMapCache.cpp b/src/share/vm/interpreter/oopMapCache.cpp -index 01d5753..6816b3a 100644 --- a/src/share/vm/interpreter/oopMapCache.cpp +++ b/src/share/vm/interpreter/oopMapCache.cpp -@@ -536,9 +536,9 @@ void OopMapCache::flush_obsolete_entries() { +@@ -536,9 +536,9 @@ if (!_array[i].is_empty() && _array[i].method()->is_old()) { // Cache entry is occupied by an old redefined method and we don't want // to pin it down so flush the entry. @@ -1343,10 +1314,9 @@ index 01d5753..6816b3a 100644 _array[i].flush(); } diff --git a/src/share/vm/memory/genMarkSweep.cpp b/src/share/vm/memory/genMarkSweep.cpp -index 76e18d8..6af7c14 100644 --- a/src/share/vm/memory/genMarkSweep.cpp +++ b/src/share/vm/memory/genMarkSweep.cpp -@@ -421,6 +421,7 @@ void GenMarkSweep::mark_sweep_phase4() { +@@ -421,6 +421,7 @@ // in the same order in phase2, phase3 and phase4. We don't quite do that // here (perm_gen first rather than last), so we tell the validate code // to use a higher index (saved from phase2) when verifying perm_gen. @@ -1354,7 +1324,7 @@ index 76e18d8..6af7c14 100644 GenCollectedHeap* gch = GenCollectedHeap::heap(); Generation* pg = gch->perm_gen(); -@@ -433,10 +434,14 @@ void GenMarkSweep::mark_sweep_phase4() { +@@ -433,10 +434,14 @@ VALIDATE_MARK_SWEEP_ONLY(reset_live_oop_tracking(false)); @@ -1370,10 +1340,9 @@ index 76e18d8..6af7c14 100644 pg->post_compact(); // Shared spaces verification. } diff --git a/src/share/vm/memory/iterator.hpp b/src/share/vm/memory/iterator.hpp -index b5f8e0e..856cfce 100644 --- a/src/share/vm/memory/iterator.hpp +++ b/src/share/vm/memory/iterator.hpp -@@ -101,6 +101,12 @@ class OopClosure : public Closure { +@@ -101,6 +101,12 @@ #endif }; @@ -1387,10 +1356,9 @@ index b5f8e0e..856cfce 100644 class ObjectClosure : public Closure { diff --git a/src/share/vm/memory/oopFactory.cpp b/src/share/vm/memory/oopFactory.cpp -index def88cc..016d7eb 100644 --- a/src/share/vm/memory/oopFactory.cpp +++ b/src/share/vm/memory/oopFactory.cpp -@@ -129,11 +129,11 @@ klassOop oopFactory::new_instanceKlass(Symbol* name, int vtable_len, int itable_ +@@ -129,11 +129,11 @@ unsigned int nonstatic_oop_map_count, AccessFlags access_flags, ReferenceType rt, @@ -1405,10 +1373,9 @@ index def88cc..016d7eb 100644 diff --git a/src/share/vm/memory/oopFactory.hpp b/src/share/vm/memory/oopFactory.hpp -index e7e22d4..ce39ada 100644 --- a/src/share/vm/memory/oopFactory.hpp +++ b/src/share/vm/memory/oopFactory.hpp -@@ -80,7 +80,7 @@ class oopFactory: AllStatic { +@@ -80,7 +80,7 @@ unsigned int nonstatic_oop_map_count, AccessFlags access_flags, ReferenceType rt, @@ -1418,10 +1385,9 @@ index e7e22d4..ce39ada 100644 // Methods private: diff --git a/src/share/vm/memory/space.cpp b/src/share/vm/memory/space.cpp -index f97bc34..c8563b2 100644 --- a/src/share/vm/memory/space.cpp +++ b/src/share/vm/memory/space.cpp -@@ -378,9 +378,8 @@ void CompactibleSpace::clear(bool mangle_space) { +@@ -378,9 +378,8 @@ _compaction_top = bottom(); } @@ -1433,7 +1399,7 @@ index f97bc34..c8563b2 100644 // First check if we should switch compaction space assert(this == cp->space, "'this' should be current compaction space."); size_t compaction_max_size = pointer_delta(end(), compact_top); -@@ -400,8 +399,15 @@ HeapWord* CompactibleSpace::forward(oop q, size_t size, +@@ -400,8 +399,15 @@ compaction_max_size = pointer_delta(cp->space->end(), compact_top); } @@ -1450,7 +1416,7 @@ index f97bc34..c8563b2 100644 q->forward_to(oop(compact_top)); assert(q->is_gc_marked(), "encoding the pointer should preserve the mark"); } else { -@@ -423,6 +429,58 @@ HeapWord* CompactibleSpace::forward(oop q, size_t size, +@@ -423,6 +429,58 @@ return compact_top; } @@ -1509,7 +1475,7 @@ index f97bc34..c8563b2 100644 bool CompactibleSpace::insert_deadspace(size_t& allowed_deadspace_words, HeapWord* q, size_t deadlength) { -@@ -444,12 +502,17 @@ bool CompactibleSpace::insert_deadspace(size_t& allowed_deadspace_words, +@@ -444,12 +502,17 @@ #define adjust_obj_size(s) s void CompactibleSpace::prepare_for_compaction(CompactPoint* cp) { @@ -1529,7 +1495,7 @@ index f97bc34..c8563b2 100644 } void Space::adjust_pointers() { -@@ -490,6 +553,111 @@ void Space::adjust_pointers() { +@@ -490,6 +553,111 @@ assert(q == t, "just checking"); } @@ -1641,7 +1607,7 @@ index f97bc34..c8563b2 100644 void CompactibleSpace::adjust_pointers() { // Check first is there is any work to do. if (used() == 0) { -@@ -500,7 +668,13 @@ void CompactibleSpace::adjust_pointers() { +@@ -500,7 +668,13 @@ } void CompactibleSpace::compact() { @@ -1657,10 +1623,9 @@ index f97bc34..c8563b2 100644 void Space::print_short() const { print_short_on(tty); } diff --git a/src/share/vm/memory/space.hpp b/src/share/vm/memory/space.hpp -index ef2f2c6..ff95a8b 100644 --- a/src/share/vm/memory/space.hpp +++ b/src/share/vm/memory/space.hpp -@@ -445,6 +445,9 @@ public: +@@ -445,6 +445,9 @@ // indicates when the next such action should be taken. virtual void prepare_for_compaction(CompactPoint* cp); // MarkSweep support phase3 @@ -1670,7 +1635,7 @@ index ef2f2c6..ff95a8b 100644 virtual void adjust_pointers(); // MarkSweep support phase4 virtual void compact(); -@@ -474,6 +477,15 @@ public: +@@ -474,6 +477,15 @@ // accordingly". virtual HeapWord* forward(oop q, size_t size, CompactPoint* cp, HeapWord* compact_top); @@ -1686,7 +1651,7 @@ index ef2f2c6..ff95a8b 100644 // Return a size with adjusments as required of the space. virtual size_t adjust_object_size_v(size_t size) const { return size; } -@@ -504,7 +516,7 @@ protected: +@@ -504,7 +516,7 @@ size_t word_len); }; @@ -1695,7 +1660,7 @@ index ef2f2c6..ff95a8b 100644 /* Compute the new addresses for the live objects and store it in the mark \ * Used by universe::mark_sweep_phase2() \ */ \ -@@ -564,7 +576,17 @@ protected: +@@ -564,7 +576,17 @@ Prefetch::write(q, interval); \ /* size_t size = oop(q)->size(); changing this for cms for perm gen */\ size_t size = block_size(q); \ @@ -1714,7 +1679,7 @@ index ef2f2c6..ff95a8b 100644 q += size; \ end_of_live = q; \ } else { \ -@@ -613,6 +635,8 @@ protected: +@@ -613,6 +635,8 @@ } \ } \ \ @@ -1723,7 +1688,7 @@ index ef2f2c6..ff95a8b 100644 assert(q == t, "just checking"); \ if (liveRange != NULL) { \ liveRange->set_end(q); \ -@@ -665,13 +689,8 @@ protected: +@@ -665,13 +689,8 @@ q += size; \ } \ \ @@ -1739,7 +1704,7 @@ index ef2f2c6..ff95a8b 100644 } \ \ const intx interval = PrefetchScanIntervalInBytes; \ -@@ -702,7 +721,7 @@ protected: +@@ -702,7 +721,7 @@ assert(q == t, "just checking"); \ } @@ -1748,7 +1713,7 @@ index ef2f2c6..ff95a8b 100644 /* Copy all live objects to their new location \ * Used by MarkSweep::mark_sweep_phase4() */ \ \ -@@ -728,12 +747,8 @@ protected: +@@ -728,12 +747,8 @@ } \ ) /* debug_only */ \ \ @@ -1763,7 +1728,7 @@ index ef2f2c6..ff95a8b 100644 } \ \ const intx scan_interval = PrefetchScanIntervalInBytes; \ -@@ -752,13 +767,36 @@ protected: +@@ -752,13 +767,36 @@ size_t size = obj_size(q); \ HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); \ \ @@ -1802,7 +1767,6 @@ index ef2f2c6..ff95a8b 100644 oop(compaction_top)->init_mark(); \ assert(oop(compaction_top)->klass() != NULL, "should have a class"); \ diff --git a/src/share/vm/memory/specialized_oop_closures.hpp b/src/share/vm/memory/specialized_oop_closures.hpp -index 4d7c50b..671787e 100644 --- a/src/share/vm/memory/specialized_oop_closures.hpp +++ b/src/share/vm/memory/specialized_oop_closures.hpp @@ -37,6 +37,7 @@ @@ -1813,7 +1777,7 @@ index 4d7c50b..671787e 100644 class OopsInGenClosure; // DefNew class ScanClosure; -@@ -74,6 +75,7 @@ class CMSInnerParMarkAndPushClosure; +@@ -74,6 +75,7 @@ #endif #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f) \ @@ -1821,7 +1785,7 @@ index 4d7c50b..671787e 100644 f(ScanClosure,_nv) \ f(FastScanClosure,_nv) \ f(FilteringClosure,_nv) -@@ -132,6 +134,7 @@ class CMSInnerParMarkAndPushClosure; +@@ -132,6 +134,7 @@ #define ALL_PAR_OOP_ITERATE_CLOSURES(f) \ f(OopClosure,_v) \ @@ -1830,7 +1794,6 @@ index 4d7c50b..671787e 100644 #endif // SERIALGC diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp -index 8ce17d9..fe37993 100644 --- a/src/share/vm/memory/universe.cpp +++ b/src/share/vm/memory/universe.cpp @@ -100,6 +100,8 @@ @@ -1842,7 +1805,7 @@ index 8ce17d9..fe37993 100644 // Known objects klassOop Universe::_boolArrayKlassObj = NULL; klassOop Universe::_byteArrayKlassObj = NULL; -@@ -204,6 +206,42 @@ void Universe::system_classes_do(void f(klassOop)) { +@@ -204,6 +206,42 @@ f(systemObjArrayKlassObj()); } @@ -1885,7 +1848,7 @@ index 8ce17d9..fe37993 100644 void Universe::oops_do(OopClosure* f, bool do_all) { f->do_oop((oop*) &_int_mirror); -@@ -1590,10 +1628,9 @@ void ActiveMethodOopsCache::add_previous_version(const methodOop method) { +@@ -1590,10 +1628,9 @@ } // RC_TRACE macro has an embedded ResourceMark @@ -1898,7 +1861,7 @@ index 8ce17d9..fe37993 100644 methodHandle method_h(method); jweak method_ref = JNIHandles::make_weak_global(method_h); -@@ -1620,9 +1657,8 @@ void ActiveMethodOopsCache::add_previous_version(const methodOop method) { +@@ -1620,9 +1657,8 @@ JNIHandles::destroy_weak_global(method_ref); _prev_methods->remove_at(i); } else { @@ -1911,10 +1874,9 @@ index 8ce17d9..fe37993 100644 } } // end add_previous_version() diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp -index da21a8b..676675e 100644 --- a/src/share/vm/memory/universe.hpp +++ b/src/share/vm/memory/universe.hpp -@@ -127,6 +127,8 @@ class Universe: AllStatic { +@@ -127,6 +127,8 @@ friend class SystemDictionary; friend class VMStructs; friend class CompactingPermGenGen; @@ -1923,7 +1885,7 @@ index da21a8b..676675e 100644 friend class VM_PopulateDumpSharedSpace; friend jint universe_init(); -@@ -258,7 +260,18 @@ class Universe: AllStatic { +@@ -258,7 +260,18 @@ static void compute_verify_oop_data(); @@ -1942,7 +1904,7 @@ index da21a8b..676675e 100644 // Known classes in the VM static klassOop boolArrayKlassObj() { return _boolArrayKlassObj; } static klassOop byteArrayKlassObj() { return _byteArrayKlassObj; } -@@ -403,6 +416,8 @@ class Universe: AllStatic { +@@ -403,6 +416,8 @@ // Iteration @@ -1951,7 +1913,7 @@ index da21a8b..676675e 100644 // Apply "f" to the addresses of all the direct heap pointers maintained // as static fields of "Universe". static void oops_do(OopClosure* f, bool do_all = false); -@@ -419,6 +434,7 @@ class Universe: AllStatic { +@@ -419,6 +434,7 @@ // Debugging static bool verify_in_progress() { return _verify_in_progress; } @@ -1960,7 +1922,6 @@ index da21a8b..676675e 100644 static void verify(bool silent) { verify(silent, VerifyOption_Default /* option */); diff --git a/src/share/vm/oops/cpCacheOop.cpp b/src/share/vm/oops/cpCacheOop.cpp -index ad62921..1cd422c 100644 --- a/src/share/vm/oops/cpCacheOop.cpp +++ b/src/share/vm/oops/cpCacheOop.cpp @@ -40,6 +40,11 @@ @@ -1975,7 +1936,7 @@ index ad62921..1cd422c 100644 assert(constant_pool_index() == index, ""); } -@@ -162,7 +167,8 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, +@@ -162,7 +167,8 @@ int vtable_index) { assert(!is_secondary_entry(), ""); assert(method->interpreter_entry() != NULL, "should have been set at this point"); @@ -1985,7 +1946,7 @@ index ad62921..1cd422c 100644 int byte_no = -1; bool change_to_virtual = false; -@@ -516,116 +522,6 @@ void ConstantPoolCacheEntry::update_pointers() { +@@ -516,116 +522,6 @@ } #endif // SERIALGC @@ -2102,7 +2063,7 @@ index ad62921..1cd422c 100644 void ConstantPoolCacheEntry::print(outputStream* st, int index) const { // print separator if (index == 0) st->print_cr(" -------------"); -@@ -663,60 +559,10 @@ void constantPoolCacheOopDesc::initialize(intArray& inverse_index_map) { +@@ -663,60 +559,10 @@ } } @@ -2166,10 +2127,9 @@ index ad62921..1cd422c 100644 - } -} diff --git a/src/share/vm/oops/cpCacheOop.hpp b/src/share/vm/oops/cpCacheOop.hpp -index ef26775..a270d0d 100644 --- a/src/share/vm/oops/cpCacheOop.hpp +++ b/src/share/vm/oops/cpCacheOop.hpp -@@ -355,17 +355,6 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { +@@ -355,17 +355,6 @@ void update_pointers(); @@ -2187,7 +2147,7 @@ index ef26775..a270d0d 100644 // Debugging & Printing void print (outputStream* st, int index) const; void verify(outputStream* st) const; -@@ -485,16 +474,8 @@ class constantPoolCacheOopDesc: public oopDesc { +@@ -485,16 +474,8 @@ return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index); } @@ -2207,10 +2167,9 @@ index ef26775..a270d0d 100644 #endif // SHARE_VM_OOPS_CPCACHEOOP_HPP diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp -index cd3dce0..666ffdf 100644 --- a/src/share/vm/oops/instanceKlass.cpp +++ b/src/share/vm/oops/instanceKlass.cpp -@@ -255,7 +255,7 @@ bool instanceKlass::verify_code( +@@ -255,7 +255,7 @@ // 1) Verify the bytecodes Verifier::Mode mode = throw_verifyerror ? Verifier::ThrowException : Verifier::NoException; @@ -2219,7 +2178,7 @@ index cd3dce0..666ffdf 100644 } -@@ -362,7 +362,13 @@ bool instanceKlass::link_class_impl( +@@ -362,7 +362,13 @@ jt->get_thread_stat()->perf_recursion_counts_addr(), jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_VERIFY); @@ -2233,7 +2192,7 @@ index cd3dce0..666ffdf 100644 if (!verify_ok) { return false; } -@@ -400,7 +406,8 @@ bool instanceKlass::link_class_impl( +@@ -400,7 +406,8 @@ } #endif this_oop->set_init_state(linked); @@ -2243,7 +2202,7 @@ index cd3dce0..666ffdf 100644 Thread *thread = THREAD; assert(thread->is_Java_thread(), "thread->is_Java_thread()"); JvmtiExport::post_class_prepare((JavaThread *) thread, this_oop()); -@@ -454,7 +461,9 @@ void instanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { +@@ -454,7 +461,9 @@ // 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. @@ -2254,7 +2213,7 @@ index cd3dce0..666ffdf 100644 wait = true; ol.waitUninterruptibly(CHECK); } -@@ -673,6 +682,18 @@ bool instanceKlass::implements_interface(klassOop k) const { +@@ -673,6 +682,18 @@ return false; } @@ -2273,7 +2232,7 @@ index cd3dce0..666ffdf 100644 objArrayOop instanceKlass::allocate_objArray(int n, int length, TRAPS) { if (length < 0) THROW_0(vmSymbols::java_lang_NegativeArraySizeException()); if (length > arrayOopDesc::max_array_length(T_OBJECT)) { -@@ -949,6 +970,18 @@ void instanceKlass::methods_do(void f(methodOop method)) { +@@ -949,6 +970,18 @@ } } @@ -2292,7 +2251,7 @@ index cd3dce0..666ffdf 100644 void instanceKlass::do_local_static_fields(FieldClosure* cl) { for (JavaFieldStream fs(this); !fs.done(); fs.next()) { -@@ -1368,6 +1401,20 @@ jmethodID instanceKlass::jmethod_id_or_null(methodOop method) { +@@ -1368,6 +1401,20 @@ return id; } @@ -2313,7 +2272,7 @@ index cd3dce0..666ffdf 100644 // Cache an itable index void instanceKlass::set_cached_itable_index(size_t idnum, int index) { -@@ -1527,6 +1574,13 @@ void instanceKlass::remove_dependent_nmethod(nmethod* nm) { +@@ -1527,6 +1574,13 @@ last = b; b = b->next(); } @@ -2327,7 +2286,7 @@ index cd3dce0..666ffdf 100644 #ifdef ASSERT tty->print_cr("### %s can't find dependent nmethod:", this->external_name()); nm->print(); -@@ -1922,16 +1976,6 @@ void instanceKlass::release_C_heap_structures() { +@@ -1922,16 +1976,6 @@ assert(breakpoints() == 0x0, "should have cleared breakpoints"); } @@ -2344,7 +2303,7 @@ index cd3dce0..666ffdf 100644 // deallocate the cached class file if (_cached_class_file_bytes != NULL) { os::free(_cached_class_file_bytes, mtClass); -@@ -2545,275 +2589,10 @@ void instanceKlass::set_init_state(ClassState state) { +@@ -2545,275 +2589,10 @@ } #endif @@ -2622,7 +2581,7 @@ index cd3dce0..666ffdf 100644 methodOop instanceKlass::method_with_idnum(int idnum) { methodOop m = NULL; -@@ -2854,153 +2633,3 @@ void instanceKlass::set_methods_annotations_of(int idnum, typeArrayOop anno, obj +@@ -2854,153 +2633,3 @@ } // if no array and idnum isn't included there is nothing to do } @@ -2777,10 +2736,9 @@ index cd3dce0..666ffdf 100644 - return NULL; -} // end next_previous_version() diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp -index 8a849cb..53163b6 100644 --- a/src/share/vm/oops/instanceKlass.hpp +++ b/src/share/vm/oops/instanceKlass.hpp -@@ -271,9 +271,6 @@ class instanceKlass: public Klass { +@@ -271,9 +271,6 @@ nmethodBucket* _dependencies; // list of dependent nmethods nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class BreakpointInfo* _breakpoints; // bpt lists, managed by methodOop @@ -2790,7 +2748,7 @@ index 8a849cb..53163b6 100644 // JVMTI fields can be moved to their own structure - see 6315920 unsigned char * _cached_class_file_bytes; // JVMTI: cached class file, before retransformable agent modified it in CFLH jint _cached_class_file_len; // JVMTI: length of above -@@ -571,20 +568,11 @@ class instanceKlass: public Klass { +@@ -571,20 +568,11 @@ _nonstatic_oop_map_size = words; } @@ -2812,7 +2770,7 @@ index 8a849cb..53163b6 100644 // JVMTI: Support for caching a class file before it is modified by an agent that can do retransformation void set_cached_class_file(unsigned char *class_file_bytes, -@@ -629,6 +617,7 @@ class instanceKlass: public Klass { +@@ -629,6 +617,7 @@ static void get_jmethod_id_length_value(jmethodID* cache, size_t idnum, size_t *length_p, jmethodID* id_p); jmethodID jmethod_id_or_null(methodOop method); @@ -2820,7 +2778,7 @@ index 8a849cb..53163b6 100644 // cached itable index support void set_cached_itable_index(size_t idnum, int index); -@@ -711,6 +700,7 @@ class instanceKlass: public Klass { +@@ -711,6 +700,7 @@ // subclass/subinterface checks bool implements_interface(klassOop k) const; @@ -2828,7 +2786,7 @@ index 8a849cb..53163b6 100644 // Access to the implementor of an interface. klassOop implementor() const -@@ -760,6 +750,9 @@ class instanceKlass: public Klass { +@@ -760,6 +750,9 @@ void do_local_static_fields(FieldClosure* cl); void do_nonstatic_fields(FieldClosure* cl); // including inherited fields void do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAPS); @@ -2838,7 +2796,7 @@ index 8a849cb..53163b6 100644 void methods_do(void f(methodOop method)); void array_klasses_do(void f(klassOop k)); -@@ -895,7 +888,6 @@ class instanceKlass: public Klass { +@@ -895,7 +888,6 @@ ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) #endif // !SERIALGC @@ -2846,7 +2804,7 @@ index 8a849cb..53163b6 100644 // initialization state #ifdef ASSERT void set_init_state(ClassState state); -@@ -1057,106 +1049,6 @@ class JNIid: public CHeapObj<mtClass> { +@@ -1057,106 +1049,6 @@ void verify(klassOop holder); }; @@ -2954,10 +2912,9 @@ index 8a849cb..53163b6 100644 // nmethodBucket is used to record dependent nmethods for // deoptimization. nmethod dependencies are actually <klass, method> diff --git a/src/share/vm/oops/instanceKlassKlass.cpp b/src/share/vm/oops/instanceKlassKlass.cpp -index 8e7dc12..5b9b266 100644 --- a/src/share/vm/oops/instanceKlassKlass.cpp +++ b/src/share/vm/oops/instanceKlassKlass.cpp -@@ -358,7 +358,7 @@ instanceKlassKlass::allocate_instance_klass(Symbol* name, int vtable_len, int it +@@ -358,7 +358,7 @@ unsigned nonstatic_oop_map_count, AccessFlags access_flags, ReferenceType rt, @@ -2966,7 +2923,7 @@ index 8e7dc12..5b9b266 100644 const int nonstatic_oop_map_size = instanceKlass::nonstatic_oop_map_size(nonstatic_oop_map_count); -@@ -435,7 +435,6 @@ instanceKlassKlass::allocate_instance_klass(Symbol* name, int vtable_len, int it +@@ -435,7 +435,6 @@ ik->set_jni_ids(NULL); ik->set_osr_nmethods_head(NULL); ik->set_breakpoints(NULL); @@ -2974,7 +2931,7 @@ index 8e7dc12..5b9b266 100644 ik->set_generic_signature(NULL); ik->release_set_methods_jmethod_ids(NULL); ik->release_set_methods_cached_itable_indices(NULL); -@@ -480,6 +479,28 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { +@@ -480,6 +479,28 @@ instanceKlass* ik = instanceKlass::cast(klassOop(obj)); klassKlass::oop_print_on(obj, st); @@ -3003,7 +2960,7 @@ index 8e7dc12..5b9b266 100644 st->print(BULLET"instance size: %d", ik->size_helper()); st->cr(); st->print(BULLET"klass size: %d", ik->object_size()); st->cr(); st->print(BULLET"access: "); ik->access_flags().print_on(st); st->cr(); -@@ -537,26 +558,6 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { +@@ -537,26 +558,6 @@ st->cr(); } @@ -3030,7 +2987,7 @@ index 8e7dc12..5b9b266 100644 if (ik->generic_signature() != NULL) { st->print(BULLET"generic signature: "); ik->generic_signature()->print_value_on(st); -@@ -663,7 +664,7 @@ void instanceKlassKlass::oop_verify_on(oop obj, outputStream* st) { +@@ -663,7 +664,7 @@ } guarantee(sib->as_klassOop()->is_klass(), "should be klass"); guarantee(sib->as_klassOop()->is_perm(), "should be in permspace"); @@ -3040,10 +2997,9 @@ index 8e7dc12..5b9b266 100644 } diff --git a/src/share/vm/oops/instanceKlassKlass.hpp b/src/share/vm/oops/instanceKlassKlass.hpp -index df674a9..45d0b66 100644 --- a/src/share/vm/oops/instanceKlassKlass.hpp +++ b/src/share/vm/oops/instanceKlassKlass.hpp -@@ -50,6 +50,7 @@ class instanceKlassKlass : public klassKlass { +@@ -50,6 +50,7 @@ AccessFlags access_flags, ReferenceType rt, KlassHandle host_klass, @@ -3052,10 +3008,9 @@ index df674a9..45d0b66 100644 // Casting from klassOop diff --git a/src/share/vm/oops/instanceMirrorKlass.cpp b/src/share/vm/oops/instanceMirrorKlass.cpp -index e0dd7d7..a7eec08 100644 --- a/src/share/vm/oops/instanceMirrorKlass.cpp +++ b/src/share/vm/oops/instanceMirrorKlass.cpp -@@ -156,6 +156,13 @@ void instanceMirrorKlass::oop_follow_contents(oop obj) { +@@ -156,6 +156,13 @@ assert_is_in_closed_subset) } @@ -3070,10 +3025,9 @@ index e0dd7d7..a7eec08 100644 void instanceMirrorKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { diff --git a/src/share/vm/oops/instanceMirrorKlass.hpp b/src/share/vm/oops/instanceMirrorKlass.hpp -index 2b8b2f4..31969c7 100644 --- a/src/share/vm/oops/instanceMirrorKlass.hpp +++ b/src/share/vm/oops/instanceMirrorKlass.hpp -@@ -79,6 +79,9 @@ class instanceMirrorKlass: public instanceKlass { +@@ -79,6 +79,9 @@ DEFINE_ALLOCATE_PERMANENT(instanceMirrorKlass); instanceOop allocate_instance(KlassHandle k, TRAPS); @@ -3084,10 +3038,9 @@ index 2b8b2f4..31969c7 100644 int oop_adjust_pointers(oop obj); void oop_follow_contents(oop obj); diff --git a/src/share/vm/oops/instanceRefKlass.cpp b/src/share/vm/oops/instanceRefKlass.cpp -index 7db4f03..1171487 100644 --- a/src/share/vm/oops/instanceRefKlass.cpp +++ b/src/share/vm/oops/instanceRefKlass.cpp -@@ -455,10 +455,13 @@ void instanceRefKlass::update_nonstatic_oop_maps(klassOop k) { +@@ -455,10 +455,13 @@ instanceKlass* ik = instanceKlass::cast(k); // Check that we have the right class @@ -3106,10 +3059,9 @@ index 7db4f03..1171487 100644 OopMapBlock* map = ik->start_of_nonstatic_oop_maps(); diff --git a/src/share/vm/oops/klass.cpp b/src/share/vm/oops/klass.cpp -index 596d5ad..a928777 100644 --- a/src/share/vm/oops/klass.cpp +++ b/src/share/vm/oops/klass.cpp -@@ -161,6 +161,13 @@ klassOop Klass::base_create_klass_oop(KlassHandle& klass, int size, +@@ -161,6 +161,13 @@ kl->set_alloc_size(0); TRACE_INIT_ID(kl); @@ -3123,7 +3075,7 @@ index 596d5ad..a928777 100644 kl->set_prototype_header(markOopDesc::prototype()); kl->set_biased_lock_revocation_count(0); kl->set_last_biased_lock_bulk_revocation_time(0); -@@ -232,7 +239,7 @@ void Klass::initialize_supers(klassOop k, TRAPS) { +@@ -232,7 +239,7 @@ set_super(NULL); oop_store_without_check((oop*) &_primary_supers[0], (oop) this->as_klassOop()); assert(super_depth() == 0, "Object must already be initialized properly"); @@ -3132,7 +3084,7 @@ index 596d5ad..a928777 100644 assert(super() == NULL || super() == SystemDictionary::Object_klass(), "initialize this only once to a non-trivial value"); set_super(k); -@@ -385,7 +392,7 @@ void Klass::append_to_sibling_list() { +@@ -385,7 +392,7 @@ void Klass::remove_from_sibling_list() { // remove receiver from sibling list instanceKlass* super = superklass(); @@ -3142,10 +3094,9 @@ index 596d5ad..a928777 100644 if (super->subklass() == this) { // first subklass diff --git a/src/share/vm/oops/klass.hpp b/src/share/vm/oops/klass.hpp -index bcbd4e7..bf242d9 100644 --- a/src/share/vm/oops/klass.hpp +++ b/src/share/vm/oops/klass.hpp -@@ -170,6 +170,7 @@ class Klass_vtbl { +@@ -170,6 +170,7 @@ void* operator new(size_t ignored, KlassHandle& klass, int size, TRAPS); }; @@ -3153,7 +3104,7 @@ index bcbd4e7..bf242d9 100644 class Klass : public Klass_vtbl { friend class VMStructs; -@@ -222,6 +223,31 @@ class Klass : public Klass_vtbl { +@@ -222,6 +223,31 @@ oop* oop_block_beg() const { return adr_secondary_super_cache(); } oop* oop_block_end() const { return adr_next_sibling() + 1; } @@ -3185,7 +3136,7 @@ index bcbd4e7..bf242d9 100644 protected: // // The oop block. All oop fields must be declared here and only oop fields -@@ -241,6 +267,10 @@ class Klass : public Klass_vtbl { +@@ -241,6 +267,10 @@ oop _java_mirror; // Superclass klassOop _super; @@ -3196,7 +3147,7 @@ index bcbd4e7..bf242d9 100644 // First subclass (NULL if none); _subklass->next_sibling() is next one klassOop _subklass; // Sibling link (or NULL); links all subklasses of a klass -@@ -253,6 +283,16 @@ class Klass : public Klass_vtbl { +@@ -253,6 +283,16 @@ jint _modifier_flags; // Processed access flags, for use by Class.getModifiers. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. @@ -3213,7 +3164,7 @@ index bcbd4e7..bf242d9 100644 #ifndef PRODUCT int _verify_count; // to avoid redundant verifies #endif -@@ -301,6 +341,75 @@ class Klass : public Klass_vtbl { +@@ -301,6 +341,75 @@ klassOop secondary_super_cache() const { return _secondary_super_cache; } void set_secondary_super_cache(klassOop k) { oop_store_without_check((oop*) &_secondary_super_cache, (oop) k); } @@ -3289,7 +3240,7 @@ index bcbd4e7..bf242d9 100644 objArrayOop secondary_supers() const { return _secondary_supers; } void set_secondary_supers(objArrayOop k) { oop_store_without_check((oop*) &_secondary_supers, (oop) k); } -@@ -361,6 +470,8 @@ class Klass : public Klass_vtbl { +@@ -361,6 +470,8 @@ void set_next_sibling(klassOop s); oop* adr_super() const { return (oop*)&_super; } @@ -3299,10 +3250,9 @@ index bcbd4e7..bf242d9 100644 oop* adr_secondary_super_cache() const { return (oop*)&_secondary_super_cache; } oop* adr_secondary_supers()const { return (oop*)&_secondary_supers; } diff --git a/src/share/vm/oops/klassKlass.cpp b/src/share/vm/oops/klassKlass.cpp -index 06809d5..1050eda 100644 --- a/src/share/vm/oops/klassKlass.cpp +++ b/src/share/vm/oops/klassKlass.cpp -@@ -68,6 +68,8 @@ void klassKlass::oop_follow_contents(oop obj) { +@@ -68,6 +68,8 @@ Klass* k = Klass::cast(klassOop(obj)); // If we are alive it is valid to keep our superclass and subtype caches alive MarkSweep::mark_and_push(k->adr_super()); @@ -3311,7 +3261,7 @@ index 06809d5..1050eda 100644 for (juint i = 0; i < Klass::primary_super_limit(); i++) MarkSweep::mark_and_push(k->adr_primary_supers()+i); MarkSweep::mark_and_push(k->adr_secondary_super_cache()); -@@ -87,6 +89,8 @@ void klassKlass::oop_follow_contents(ParCompactionManager* cm, +@@ -87,6 +89,8 @@ Klass* k = Klass::cast(klassOop(obj)); // If we are alive it is valid to keep our superclass and subtype caches alive PSParallelCompact::mark_and_push(cm, k->adr_super()); @@ -3320,7 +3270,7 @@ index 06809d5..1050eda 100644 for (juint i = 0; i < Klass::primary_super_limit(); i++) PSParallelCompact::mark_and_push(cm, k->adr_primary_supers()+i); PSParallelCompact::mark_and_push(cm, k->adr_secondary_super_cache()); -@@ -106,6 +110,8 @@ int klassKlass::oop_oop_iterate(oop obj, OopClosure* blk) { +@@ -106,6 +110,8 @@ int size = oop_size(obj); Klass* k = Klass::cast(klassOop(obj)); blk->do_oop(k->adr_super()); @@ -3329,7 +3279,7 @@ index 06809d5..1050eda 100644 for (juint i = 0; i < Klass::primary_super_limit(); i++) blk->do_oop(k->adr_primary_supers()+i); blk->do_oop(k->adr_secondary_super_cache()); -@@ -134,6 +140,10 @@ int klassKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { +@@ -134,6 +140,10 @@ oop* adr; adr = k->adr_super(); if (mr.contains(adr)) blk->do_oop(adr); @@ -3340,7 +3290,7 @@ index 06809d5..1050eda 100644 for (juint i = 0; i < Klass::primary_super_limit(); i++) { adr = k->adr_primary_supers()+i; if (mr.contains(adr)) blk->do_oop(adr); -@@ -167,6 +177,8 @@ int klassKlass::oop_adjust_pointers(oop obj) { +@@ -167,6 +177,8 @@ Klass* k = Klass::cast(klassOop(obj)); MarkSweep::adjust_pointer(k->adr_super()); @@ -3350,10 +3300,9 @@ index 06809d5..1050eda 100644 MarkSweep::adjust_pointer(k->adr_primary_supers()+i); MarkSweep::adjust_pointer(k->adr_secondary_super_cache()); diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.cpp -index 94e2e04..a683a4b 100644 --- a/src/share/vm/oops/klassVtable.cpp +++ b/src/share/vm/oops/klassVtable.cpp -@@ -628,17 +628,13 @@ void klassVtable::adjust_method_entries(methodOop* old_methods, methodOop* new_m +@@ -628,17 +628,13 @@ if (unchecked_method_at(index) == old_method) { put_method_at(new_method, index); @@ -3375,7 +3324,7 @@ index 94e2e04..a683a4b 100644 } // cannot 'break' here; see for-loop comment above. } -@@ -1008,17 +1004,13 @@ void klassItable::adjust_method_entries(methodOop* old_methods, methodOop* new_m +@@ -1008,17 +1004,13 @@ if (ime->method() == old_method) { ime->initialize(new_method); @@ -3397,7 +3346,7 @@ index 94e2e04..a683a4b 100644 } // cannot 'break' here; see for-loop comment above. } -@@ -1241,6 +1233,7 @@ void klassVtable::verify(outputStream* st, bool forced) { +@@ -1241,6 +1233,7 @@ void klassVtable::verify_against(outputStream* st, klassVtable* vt, int index) { vtableEntry* vte = &vt->table()[index]; @@ -3405,7 +3354,7 @@ index 94e2e04..a683a4b 100644 if (vte->method()->name() != table()[index].method()->name() || vte->method()->signature() != table()[index].method()->signature()) { fatal("mismatched name/signature of vtable entries"); -@@ -1260,6 +1253,8 @@ void klassVtable::print() { +@@ -1260,6 +1253,8 @@ void vtableEntry::verify(klassVtable* vt, outputStream* st) { NOT_PRODUCT(FlagSetting fs(IgnoreLockingAssertions, true)); @@ -3414,7 +3363,7 @@ index 94e2e04..a683a4b 100644 assert(method() != NULL, "must have set method"); method()->verify(); // we sub_type, because it could be a miranda method -@@ -1267,7 +1262,13 @@ void vtableEntry::verify(klassVtable* vt, outputStream* st) { +@@ -1267,7 +1262,13 @@ #ifndef PRODUCT print(); #endif @@ -3429,7 +3378,7 @@ index 94e2e04..a683a4b 100644 } } -@@ -1275,8 +1276,8 @@ void vtableEntry::verify(klassVtable* vt, outputStream* st) { +@@ -1275,8 +1276,8 @@ void vtableEntry::print() { ResourceMark rm; @@ -3440,10 +3389,9 @@ index 94e2e04..a683a4b 100644 } } diff --git a/src/share/vm/oops/methodKlass.cpp b/src/share/vm/oops/methodKlass.cpp -index 75d0b09..c4be146 100644 --- a/src/share/vm/oops/methodKlass.cpp +++ b/src/share/vm/oops/methodKlass.cpp -@@ -93,6 +93,9 @@ methodOop methodKlass::allocate(constMethodHandle xconst, +@@ -93,6 +93,9 @@ m->set_adapter_entry(NULL); m->clear_code(); // from_c/from_i get set to c2i/i2i @@ -3453,7 +3401,7 @@ index 75d0b09..c4be146 100644 if (access_flags.is_native()) { m->clear_native_function(); m->set_signature_handler(NULL); -@@ -122,6 +125,8 @@ void methodKlass::oop_follow_contents(oop obj) { +@@ -122,6 +125,8 @@ // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::methodKlassObj never moves. MarkSweep::mark_and_push(m->adr_constMethod()); @@ -3462,7 +3410,7 @@ index 75d0b09..c4be146 100644 if (m->method_data() != NULL) { MarkSweep::mark_and_push(m->adr_method_data()); } -@@ -135,6 +140,8 @@ void methodKlass::oop_follow_contents(ParCompactionManager* cm, +@@ -135,6 +140,8 @@ // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::methodKlassObj never moves. PSParallelCompact::mark_and_push(cm, m->adr_constMethod()); @@ -3471,7 +3419,7 @@ index 75d0b09..c4be146 100644 #ifdef COMPILER2 if (m->method_data() != NULL) { PSParallelCompact::mark_and_push(cm, m->adr_method_data()); -@@ -152,6 +159,8 @@ int methodKlass::oop_oop_iterate(oop obj, OopClosure* blk) { +@@ -152,6 +159,8 @@ // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::methodKlassObj never moves blk->do_oop(m->adr_constMethod()); @@ -3480,7 +3428,7 @@ index 75d0b09..c4be146 100644 if (m->method_data() != NULL) { blk->do_oop(m->adr_method_data()); } -@@ -170,6 +179,10 @@ int methodKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { +@@ -170,6 +179,10 @@ oop* adr; adr = m->adr_constMethod(); if (mr.contains(adr)) blk->do_oop(adr); @@ -3491,7 +3439,7 @@ index 75d0b09..c4be146 100644 if (m->method_data() != NULL) { adr = m->adr_method_data(); if (mr.contains(adr)) blk->do_oop(adr); -@@ -187,6 +200,8 @@ int methodKlass::oop_adjust_pointers(oop obj) { +@@ -187,6 +200,8 @@ // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::methodKlassObj never moves. MarkSweep::adjust_pointer(m->adr_constMethod()); @@ -3500,7 +3448,7 @@ index 75d0b09..c4be146 100644 if (m->method_data() != NULL) { MarkSweep::adjust_pointer(m->adr_method_data()); } -@@ -202,6 +217,8 @@ int methodKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { +@@ -202,6 +217,8 @@ assert(obj->is_method(), "should be method"); methodOop m = methodOop(obj); PSParallelCompact::adjust_pointer(m->adr_constMethod()); @@ -3509,7 +3457,7 @@ index 75d0b09..c4be146 100644 #ifdef COMPILER2 if (m->method_data() != NULL) { PSParallelCompact::adjust_pointer(m->adr_method_data()); -@@ -222,7 +239,18 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) { +@@ -222,7 +239,18 @@ methodOop m = methodOop(obj); // get the effect of PrintOopAddress, always, for methods: st->print_cr(" - this oop: "INTPTR_FORMAT, (intptr_t)m); @@ -3530,10 +3478,9 @@ index 75d0b09..c4be146 100644 m->constants()->print_value_on(st); st->cr(); st->print (" - access: 0x%x ", m->access_flags().as_int()); m->access_flags().print_on(st); st->cr(); diff --git a/src/share/vm/oops/methodOop.cpp b/src/share/vm/oops/methodOop.cpp -index 4f59d3a..32cb4cf 100644 --- a/src/share/vm/oops/methodOop.cpp +++ b/src/share/vm/oops/methodOop.cpp -@@ -1061,6 +1061,8 @@ methodHandle methodOopDesc::clone_with_new_data(methodHandle m, u_char* new_code +@@ -1061,6 +1061,8 @@ // Reset correct method/const method, method size, and parameter info newm->set_constMethod(newcm); @@ -3543,10 +3490,9 @@ index 4f59d3a..32cb4cf 100644 newm->constMethod()->set_constMethod_size(new_const_method_size); newm->set_method_size(new_method_size); diff --git a/src/share/vm/oops/methodOop.hpp b/src/share/vm/oops/methodOop.hpp -index 486e106..e35d5ed 100644 --- a/src/share/vm/oops/methodOop.hpp +++ b/src/share/vm/oops/methodOop.hpp -@@ -114,6 +114,10 @@ class methodOopDesc : public oopDesc { +@@ -114,6 +114,10 @@ AccessFlags _access_flags; // Access flags int _vtable_index; // vtable index of this method (see VtableIndexFlag) // note: can have vtables with >2**16 elements (because of inheritance) @@ -3557,7 +3503,7 @@ index 486e106..e35d5ed 100644 #ifdef CC_INTERP int _result_index; // C++ interpreter needs for converting results to/from stack #endif -@@ -175,6 +179,29 @@ class methodOopDesc : public oopDesc { +@@ -175,6 +179,29 @@ int name_index() const { return constMethod()->name_index(); } void set_name_index(int index) { constMethod()->set_name_index(index); } @@ -3587,7 +3533,7 @@ index 486e106..e35d5ed 100644 // signature Symbol* signature() const { return constants()->symbol_at(signature_index()); } int signature_index() const { return constMethod()->signature_index(); } -@@ -734,6 +761,8 @@ class methodOopDesc : public oopDesc { +@@ -734,6 +761,8 @@ // Garbage collection support oop* adr_constMethod() const { return (oop*)&_constMethod; } @@ -3597,10 +3543,9 @@ index 486e106..e35d5ed 100644 }; diff --git a/src/share/vm/oops/oop.hpp b/src/share/vm/oops/oop.hpp -index 5982c88..4873fca 100644 --- a/src/share/vm/oops/oop.hpp +++ b/src/share/vm/oops/oop.hpp -@@ -95,6 +95,7 @@ class oopDesc { +@@ -95,6 +95,7 @@ narrowOop* compressed_klass_addr(); void set_klass(klassOop k); @@ -3608,7 +3553,7 @@ index 5982c88..4873fca 100644 // For klass field compression int klass_gap() const; -@@ -135,6 +136,7 @@ class oopDesc { +@@ -135,6 +136,7 @@ bool is_array() const; bool is_objArray() const; bool is_klass() const; @@ -3617,10 +3562,9 @@ index 5982c88..4873fca 100644 bool is_method() const; bool is_constMethod() const; diff --git a/src/share/vm/oops/oop.inline.hpp b/src/share/vm/oops/oop.inline.hpp -index f4eb2f7..0acb346 100644 --- a/src/share/vm/oops/oop.inline.hpp +++ b/src/share/vm/oops/oop.inline.hpp -@@ -123,6 +123,14 @@ inline void oopDesc::set_klass(klassOop k) { +@@ -123,6 +123,14 @@ } } @@ -3635,7 +3579,7 @@ index f4eb2f7..0acb346 100644 inline int oopDesc::klass_gap() const { return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes()); } -@@ -156,6 +164,7 @@ inline bool oopDesc::is_objArray() const { return blueprint()->oop_is_ +@@ -156,6 +164,7 @@ inline bool oopDesc::is_typeArray() const { return blueprint()->oop_is_typeArray(); } inline bool oopDesc::is_javaArray() const { return blueprint()->oop_is_javaArray(); } inline bool oopDesc::is_klass() const { return blueprint()->oop_is_klass(); } @@ -3644,10 +3588,9 @@ index f4eb2f7..0acb346 100644 inline bool oopDesc::is_method() const { return blueprint()->oop_is_method(); } inline bool oopDesc::is_constMethod() const { return blueprint()->oop_is_constMethod(); } diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp -index 2123991..6cbd78c 100644 --- a/src/share/vm/prims/jni.cpp +++ b/src/share/vm/prims/jni.cpp -@@ -406,7 +406,7 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR +@@ -406,7 +406,7 @@ } } klassOop k = SystemDictionary::resolve_from_stream(class_name, class_loader, @@ -3657,10 +3600,9 @@ index 2123991..6cbd78c 100644 if (TraceClassResolution && k != NULL) { diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp -index 7dcd968..d59052f 100644 --- a/src/share/vm/prims/jvm.cpp +++ b/src/share/vm/prims/jvm.cpp -@@ -872,7 +872,7 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, +@@ -872,7 +872,7 @@ Handle protection_domain (THREAD, JNIHandles::resolve(pd)); klassOop k = SystemDictionary::resolve_from_stream(class_name, class_loader, protection_domain, &st, @@ -3670,10 +3612,9 @@ index 7dcd968..d59052f 100644 if (TraceClassResolution && k != NULL) { diff --git a/src/share/vm/prims/jvm_misc.hpp b/src/share/vm/prims/jvm_misc.hpp -index 2b46e36..549e949 100644 --- a/src/share/vm/prims/jvm_misc.hpp +++ b/src/share/vm/prims/jvm_misc.hpp -@@ -84,6 +84,7 @@ extern "C" { +@@ -84,6 +84,7 @@ (JNIEnv *env, jobject obj, jfieldID fieldID); } @@ -3682,10 +3623,9 @@ index 2b46e36..549e949 100644 address jni_GetBooleanField_addr(); address jni_GetByteField_addr(); diff --git a/src/share/vm/prims/jvmtiEnv.cpp b/src/share/vm/prims/jvmtiEnv.cpp -index 4ac6b82..30b8e84 100644 --- a/src/share/vm/prims/jvmtiEnv.cpp +++ b/src/share/vm/prims/jvmtiEnv.cpp -@@ -290,7 +290,10 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) { +@@ -290,7 +290,10 @@ class_definitions[index].klass = jcls; } VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform); @@ -3697,7 +3637,7 @@ index 4ac6b82..30b8e84 100644 return (op.check_error()); } /* end RetransformClasses */ -@@ -299,9 +302,12 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) { +@@ -299,9 +302,12 @@ // class_definitions - pre-checked for NULL jvmtiError JvmtiEnv::RedefineClasses(jint class_count, const jvmtiClassDefinition* class_definitions) { @@ -3713,10 +3653,9 @@ index 4ac6b82..30b8e84 100644 } /* end RedefineClasses */ diff --git a/src/share/vm/prims/jvmtiExport.cpp b/src/share/vm/prims/jvmtiExport.cpp -index ec8ede3..2bd5983 100644 --- a/src/share/vm/prims/jvmtiExport.cpp +++ b/src/share/vm/prims/jvmtiExport.cpp -@@ -2296,7 +2296,7 @@ JvmtiDynamicCodeEventCollector::JvmtiDynamicCodeEventCollector() : _code_blobs(N +@@ -2296,7 +2296,7 @@ // iterate over any code blob descriptors collected and post a // DYNAMIC_CODE_GENERATED event to the profiler. JvmtiDynamicCodeEventCollector::~JvmtiDynamicCodeEventCollector() { @@ -3726,10 +3665,9 @@ index ec8ede3..2bd5983 100644 if (_code_blobs != NULL) { for (int i=0; i<_code_blobs->length(); i++) { diff --git a/src/share/vm/prims/jvmtiImpl.cpp b/src/share/vm/prims/jvmtiImpl.cpp -index d3fa140..31a8a19 100644 --- a/src/share/vm/prims/jvmtiImpl.cpp +++ b/src/share/vm/prims/jvmtiImpl.cpp -@@ -284,60 +284,11 @@ address JvmtiBreakpoint::getBcp() { +@@ -284,60 +284,11 @@ } void JvmtiBreakpoint::each_method_version_do(method_action meth_act) { @@ -3796,7 +3734,6 @@ index d3fa140..31a8a19 100644 void JvmtiBreakpoint::set() { diff --git a/src/share/vm/prims/jvmtiRedefineClasses.cpp b/src/share/vm/prims/jvmtiRedefineClasses.cpp -index eb52388..432e15a 100644 --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1,5 +1,5 @@ @@ -3806,7 +3743,7 @@ index eb52388..432e15a 100644 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it -@@ -38,490 +38,669 @@ +@@ -38,460 +38,55 @@ #include "runtime/deoptimization.hpp" #include "runtime/relocator.hpp" #include "utilities/bitMap.inline.hpp" @@ -3852,10 +3789,103 @@ index eb52388..432e15a 100644 - if (_class_count == 0) { - _res = JVMTI_ERROR_NONE; - return false; +- } +- if (_class_defs == NULL) { +- _res = JVMTI_ERROR_NULL_POINTER; +- return false; +- } +- for (int i = 0; i < _class_count; i++) { +- if (_class_defs[i].klass == NULL) { +- _res = JVMTI_ERROR_INVALID_CLASS; +- return false; +- } +- if (_class_defs[i].class_byte_count == 0) { +- _res = JVMTI_ERROR_INVALID_CLASS_FORMAT; +- return false; +- } +- if (_class_defs[i].class_bytes == NULL) { +- _res = JVMTI_ERROR_NULL_POINTER; +- return false; +- } +- } +VM_RedefineClasses::~VM_RedefineClasses() { + unlock_threads(); + RC_TIMER_STOP(_timer_total); -+ + +- // Start timer after all the sanity checks; not quite accurate, but +- // better than adding a bunch of stop() calls. +- RC_TIMER_START(_timer_vm_op_prologue); +- +- // 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()); +- if (_res != JVMTI_ERROR_NONE) { +- // Free os::malloc allocated memory in load_new_class_version. +- os::free(_scratch_classes); +- RC_TIMER_STOP(_timer_vm_op_prologue); +- return false; +- } +- +- RC_TIMER_STOP(_timer_vm_op_prologue); +- return true; +-} +- +-void VM_RedefineClasses::doit() { +- Thread *thread = Thread::current(); +- +- if (UseSharedSpaces) { +- // Sharing is enabled so we remap the shared readonly space to +- // 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()) { +- RC_TRACE_WITH_THREAD(0x00000001, thread, +- ("failed to remap shared readonly space to readwrite, private")); +- _res = JVMTI_ERROR_INTERNAL; +- return; +- } +- } +- +- for (int i = 0; i < _class_count; i++) { +- redefine_single_class(_class_defs[i].klass, _scratch_classes[i], thread); +- } +- // Disable any dependent concurrent compilations +- SystemDictionary::notice_modification(); +- +- // Set flag indicating that some invariants are no longer true. +- // See jvmtiExport.hpp for detailed explanation. +- JvmtiExport::set_has_redefined_a_class(); +- +-// check_class() is optionally called for product bits, but is +-// always called for non-product bits. +-#ifdef PRODUCT +- if (RC_TRACE_ENABLED(0x00004000)) { +-#endif +- RC_TRACE_WITH_THREAD(0x00004000, thread, ("calling check_class")); +- SystemDictionary::classes_do(check_class, thread); +-#ifdef PRODUCT +- } +-#endif +-} +- +-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)) { +- // Used to have separate timers for "doit" and "all", but the timer +- // overhead skewed the measurements. +- jlong doit_time = _timer_rsc_phase1.milliseconds() + +- _timer_rsc_phase2.milliseconds(); +- jlong all_time = _timer_vm_op_prologue.milliseconds() + doit_time; +- +- RC_TRACE(0x00000004, ("vm_op: all=" UINT64_FORMAT +- " prologue=" UINT64_FORMAT " doit=" UINT64_FORMAT, all_time, +- _timer_vm_op_prologue.milliseconds(), doit_time)); +- RC_TRACE(0x00000004, +- ("redefine_single_class: phase1=" UINT64_FORMAT " phase2=" UINT64_FORMAT, +- _timer_rsc_phase1.milliseconds(), _timer_rsc_phase2.milliseconds())); + if (TimeRedefineClasses) { + tty->print_cr(""); + tty->print_cr("Timing Prologue: %d", _timer_prologue.milliseconds()); @@ -3870,46 +3900,359 @@ index eb52388..432e15a 100644 + tty->print_cr("Total Time: %d", _timer_total.milliseconds()); + tty->print_cr(""); } -- if (_class_defs == NULL) { -- _res = JVMTI_ERROR_NULL_POINTER; + } + +-bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) { +- // classes for primitives cannot be redefined +- if (java_lang_Class::is_primitive(klass_mirror)) { - return false; -+} -+ -+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); -+} -+ +- } +- klassOop the_class_oop = java_lang_Class::as_klassOop(klass_mirror); +- // classes for arrays cannot be redefined +- if (the_class_oop == NULL || !Klass::cast(the_class_oop)->oop_is_instance()) { +- return false; +- } +- return true; +-} +- +-// Append the current entry at scratch_i in scratch_cp to *merge_cp_p +-// where the end of *merge_cp_p is specified by *merge_cp_length_p. For +-// direct CP entries, there is just the current entry to append. For +-// indirect and double-indirect CP entries, there are zero or more +-// referenced CP entries along with the current entry to append. +-// Indirect and double-indirect CP entries are handled by recursive +-// calls to append_entry() as needed. The referenced CP entries are +-// always appended to *merge_cp_p before the referee CP entry. These +-// referenced CP entries may already exist in *merge_cp_p in which case +-// there is nothing extra to append and only the current entry is +-// appended. +-void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp, +- int scratch_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, +- TRAPS) { +- +- // append is different depending on entry tag type +- switch (scratch_cp->tag_at(scratch_i).value()) { +- +- // The old verifier is implemented outside the VM. It loads classes, +- // but does not resolve constant pool entries directly so we never +- // see Class entries here with the old verifier. Similarly the old +- // verifier does not like Class entries in the input constant pool. +- // The split-verifier is implemented in the VM so it can optionally +- // and directly resolve constant pool entries to load classes. The +- // split-verifier can accept either Class entries or UnresolvedClass +- // entries in the input constant pool. We revert the appended copy +- // back to UnresolvedClass so that either verifier will be happy +- // with the constant pool entry. +- case JVM_CONSTANT_Class: +- { +- // revert the copy to JVM_CONSTANT_UnresolvedClass +- (*merge_cp_p)->unresolved_klass_at_put(*merge_cp_length_p, +- scratch_cp->klass_name_at(scratch_i)); +- +- if (scratch_i != *merge_cp_length_p) { +- // The new entry in *merge_cp_p is at a different index than +- // the new entry in scratch_cp so we need to map the index values. +- map_index(scratch_cp, scratch_i, *merge_cp_length_p); +- } +- (*merge_cp_length_p)++; +- } break; +- +- // these are direct CP entries so they can be directly appended, +- // but double and long take two constant pool entries +- 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, +- THREAD); +- +- if (scratch_i != *merge_cp_length_p) { +- // The new entry in *merge_cp_p is at a different index than +- // the new entry in scratch_cp so we need to map the index values. +- map_index(scratch_cp, scratch_i, *merge_cp_length_p); +- } +- (*merge_cp_length_p) += 2; +- } break; +- +- // these are direct CP entries so they can be directly appended +- case JVM_CONSTANT_Float: // fall through +- case JVM_CONSTANT_Integer: // fall through +- 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. +- 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, +- THREAD); +- +- if (scratch_i != *merge_cp_length_p) { +- // The new entry in *merge_cp_p is at a different index than +- // the new entry in scratch_cp so we need to map the index values. +- map_index(scratch_cp, scratch_i, *merge_cp_length_p); +- } +- (*merge_cp_length_p)++; +- } break; +- +- // this is an indirect CP entry so it needs special handling +- case JVM_CONSTANT_NameAndType: +- { +- int name_ref_i = scratch_cp->name_ref_index_at(scratch_i); +- int new_name_ref_i = 0; +- bool match = (name_ref_i < *merge_cp_length_p) && +- scratch_cp->compare_entry_to(name_ref_i, *merge_cp_p, name_ref_i, +- THREAD); +- if (!match) { +- // forward reference in *merge_cp_p or not a direct match +- +- int found_i = scratch_cp->find_matching_entry(name_ref_i, *merge_cp_p, +- THREAD); +- if (found_i != 0) { +- guarantee(found_i != name_ref_i, +- "compare_entry_to() and find_matching_entry() do not agree"); +- +- // Found a matching entry somewhere else in *merge_cp_p so +- // just need a mapping entry. +- new_name_ref_i = found_i; +- map_index(scratch_cp, name_ref_i, found_i); +- } else { +- // no match found so we have to append this entry to *merge_cp_p +- append_entry(scratch_cp, name_ref_i, merge_cp_p, merge_cp_length_p, +- THREAD); +- // The above call to append_entry() can only append one entry +- // so the post call query of *merge_cp_length_p is only for +- // the sake of consistency. +- new_name_ref_i = *merge_cp_length_p - 1; +- } +- } +- +- int signature_ref_i = scratch_cp->signature_ref_index_at(scratch_i); +- int new_signature_ref_i = 0; +- match = (signature_ref_i < *merge_cp_length_p) && +- scratch_cp->compare_entry_to(signature_ref_i, *merge_cp_p, +- signature_ref_i, THREAD); +- if (!match) { +- // forward reference in *merge_cp_p or not a direct match +- +- int found_i = scratch_cp->find_matching_entry(signature_ref_i, +- *merge_cp_p, THREAD); +- if (found_i != 0) { +- guarantee(found_i != signature_ref_i, +- "compare_entry_to() and find_matching_entry() do not agree"); +- +- // Found a matching entry somewhere else in *merge_cp_p so +- // just need a mapping entry. +- new_signature_ref_i = found_i; +- map_index(scratch_cp, signature_ref_i, found_i); +- } else { +- // no match found so we have to append this entry to *merge_cp_p +- append_entry(scratch_cp, signature_ref_i, merge_cp_p, +- merge_cp_length_p, THREAD); +- // The above call to append_entry() can only append one entry +- // so the post call query of *merge_cp_length_p is only for +- // the sake of consistency. +- new_signature_ref_i = *merge_cp_length_p - 1; +- } +- } +- +- // If the referenced entries already exist in *merge_cp_p, then +- // both new_name_ref_i and new_signature_ref_i will both be 0. +- // In that case, all we are appending is the current entry. +- if (new_name_ref_i == 0) { +- new_name_ref_i = name_ref_i; +- } else { +- RC_TRACE(0x00080000, +- ("NameAndType entry@%d name_ref_index change: %d to %d", +- *merge_cp_length_p, name_ref_i, new_name_ref_i)); +- } +- if (new_signature_ref_i == 0) { +- new_signature_ref_i = signature_ref_i; +- } else { +- RC_TRACE(0x00080000, +- ("NameAndType entry@%d signature_ref_index change: %d to %d", +- *merge_cp_length_p, signature_ref_i, new_signature_ref_i)); +- } +- +- (*merge_cp_p)->name_and_type_at_put(*merge_cp_length_p, +- new_name_ref_i, new_signature_ref_i); +- if (scratch_i != *merge_cp_length_p) { +- // The new entry in *merge_cp_p is at a different index than +- // the new entry in scratch_cp so we need to map the index values. +- map_index(scratch_cp, scratch_i, *merge_cp_length_p); +- } +- (*merge_cp_length_p)++; +- } break; +- +- // this is a double-indirect CP entry so it needs special handling +- case JVM_CONSTANT_Fieldref: // fall through +- case JVM_CONSTANT_InterfaceMethodref: // fall through +- case JVM_CONSTANT_Methodref: +- { +- int klass_ref_i = scratch_cp->uncached_klass_ref_index_at(scratch_i); +- int new_klass_ref_i = 0; +- bool match = (klass_ref_i < *merge_cp_length_p) && +- scratch_cp->compare_entry_to(klass_ref_i, *merge_cp_p, klass_ref_i, +- THREAD); +- if (!match) { +- // forward reference in *merge_cp_p or not a direct match +- +- int found_i = scratch_cp->find_matching_entry(klass_ref_i, *merge_cp_p, +- THREAD); +- if (found_i != 0) { +- guarantee(found_i != klass_ref_i, +- "compare_entry_to() and find_matching_entry() do not agree"); +- +- // Found a matching entry somewhere else in *merge_cp_p so +- // just need a mapping entry. +- new_klass_ref_i = found_i; +- map_index(scratch_cp, klass_ref_i, found_i); +- } else { +- // no match found so we have to append this entry to *merge_cp_p +- append_entry(scratch_cp, klass_ref_i, merge_cp_p, merge_cp_length_p, +- THREAD); +- // The above call to append_entry() can only append one entry +- // so the post call query of *merge_cp_length_p is only for +- // the sake of consistency. Without the optimization where we +- // use JVM_CONSTANT_UnresolvedClass, then up to two entries +- // could be appended. +- new_klass_ref_i = *merge_cp_length_p - 1; +- } +- } +- +- int name_and_type_ref_i = +- scratch_cp->uncached_name_and_type_ref_index_at(scratch_i); +- int new_name_and_type_ref_i = 0; +- match = (name_and_type_ref_i < *merge_cp_length_p) && +- scratch_cp->compare_entry_to(name_and_type_ref_i, *merge_cp_p, +- name_and_type_ref_i, THREAD); +- if (!match) { +- // forward reference in *merge_cp_p or not a direct match +- +- int found_i = scratch_cp->find_matching_entry(name_and_type_ref_i, +- *merge_cp_p, THREAD); +- if (found_i != 0) { +- guarantee(found_i != name_and_type_ref_i, +- "compare_entry_to() and find_matching_entry() do not agree"); +- +- // Found a matching entry somewhere else in *merge_cp_p so +- // just need a mapping entry. +- new_name_and_type_ref_i = found_i; +- map_index(scratch_cp, name_and_type_ref_i, found_i); +- } else { +- // no match found so we have to append this entry to *merge_cp_p +- append_entry(scratch_cp, name_and_type_ref_i, merge_cp_p, +- merge_cp_length_p, THREAD); +- // The above call to append_entry() can append more than +- // one entry so the post call query of *merge_cp_length_p +- // is required in order to get the right index for the +- // JVM_CONSTANT_NameAndType entry. +- new_name_and_type_ref_i = *merge_cp_length_p - 1; +- } +- } +- +- // If the referenced entries already exist in *merge_cp_p, then +- // both new_klass_ref_i and new_name_and_type_ref_i will both be +- // 0. In that case, all we are appending is the current entry. +- if (new_klass_ref_i == 0) { +- new_klass_ref_i = klass_ref_i; +- } +- if (new_name_and_type_ref_i == 0) { +- new_name_and_type_ref_i = name_and_type_ref_i; +- } +- +- const char *entry_name; +- switch (scratch_cp->tag_at(scratch_i).value()) { +- case JVM_CONSTANT_Fieldref: +- entry_name = "Fieldref"; +- (*merge_cp_p)->field_at_put(*merge_cp_length_p, new_klass_ref_i, +- new_name_and_type_ref_i); +- break; +- case JVM_CONSTANT_InterfaceMethodref: +- entry_name = "IFMethodref"; +- (*merge_cp_p)->interface_method_at_put(*merge_cp_length_p, +- new_klass_ref_i, new_name_and_type_ref_i); +- break; +- case JVM_CONSTANT_Methodref: +- entry_name = "Methodref"; +- (*merge_cp_p)->method_at_put(*merge_cp_length_p, new_klass_ref_i, +- new_name_and_type_ref_i); +- break; +- default: +- guarantee(false, "bad switch"); +- break; +- } +- +- if (klass_ref_i != new_klass_ref_i) { +- RC_TRACE(0x00080000, ("%s entry@%d class_index changed: %d to %d", +- entry_name, *merge_cp_length_p, klass_ref_i, new_klass_ref_i)); +- } +- if (name_and_type_ref_i != new_name_and_type_ref_i) { +- RC_TRACE(0x00080000, +- ("%s entry@%d name_and_type_index changed: %d to %d", +- entry_name, *merge_cp_length_p, name_and_type_ref_i, +- new_name_and_type_ref_i)); +- } +- +- if (scratch_i != *merge_cp_length_p) { +- // The new entry in *merge_cp_p is at a different index than +- // the new entry in scratch_cp so we need to map the index values. +- map_index(scratch_cp, scratch_i, *merge_cp_length_p); +- } +- (*merge_cp_length_p)++; +- } break; +- +- // At this stage, Class or UnresolvedClass could be here, but not +- // ClassIndex +- case JVM_CONSTANT_ClassIndex: // fall through +- +- // Invalid is used as the tag for the second constant pool entry +- // occupied by JVM_CONSTANT_Double or JVM_CONSTANT_Long. It should +- // not be seen by itself. +- case JVM_CONSTANT_Invalid: // fall through +- +- // At this stage, String or UnresolvedString could be here, but not +- // StringIndex +- case JVM_CONSTANT_StringIndex: // fall through +- +- // At this stage JVM_CONSTANT_UnresolvedClassInError should not be +- // here +- case JVM_CONSTANT_UnresolvedClassInError: // fall through +- +- default: +- { +- // leave a breadcrumb +- jbyte bad_value = scratch_cp->tag_at(scratch_i).value(); +- ShouldNotReachHere(); +- } break; +- } // end switch tag value +-} // end append_entry() +- +- + void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class) { + typeArrayOop save; + +@@ -508,20 +103,604 @@ + scratch_class->set_method_default_annotations_of(j, save); + } + +void VM_RedefineClasses::add_affected_klasses( klassOop klass ) +{ + assert(!_affected_klasses->contains(klass), "must not occur more than once!"); + assert(klass->klass_part()->new_version() == NULL, "Only last version is valid entry in system dictionary"); -+ + +-jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( +- instanceKlassHandle the_class, +- instanceKlassHandle scratch_class) { + Klass* k = klass->klass_part(); + + if (k->check_redefinition_flag(Klass::MarkedAsAffected)) { + _affected_klasses->append(klass); + return; - } -- for (int i = 0; i < _class_count; i++) { -- if (_class_defs[i].klass == NULL) { -- _res = JVMTI_ERROR_INVALID_CLASS; -- return false; -- } -- if (_class_defs[i].class_byte_count == 0) { -- _res = JVMTI_ERROR_INVALID_CLASS_FORMAT; -- return false; ++ } + + for (juint i = 0; i < k->super_depth(); i++) { + klassOop primary_oop = k->primary_super_of_depth(i); @@ -3921,10 +4264,7 @@ index eb52388..432e15a 100644 + k->set_redefinition_flag(Klass::MarkedAsAffected); + _affected_klasses->append(klass); + return; - } -- if (_class_defs[i].class_bytes == NULL) { -- _res = JVMTI_ERROR_NULL_POINTER; -- return false; ++ } + } + + // Check secondary supers @@ -3936,22 +4276,11 @@ index eb52388..432e15a 100644 + k->set_redefinition_flag(Klass::MarkedAsAffected); + _affected_klasses->append(klass); + return; - } - } ++ } ++ } +} - -- // Start timer after all the sanity checks; not quite accurate, but -- // better than adding a bunch of stop() calls. -- RC_TIMER_START(_timer_vm_op_prologue); - -- // 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()); -- if (_res != JVMTI_ERROR_NONE) { -- // Free os::malloc allocated memory in load_new_class_version. -- os::free(_scratch_classes); -- RC_TIMER_STOP(_timer_vm_op_prologue); -- return false; ++ ++ +// Searches for all affected classes and performs a sorting such that a supertype is always before a subtype. +jvmtiError VM_RedefineClasses::find_sorted_affected_classes() { + @@ -3961,10 +4290,8 @@ index eb52388..432e15a 100644 + instanceKlassHandle klass_handle(Thread::current(), java_lang_Class::as_klassOop(mirror)); + klass_handle->set_redefinition_flag(Klass::MarkedAsAffected); + assert(klass_handle->new_version() == NULL, "Must be new class"); - } - -- RC_TIMER_STOP(_timer_vm_op_prologue); -- return true; ++ } ++ + // Find classes not directly redefined, but affected by a redefinition (because one of its supertypes is redefined) + SystemDictionary::classes_do(VM_RedefineClasses::add_affected_klasses); + TRACE_RC1("%d classes affected", _affected_klasses->length()); @@ -3979,23 +4306,11 @@ index eb52388..432e15a 100644 + } + + return result; - } - --void VM_RedefineClasses::doit() { -- Thread *thread = Thread::current(); ++} ++ +// Searches for the class bytes of the given class and returns them as a byte array. +jvmtiError VM_RedefineClasses::find_class_bytes(instanceKlassHandle the_class, const unsigned char **class_bytes, jint *class_byte_count, jboolean *not_changed) { - -- if (UseSharedSpaces) { -- // Sharing is enabled so we remap the shared readonly space to -- // 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()) { -- RC_TRACE_WITH_THREAD(0x00000001, thread, -- ("failed to remap shared readonly space to readwrite, private")); -- _res = JVMTI_ERROR_INTERNAL; -- return; ++ + *not_changed = false; + + // Search for the index in the redefinition array that corresponds to the current class @@ -4005,29 +4320,13 @@ index eb52388..432e15a 100644 + klassOop the_class_oop = java_lang_Class::as_klassOop(mirror); + if (the_class_oop == the_class()) { + break; - } - } - -- for (int i = 0; i < _class_count; i++) { -- redefine_single_class(_class_defs[i].klass, _scratch_classes[i], thread); -- } -- // Disable any dependent concurrent compilations -- SystemDictionary::notice_modification(); ++ } ++ } ++ + if (j == _class_count) { - -- // Set flag indicating that some invariants are no longer true. -- // See jvmtiExport.hpp for detailed explanation. -- JvmtiExport::set_has_redefined_a_class(); ++ + *not_changed = true; - --// check_class() is optionally called for product bits, but is --// always called for non-product bits. --#ifdef PRODUCT -- if (RC_TRACE_ENABLED(0x00004000)) { --#endif -- RC_TRACE_WITH_THREAD(0x00004000, thread, ("calling check_class")); -- SystemDictionary::classes_do(check_class, thread); --#ifdef PRODUCT ++ + // Redefine with same bytecodes. This is a class that is only indirectly affected by redefinition, + // so the user did not specify a different bytecode for that class. + @@ -4061,30 +4360,11 @@ index eb52388..432e15a 100644 + // Redefine with bytecodes at index j + *class_bytes = _class_defs[j].class_bytes; + *class_byte_count = _class_defs[j].class_byte_count; - } --#endif ++ } + + return JVMTI_ERROR_NONE; - } - --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)) { -- // Used to have separate timers for "doit" and "all", but the timer -- // overhead skewed the measurements. -- jlong doit_time = _timer_rsc_phase1.milliseconds() + -- _timer_rsc_phase2.milliseconds(); -- jlong all_time = _timer_vm_op_prologue.milliseconds() + doit_time; -- -- RC_TRACE(0x00000004, ("vm_op: all=" UINT64_FORMAT -- " prologue=" UINT64_FORMAT " doit=" UINT64_FORMAT, all_time, -- _timer_vm_op_prologue.milliseconds(), doit_time)); -- RC_TRACE(0x00000004, -- ("redefine_single_class: phase1=" UINT64_FORMAT " phase2=" UINT64_FORMAT, -- _timer_rsc_phase1.milliseconds(), _timer_rsc_phase2.milliseconds())); ++} ++ +// Prologue of the VM operation, called on the Java thread in parallel to normal program execution +bool VM_RedefineClasses::doit_prologue() { + @@ -4098,12 +4378,8 @@ index eb52388..432e15a 100644 + if (!check_arguments()) { + RC_TIMER_STOP(_timer_prologue); + return false; - } --} - --bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) { -- // classes for primitives cannot be redefined -- if (java_lang_Class::is_primitive(klass_mirror)) { ++ } ++ + // 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. + _new_classes = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<instanceKlassHandle>(5, true); @@ -4122,11 +4398,8 @@ index eb52388..432e15a 100644 + delete _affected_klasses; + _affected_klasses = NULL; + RC_TIMER_STOP(_timer_prologue); - return false; - } -- klassOop the_class_oop = java_lang_Class::as_klassOop(klass_mirror); -- // classes for arrays cannot be redefined -- if (the_class_oop == NULL || !Klass::cast(the_class_oop)->oop_is_instance()) { ++ return false; ++ } + + TRACE_RC2("nearly finished"); + VM_GC_Operation::doit_prologue(); @@ -4151,52 +4424,11 @@ index eb52388..432e15a 100644 + jvmtiError error = check_arguments_error(); + if (error != JVMTI_ERROR_NONE || _class_count == 0) { + _result = error; - return false; - } - return true; - } - --// Append the current entry at scratch_i in scratch_cp to *merge_cp_p --// where the end of *merge_cp_p is specified by *merge_cp_length_p. For --// direct CP entries, there is just the current entry to append. For --// indirect and double-indirect CP entries, there are zero or more --// referenced CP entries along with the current entry to append. --// Indirect and double-indirect CP entries are handled by recursive --// calls to append_entry() as needed. The referenced CP entries are --// always appended to *merge_cp_p before the referee CP entry. These --// referenced CP entries may already exist in *merge_cp_p in which case --// there is nothing extra to append and only the current entry is --// appended. --void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp, -- int scratch_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, -- TRAPS) { -- -- // append is different depending on entry tag type -- switch (scratch_cp->tag_at(scratch_i).value()) { -- -- // The old verifier is implemented outside the VM. It loads classes, -- // but does not resolve constant pool entries directly so we never -- // see Class entries here with the old verifier. Similarly the old -- // verifier does not like Class entries in the input constant pool. -- // The split-verifier is implemented in the VM so it can optionally -- // and directly resolve constant pool entries to load classes. The -- // split-verifier can accept either Class entries or UnresolvedClass -- // entries in the input constant pool. We revert the appended copy -- // back to UnresolvedClass so that either verifier will be happy -- // with the constant pool entry. -- case JVM_CONSTANT_Class: -- { -- // revert the copy to JVM_CONSTANT_UnresolvedClass -- (*merge_cp_p)->unresolved_klass_at_put(*merge_cp_length_p, -- scratch_cp->klass_name_at(scratch_i)); -- -- if (scratch_i != *merge_cp_length_p) { -- // The new entry in *merge_cp_p is at a different index than -- // the new entry in scratch_cp so we need to map the index values. -- map_index(scratch_cp, scratch_i, *merge_cp_length_p); -- } -- (*merge_cp_length_p)++; -- } break; ++ return false; ++ } ++ return true; ++} ++ +jvmtiError VM_RedefineClasses::check_exception() const { + Thread* THREAD = Thread::current(); + if (HAS_PENDING_EXCEPTION) { @@ -4225,82 +4457,15 @@ index eb52388..432e15a 100644 + return JVMTI_ERROR_FAILS_VERIFICATION; + } + } - -- // these are direct CP entries so they can be directly appended, -- // but double and long take two constant pool entries -- 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, -- THREAD); ++ + return JVMTI_ERROR_NONE; +} - -- if (scratch_i != *merge_cp_length_p) { -- // The new entry in *merge_cp_p is at a different index than -- // the new entry in scratch_cp so we need to map the index values. -- map_index(scratch_cp, scratch_i, *merge_cp_length_p); -- } -- (*merge_cp_length_p) += 2; -- } break; -- -- // these are direct CP entries so they can be directly appended -- case JVM_CONSTANT_Float: // fall through -- case JVM_CONSTANT_Integer: // fall through -- 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. -- 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, -- THREAD); ++ +// Loads all new class versions and stores the instanceKlass handles in an array. +jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) { - -- if (scratch_i != *merge_cp_length_p) { -- // The new entry in *merge_cp_p is at a different index than -- // the new entry in scratch_cp so we need to map the index values. -- map_index(scratch_cp, scratch_i, *merge_cp_length_p); -- } -- (*merge_cp_length_p)++; -- } break; ++ + ResourceMark rm(THREAD); - -- // this is an indirect CP entry so it needs special handling -- case JVM_CONSTANT_NameAndType: -- { -- int name_ref_i = scratch_cp->name_ref_index_at(scratch_i); -- int new_name_ref_i = 0; -- bool match = (name_ref_i < *merge_cp_length_p) && -- scratch_cp->compare_entry_to(name_ref_i, *merge_cp_p, name_ref_i, -- THREAD); -- if (!match) { -- // forward reference in *merge_cp_p or not a direct match -- -- int found_i = scratch_cp->find_matching_entry(name_ref_i, *merge_cp_p, -- THREAD); -- if (found_i != 0) { -- guarantee(found_i != name_ref_i, -- "compare_entry_to() and find_matching_entry() do not agree"); -- -- // Found a matching entry somewhere else in *merge_cp_p so -- // just need a mapping entry. -- new_name_ref_i = found_i; -- map_index(scratch_cp, name_ref_i, found_i); -- } else { -- // no match found so we have to append this entry to *merge_cp_p -- append_entry(scratch_cp, name_ref_i, merge_cp_p, merge_cp_length_p, -- THREAD); -- // The above call to append_entry() can only append one entry -- // so the post call query of *merge_cp_length_p is only for -- // the sake of consistency. -- new_name_ref_i = *merge_cp_length_p - 1; ++ + TRACE_RC1("==================================================================="); + TRACE_RC1("redefinition started by thread \"%s\"", THREAD->name()); + TRACE_RC1("load new class versions (%d)", _class_count); @@ -4402,57 +4567,21 @@ index eb52388..432e15a 100644 + while (subklass != NULL) { + assert(subklass->new_version() == NULL, "Most recent version of class!"); + subklass = subklass->next_sibling(); - } ++ } + } else { + // This can happen for reflection generated classes.. ? + CLEAR_PENDING_EXCEPTION; - } ++ } + } - -- int signature_ref_i = scratch_cp->signature_ref_index_at(scratch_i); -- int new_signature_ref_i = 0; -- match = (signature_ref_i < *merge_cp_length_p) && -- scratch_cp->compare_entry_to(signature_ref_i, *merge_cp_p, -- signature_ref_i, THREAD); -- if (!match) { -- // forward reference in *merge_cp_p or not a direct match -- -- int found_i = scratch_cp->find_matching_entry(signature_ref_i, -- *merge_cp_p, THREAD); -- if (found_i != 0) { -- guarantee(found_i != signature_ref_i, -- "compare_entry_to() and find_matching_entry() do not agree"); -- -- // Found a matching entry somewhere else in *merge_cp_p so -- // just need a mapping entry. -- new_signature_ref_i = found_i; -- map_index(scratch_cp, signature_ref_i, found_i); -- } else { -- // no match found so we have to append this entry to *merge_cp_p -- append_entry(scratch_cp, signature_ref_i, merge_cp_p, -- merge_cp_length_p, THREAD); -- // The above call to append_entry() can only append one entry -- // so the post call query of *merge_cp_length_p is only for -- // the sake of consistency. -- new_signature_ref_i = *merge_cp_length_p - 1; -- } ++ +#endif + + IF_TRACE_RC1 { + if (new_class->layout_helper() != the_class->layout_helper()) { + TRACE_RC1("Instance size change for class %s: new=%d old=%d", new_class->name()->as_C_string(), new_class->layout_helper(), the_class->layout_helper()); - } ++ } + } - -- // If the referenced entries already exist in *merge_cp_p, then -- // both new_name_ref_i and new_signature_ref_i will both be 0. -- // In that case, all we are appending is the current entry. -- if (new_name_ref_i == 0) { -- new_name_ref_i = name_ref_i; -- } else { -- RC_TRACE(0x00080000, -- ("NameAndType entry@%d name_ref_index change: %d to %d", -- *merge_cp_length_p, name_ref_i, new_name_ref_i)); ++ + // Set the new version of the class + new_class->set_revision_number(_revision_number); + new_class->set_redefinition_index(i); @@ -4471,29 +4600,17 @@ index eb52388..432e15a 100644 + TRACE_RC1("Remove super type is not allowed"); + result = JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; + break; - } -- if (new_signature_ref_i == 0) { -- new_signature_ref_i = signature_ref_i; -- } else { -- RC_TRACE(0x00080000, -- ("NameAndType entry@%d signature_ref_index change: %d to %d", -- *merge_cp_length_p, signature_ref_i, new_signature_ref_i)); ++ } + } else { + jvmtiError allowed = check_redefinition_allowed(new_class); + if (allowed != JVMTI_ERROR_NONE) { + TRACE_RC1("Error redefinition not allowed!"); + result = allowed; + break; - } ++ } + redefinition_flags = Klass::ModifyClass; + } - -- (*merge_cp_p)->name_and_type_at_put(*merge_cp_length_p, -- new_name_ref_i, new_signature_ref_i); -- if (scratch_i != *merge_cp_length_p) { -- // The new entry in *merge_cp_p is at a different index than -- // the new entry in scratch_cp so we need to map the index values. -- map_index(scratch_cp, scratch_i, *merge_cp_length_p); ++ + if (new_class->super() != NULL) { + redefinition_flags = redefinition_flags | new_class->super()->klass_part()->redefinition_flags(); + } @@ -4521,79 +4638,15 @@ index eb52388..432e15a 100644 + flags.set_is_field_modification_watched(old_fs.access_flags().is_field_modification_watched()); + flags.set_is_field_access_watched(old_fs.access_flags().is_field_access_watched()); + new_fs.set_access_flags(flags); - } -- (*merge_cp_length_p)++; -- } break; ++ } + } - -- // this is a double-indirect CP entry so it needs special handling -- case JVM_CONSTANT_Fieldref: // fall through -- case JVM_CONSTANT_InterfaceMethodref: // fall through -- case JVM_CONSTANT_Methodref: -- { -- int klass_ref_i = scratch_cp->uncached_klass_ref_index_at(scratch_i); -- int new_klass_ref_i = 0; -- bool match = (klass_ref_i < *merge_cp_length_p) && -- scratch_cp->compare_entry_to(klass_ref_i, *merge_cp_p, klass_ref_i, -- THREAD); -- if (!match) { -- // forward reference in *merge_cp_p or not a direct match -- -- int found_i = scratch_cp->find_matching_entry(klass_ref_i, *merge_cp_p, -- THREAD); -- if (found_i != 0) { -- guarantee(found_i != klass_ref_i, -- "compare_entry_to() and find_matching_entry() do not agree"); -- -- // Found a matching entry somewhere else in *merge_cp_p so -- // just need a mapping entry. -- new_klass_ref_i = found_i; -- map_index(scratch_cp, klass_ref_i, found_i); -- } else { -- // no match found so we have to append this entry to *merge_cp_p -- append_entry(scratch_cp, klass_ref_i, merge_cp_p, merge_cp_length_p, -- THREAD); -- // The above call to append_entry() can only append one entry -- // so the post call query of *merge_cp_length_p is only for -- // the sake of consistency. Without the optimization where we -- // use JVM_CONSTANT_UnresolvedClass, then up to two entries -- // could be appended. -- new_klass_ref_i = *merge_cp_length_p - 1; -- } ++ + IF_TRACE_RC3 { + if (new_class->super() != NULL) { + TRACE_RC3("Super class is %s", new_class->super()->klass_part()->name()->as_C_string()); - } ++ } + } - -- int name_and_type_ref_i = -- scratch_cp->uncached_name_and_type_ref_index_at(scratch_i); -- int new_name_and_type_ref_i = 0; -- match = (name_and_type_ref_i < *merge_cp_length_p) && -- scratch_cp->compare_entry_to(name_and_type_ref_i, *merge_cp_p, -- name_and_type_ref_i, THREAD); -- if (!match) { -- // forward reference in *merge_cp_p or not a direct match -- -- int found_i = scratch_cp->find_matching_entry(name_and_type_ref_i, -- *merge_cp_p, THREAD); -- if (found_i != 0) { -- guarantee(found_i != name_and_type_ref_i, -- "compare_entry_to() and find_matching_entry() do not agree"); -- -- // Found a matching entry somewhere else in *merge_cp_p so -- // just need a mapping entry. -- new_name_and_type_ref_i = found_i; -- map_index(scratch_cp, name_and_type_ref_i, found_i); -- } else { -- // no match found so we have to append this entry to *merge_cp_p -- append_entry(scratch_cp, name_and_type_ref_i, merge_cp_p, -- merge_cp_length_p, THREAD); -- // The above call to append_entry() can append more than -- // one entry so the post call query of *merge_cp_length_p -- // is required in order to get the right index for the -- // JVM_CONSTANT_NameAndType entry. -- new_name_and_type_ref_i = *merge_cp_length_p - 1; ++ +#ifdef ASSERT + assert(new_class->super() == NULL || new_class->super()->klass_part()->new_version() == NULL, "Super klass must be newest version!"); + @@ -4630,145 +4683,67 @@ index eb52388..432e15a 100644 + } + + cur_klass = cur_klass->next_sibling(); - } - } - -- // If the referenced entries already exist in *merge_cp_p, then -- // both new_klass_ref_i and new_name_and_type_ref_i will both be -- // 0. In that case, all we are appending is the current entry. -- if (new_klass_ref_i == 0) { -- new_klass_ref_i = klass_ref_i; -- } -- if (new_name_and_type_ref_i == 0) { -- new_name_and_type_ref_i = name_and_type_ref_i; -- } ++ } ++ } ++ + int new_count = _affected_klasses->length() - 1 - i; + if (new_count != 0) { - -- const char *entry_name; -- switch (scratch_cp->tag_at(scratch_i).value()) { -- case JVM_CONSTANT_Fieldref: -- entry_name = "Fieldref"; -- (*merge_cp_p)->field_at_put(*merge_cp_length_p, new_klass_ref_i, -- new_name_and_type_ref_i); -- break; -- case JVM_CONSTANT_InterfaceMethodref: -- entry_name = "IFMethodref"; -- (*merge_cp_p)->interface_method_at_put(*merge_cp_length_p, -- new_klass_ref_i, new_name_and_type_ref_i); -- break; -- case JVM_CONSTANT_Methodref: -- entry_name = "Methodref"; -- (*merge_cp_p)->method_at_put(*merge_cp_length_p, new_klass_ref_i, -- new_name_and_type_ref_i); -- break; -- default: -- guarantee(false, "bad switch"); -- break; ++ + TRACE_RC1("Found new number of affected classes: %d", new_count); - } ++ } + } + } - -- if (klass_ref_i != new_klass_ref_i) { -- RC_TRACE(0x00080000, ("%s entry@%d class_index changed: %d to %d", -- entry_name, *merge_cp_length_p, klass_ref_i, new_klass_ref_i)); -- } -- if (name_and_type_ref_i != new_name_and_type_ref_i) { -- RC_TRACE(0x00080000, -- ("%s entry@%d name_and_type_index changed: %d to %d", -- entry_name, *merge_cp_length_p, name_and_type_ref_i, -- new_name_and_type_ref_i)); -- } ++ + if (result != JVMTI_ERROR_NONE) { + rollback(); + return result; + } - -- if (scratch_i != *merge_cp_length_p) { -- // The new entry in *merge_cp_p is at a different index than -- // the new entry in scratch_cp so we need to map the index values. -- map_index(scratch_cp, scratch_i, *merge_cp_length_p); -- } -- (*merge_cp_length_p)++; -- } break; ++ + RC_TIMER_STOP(_timer_prologue); + RC_TIMER_START(_timer_class_linking); + // Link and verify new classes _after_ all classes have been updated in the system dictionary! + for (int i=0; i<_affected_klasses->length(); i++) { + instanceKlassHandle the_class = _affected_klasses->at(i); + instanceKlassHandle new_class(the_class->new_version()); - -- // At this stage, Class or UnresolvedClass could be here, but not -- // ClassIndex -- case JVM_CONSTANT_ClassIndex: // fall through ++ + TRACE_RC2("Linking class %d/%d %s", i, _affected_klasses->length(), the_class->name()->as_C_string()); + new_class->link_class(THREAD); - -- // Invalid is used as the tag for the second constant pool entry -- // occupied by JVM_CONSTANT_Double or JVM_CONSTANT_Long. It should -- // not be seen by itself. -- case JVM_CONSTANT_Invalid: // fall through ++ + result = check_exception(); + if (result != JVMTI_ERROR_NONE) break; + } + RC_TIMER_STOP(_timer_class_linking); + RC_TIMER_START(_timer_prologue); - -- // At this stage, String or UnresolvedString could be here, but not -- // StringIndex -- case JVM_CONSTANT_StringIndex: // fall through ++ + if (result != JVMTI_ERROR_NONE) { + rollback(); + return result; + } - -- // At this stage JVM_CONSTANT_UnresolvedClassInError should not be -- // here -- case JVM_CONSTANT_UnresolvedClassInError: // fall through ++ + TRACE_RC2("All classes loaded!"); - -- default: -- { -- // leave a breadcrumb -- jbyte bad_value = scratch_cp->tag_at(scratch_i).value(); -- ShouldNotReachHere(); -- } break; -- } // end switch tag value --} // end append_entry() ++ +#ifdef ASSERT + for (int i=0; i<_affected_klasses->length(); i++) { + instanceKlassHandle the_class = _affected_klasses->at(i); + assert(the_class->new_version() != NULL, "Must have been redefined"); + instanceKlassHandle new_version = instanceKlassHandle(THREAD, the_class->new_version()); + assert(new_version->new_version() == NULL, "Must be newest version"); - ++ + if (!(new_version->super() == NULL || new_version->super()->klass_part()->new_version() == NULL)) { + new_version()->print(); + new_version->super()->print(); + } + assert(new_version->super() == NULL || new_version->super()->klass_part()->new_version() == NULL, "Super class must be newest version"); + } - --void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class) { -- typeArrayOop save; ++ + SystemDictionary::classes_do(check_class, THREAD); - -- 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); ++ +#endif - -- 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); ++ + TRACE_RC1("Finished verification!"); + return JVMTI_ERROR_NONE; +} - -- 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::lock_threads() { + + RC_TIMER_START(_timer_wait_for_locks); @@ -4843,8 +4818,8 @@ index eb52388..432e15a 100644 + } + + TRACE_RC2("Unlocked %d threads", cnt); - } - ++} ++ +jvmtiError VM_RedefineClasses::check_redefinition_allowed(instanceKlassHandle scratch_class) { + + @@ -4854,10 +4829,7 @@ index eb52388..432e15a 100644 + + assert(scratch_class->old_version() != NULL, "must have old version"); + instanceKlassHandle the_class(scratch_class->old_version()); - --jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( -- instanceKlassHandle the_class, -- instanceKlassHandle scratch_class) { ++ int i; // Check superclasses, or rather their names, since superclasses themselves can be @@ -4875,7 +4847,7 @@ index eb52388..432e15a 100644 } // Check if the number, names and order of directly implemented interfaces are the same. -@@ -539,8 +718,8 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( +@@ -539,8 +718,8 @@ } for (i = 0; i < n_intfs; i++) { if (Klass::cast((klassOop) k_interfaces->obj_at(i))->name() != @@ -4886,176 +4858,79 @@ index eb52388..432e15a 100644 } } -@@ -578,14 +757,283 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( - Symbol* name_sym2 = scratch_class->constants()->symbol_at(new_fs.name_index()); - Symbol* sig_sym2 = scratch_class->constants()->symbol_at(new_fs.signature_index()); - if (name_sym1 != name_sym2 || sig_sym1 != sig_sym2) { -- return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; -+ return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; -+ } -+ } -+ -+ // If both streams aren't done then we have a differing number of -+ // fields. -+ if (!old_fs.done() || !new_fs.done()) { -+ return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; -+ } -+ -+ // Do a parallel walk through the old and new methods. Detect -+ // cases where they match (exist in both), have been added in -+ // the new methods, or have been deleted (exist only in the -+ // old methods). The class file parser places methods in order -+ // by method name, but does not order overloaded methods by -+ // signature. In order to determine what fate befell the methods, -+ // this code places the overloaded new methods that have matching -+ // 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(). -+ // 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()); -+ int n_old_methods = k_old_methods->length(); -+ int n_new_methods = k_new_methods->length(); -+ -+ int ni = 0; -+ int oi = 0; -+ while (true) { -+ methodOop k_old_method; -+ methodOop k_new_method; -+ enum { matched, added, deleted, undetermined } method_was = undetermined; -+ -+ if (oi >= n_old_methods) { -+ if (ni >= n_new_methods) { -+ break; // we've looked at everything, done -+ } -+ // New method at the end -+ k_new_method = (methodOop) k_new_methods->obj_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); -+ 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); -+ if (k_old_method->name() != k_new_method->name()) { -+ // Methods are sorted by method name, so a mismatch means added -+ // or deleted -+ if (k_old_method->name()->fast_compare(k_new_method->name()) > 0) { -+ method_was = added; -+ } else { -+ method_was = deleted; -+ } -+ } else if (k_old_method->signature() == k_new_method->signature()) { -+ // Both the name and signature match -+ method_was = matched; -+ } else { -+ // The name matches, but the signature doesn't, which means we have to -+ // 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); -+ if (k_old_method->name() != m->name()) { -+ // reached another method name so no more overloaded methods -+ method_was = deleted; -+ break; -+ } -+ 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_method = m; -+ method_was = matched; -+ break; -+ } -+ } -+ -+ if (nj >= n_new_methods) { -+ // reached the end without a match; so method was deleted -+ method_was = deleted; -+ } -+ } -+ } -+ -+ switch (method_was) { -+ case matched: -+ // methods match, be sure modifiers do too -+ old_flags = (jushort) k_old_method->access_flags().get_flags(); -+ new_flags = (jushort) k_new_method->access_flags().get_flags(); -+ if ((old_flags ^ new_flags) & ~(JVM_ACC_NATIVE)) { -+ return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED; -+ } -+ { -+ 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); -+ 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); -+ } -+ } -+ // advance to next pair of methods -+ ++oi; -+ ++ni; -+ break; -+ case added: -+ // method added, see if it is OK -+ new_flags = (jushort) k_new_method->access_flags().get_flags(); -+ if ((new_flags & JVM_ACC_PRIVATE) == 0 +@@ -689,12 +868,8 @@ + 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); + } + } +- RC_TRACE(0x00008000, ("Method matched: new: %s [%d] == old: %s [%d]", +- k_new_method->name_and_sig_as_C_string(), ni, +- k_old_method->name_and_sig_as_C_string(), oi)); + // advance to next pair of methods + ++oi; + ++ni; +@@ -703,11 +878,11 @@ + // method added, see if it is OK + new_flags = (jushort) k_new_method->access_flags().get_flags(); + if ((new_flags & JVM_ACC_PRIVATE) == 0 +- // hack: private should be treated as final, but alas +- || (new_flags & (JVM_ACC_FINAL|JVM_ACC_STATIC)) == 0 +- ) { +- // new methods must be private +- return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED; + // hack: private should be treated as final, but alas + || (new_flags & (JVM_ACC_FINAL|JVM_ACC_STATIC)) == 0 + ) { + // new methods must be private + return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED; -+ } -+ { -+ u2 num = the_class->next_method_idnum(); -+ if (num == constMethodOopDesc::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); -+ 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); -+ } -+ ++ni; // advance to next new method -+ break; -+ case deleted: -+ // method deleted, see if it is OK -+ old_flags = (jushort) k_old_method->access_flags().get_flags(); -+ if ((old_flags & JVM_ACC_PRIVATE) == 0 + } + { + u2 num = the_class->next_method_idnum(); +@@ -722,24 +897,19 @@ + idnum_owner->set_method_idnum(new_num); + } + k_new_method->set_method_idnum(num); +- swap_all_method_annotations(new_num, num, scratch_class); + } +- RC_TRACE(0x00008000, ("Method added: new: %s [%d]", +- k_new_method->name_and_sig_as_C_string(), ni)); + ++ni; // advance to next new method + break; + case deleted: + // method deleted, see if it is OK + old_flags = (jushort) k_old_method->access_flags().get_flags(); + if ((old_flags & JVM_ACC_PRIVATE) == 0 +- // hack: private should be treated as final, but alas +- || (old_flags & (JVM_ACC_FINAL|JVM_ACC_STATIC)) == 0 +- ) { +- // deleted methods must be private +- return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED; + // hack: private should be treated as final, but alas + || (old_flags & (JVM_ACC_FINAL|JVM_ACC_STATIC)) == 0 + ) { + // deleted methods must be private + return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED; -+ } -+ ++oi; // advance to next old method -+ break; -+ default: -+ ShouldNotReachHere(); -+ } -+ } -+ -+ return JVMTI_ERROR_NONE; -+} -+ + } +- RC_TRACE(0x00008000, ("Method deleted: old: %s [%d]", +- k_old_method->name_and_sig_as_C_string(), oi)); + ++oi; // advance to next old method + break; + default: +@@ -750,2065 +920,1316 @@ + return JVMTI_ERROR_NONE; + } + +int VM_RedefineClasses::calculate_redefinition_flags(instanceKlassHandle new_class) { -+ + +-// Find new constant pool index value for old constant pool index value +-// by seaching the index map. Returns zero (0) if there is no mapped +-// value for the old constant pool index. +-int VM_RedefineClasses::find_new_index(int old_index) { +- if (_index_map_count == 0) { +- // map is empty so nothing can be found +- return 0; + int result = Klass::NoRedefinition; + + @@ -5069,8 +4944,13 @@ index eb52388..432e15a 100644 + if (the_class->is_in_error_state()) { + // TBD #5057930: special error code is needed in 1.6 + //result = Klass::union_redefinition_level(result, Klass::Invalid); -+ } -+ + } + +- if (old_index < 1 || old_index >= _index_map_p->length()) { +- // The old_index is out of range so it is not mapped. This should +- // not happen in regular constant pool merging use, but it can +- // happen if a corrupt annotation is processed. +- return 0; + int i; + + ////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -5102,8 +4982,12 @@ index eb52388..432e15a 100644 + } + cur_klass = cur_klass->klass_part()->super(); + } -+ } -+ + } + +- int value = _index_map_p->at(old_index); +- if (value == -1) { +- // the old_index is not mapped +- return 0; + ////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Check interfaces + @@ -5120,8 +5004,20 @@ index eb52388..432e15a 100644 + old_interface->set_subtype_changed(true); + } + } -+ } -+ + } + +- return value; +-} // end find_new_index() +- +- +-// Returns true if the current mismatch is due to a resolved/unresolved +-// class pair. Otherwise, returns false. +-bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1, +- int index1, constantPoolHandle cp2, int index2) { +- +- jbyte t1 = cp1->tag_at(index1).value(); +- if (t1 != JVM_CONSTANT_Class && t1 != JVM_CONSTANT_UnresolvedClass) { +- return false; // wrong entry type; not our special case + // Interfaces added? + objArrayOop new_interfaces = new_class->transitive_interfaces(); + for (i = 0; i<new_interfaces->length(); i++) { @@ -5129,8 +5025,11 @@ index eb52388..432e15a 100644 + result = result | Klass::ModifyClass; + TRACE_RC2("Added interface %s", ((klassOop)new_interfaces->obj_at(i))->klass_part()->name()->as_C_string()); + } -+ } -+ + } + +- jbyte t2 = cp2->tag_at(index2).value(); +- if (t2 != JVM_CONSTANT_Class && t2 != JVM_CONSTANT_UnresolvedClass) { +- return false; // wrong entry type; not our special case + + // Check whether class modifiers are the same. + jushort old_flags = (jushort) the_class->access_flags().get_flags(); @@ -5161,177 +5060,100 @@ index eb52388..432e15a 100644 + Symbol* sig_sym2 = new_class->constants()->symbol_at(new_fs.signature_index()); + if (name_sym1 != name_sym2 || sig_sym1 != sig_sym2) { + result = result | Klass::ModifyInstances; - } ++ } } - // If both streams aren't done then we have a differing number of - // fields. - if (!old_fs.done() || !new_fs.done()) { -- return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; +- if (t1 == t2) { +- return false; // not a mismatch; not our special case ++ // If both streams aren't done then we have a differing number of ++ // fields. ++ if (!old_fs.done() || !new_fs.done()) { + result = result | Klass::ModifyInstances; } - // Do a parallel walk through the old and new methods. Detect -@@ -606,7 +1054,7 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( - // 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()); -+ objArrayHandle k_new_methods(new_class->methods()); - int n_old_methods = k_old_methods->length(); - int n_new_methods = k_new_methods->length(); - -@@ -672,2278 +1120,701 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( - } - - switch (method_was) { -- case matched: -- // methods match, be sure modifiers do too -- old_flags = (jushort) k_old_method->access_flags().get_flags(); -- new_flags = (jushort) k_new_method->access_flags().get_flags(); -- if ((old_flags ^ new_flags) & ~(JVM_ACC_NATIVE)) { -- return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED; -- } -- { -- 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); -- 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); -- } -- } -- RC_TRACE(0x00008000, ("Method matched: new: %s [%d] == old: %s [%d]", -- k_new_method->name_and_sig_as_C_string(), ni, -- k_old_method->name_and_sig_as_C_string(), oi)); -- // advance to next pair of methods -- ++oi; -- ++ni; -- break; -- case added: -- // method added, see if it is OK -- new_flags = (jushort) k_new_method->access_flags().get_flags(); -- if ((new_flags & JVM_ACC_PRIVATE) == 0 -- // hack: private should be treated as final, but alas -- || (new_flags & (JVM_ACC_FINAL|JVM_ACC_STATIC)) == 0 -- ) { -- // new methods must be private -- return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED; -- } -- { -- u2 num = the_class->next_method_idnum(); -- if (num == constMethodOopDesc::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); -+ case matched: -+ // methods match, be sure modifiers do too -+ old_flags = (jushort) k_old_method->access_flags().get_flags(); -+ new_flags = (jushort) k_new_method->access_flags().get_flags(); -+ if ((old_flags ^ new_flags) & ~(JVM_ACC_NATIVE)) { -+ // (tw) Can this have any effects? Probably yes on vtables? -+ result = result | Klass::ModifyClass; -+ } -+ { -+ u2 new_num = k_new_method->method_idnum(); -+ u2 old_num = k_old_method->method_idnum(); -+ if (new_num != old_num) { -+ methodOop idnum_owner = new_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(num); -- swap_all_method_annotations(new_num, num, scratch_class); -- } -- RC_TRACE(0x00008000, ("Method added: new: %s [%d]", -- k_new_method->name_and_sig_as_C_string(), ni)); -- ++ni; // advance to next new method -- break; -- case deleted: -- // method deleted, see if it is OK -- old_flags = (jushort) k_old_method->access_flags().get_flags(); -- if ((old_flags & JVM_ACC_PRIVATE) == 0 -- // hack: private should be treated as final, but alas -- || (old_flags & (JVM_ACC_FINAL|JVM_ACC_STATIC)) == 0 -- ) { -- // deleted methods must be private -- return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED; -- } -- RC_TRACE(0x00008000, ("Method deleted: old: %s [%d]", -- k_old_method->name_and_sig_as_C_string(), oi)); -- ++oi; // advance to next old method -- break; -- default: -- ShouldNotReachHere(); -- } -- } -- -- return JVMTI_ERROR_NONE; --} -- -- --// Find new constant pool index value for old constant pool index value --// by seaching the index map. Returns zero (0) if there is no mapped --// value for the old constant pool index. --int VM_RedefineClasses::find_new_index(int old_index) { -- if (_index_map_count == 0) { -- // map is empty so nothing can be found -- return 0; -- } -- -- if (old_index < 1 || old_index >= _index_map_p->length()) { -- // The old_index is out of range so it is not mapped. This should -- // not happen in regular constant pool merging use, but it can -- // happen if a corrupt annotation is processed. -- return 0; -- } -- -- int value = _index_map_p->at(old_index); -- if (value == -1) { -- // the old_index is not mapped -- return 0; -- } -- -- return value; --} // end find_new_index() -- -- --// Returns true if the current mismatch is due to a resolved/unresolved --// class pair. Otherwise, returns false. --bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1, -- int index1, constantPoolHandle cp2, int index2) { -- -- jbyte t1 = cp1->tag_at(index1).value(); -- if (t1 != JVM_CONSTANT_Class && t1 != JVM_CONSTANT_UnresolvedClass) { -- return false; // wrong entry type; not our special case -- } -- -- jbyte t2 = cp2->tag_at(index2).value(); -- if (t2 != JVM_CONSTANT_Class && t2 != JVM_CONSTANT_UnresolvedClass) { -- return false; // wrong entry type; not our special case -- } -- -- if (t1 == t2) { -- return false; // not a mismatch; not our special case -- } -- - char *s1 = cp1->klass_name_at(index1)->as_C_string(); - char *s2 = cp2->klass_name_at(index2)->as_C_string(); - if (strcmp(s1, s2) != 0) { - return false; // strings don't match; not our special case - } -- ++ // Do a parallel walk through the old and new methods. Detect ++ // cases where they match (exist in both), have been added in ++ // the new methods, or have been deleted (exist only in the ++ // old methods). The class file parser places methods in order ++ // by method name, but does not order overloaded methods by ++ // signature. In order to determine what fate befell the methods, ++ // this code places the overloaded new methods that have matching ++ // 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(). ++ // 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(new_class->methods()); ++ int n_old_methods = k_old_methods->length(); ++ int n_new_methods = k_new_methods->length(); + - return true; // made it through the gauntlet; this is our special case -} // end is_unresolved_class_mismatch() -- -- ++ int ni = 0; ++ int oi = 0; ++ while (true) { ++ methodOop k_old_method; ++ methodOop k_new_method; ++ enum { matched, added, deleted, undetermined } method_was = undetermined; + ++ if (oi >= n_old_methods) { ++ if (ni >= n_new_methods) { ++ break; // we've looked at everything, done ++ } ++ // New method at the end ++ k_new_method = (methodOop) k_new_methods->obj_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); ++ 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); ++ if (k_old_method->name() != k_new_method->name()) { ++ // Methods are sorted by method name, so a mismatch means added ++ // or deleted ++ if (k_old_method->name()->fast_compare(k_new_method->name()) > 0) { ++ method_was = added; ++ } else { ++ method_was = deleted; ++ } ++ } else if (k_old_method->signature() == k_new_method->signature()) { ++ // Both the name and signature match ++ method_was = matched; ++ } else { ++ // The name matches, but the signature doesn't, which means we have to ++ // 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); ++ if (k_old_method->name() != m->name()) { ++ // reached another method name so no more overloaded methods ++ method_was = deleted; ++ break; ++ } ++ 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_method = m; ++ method_was = matched; ++ break; ++ } ++ } + -// 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, @@ -5450,13 +5272,13 @@ index eb52388..432e15a 100644 - return JVMTI_ERROR_OUT_OF_MEMORY; - } else { - return JVMTI_ERROR_INTERNAL; -- } -+ k_new_method->set_method_idnum(old_num); -+ TRACE_RC2("swapping idnum of new and old method %d / %d!", new_num, old_num); -+ swap_all_method_annotations(old_num, new_num, new_class); ++ if (nj >= n_new_methods) { ++ // reached the end without a match; so method was deleted ++ method_was = deleted; + } } } -- + - // Do the validity checks in compare_and_normalize_class_versions() - // before verifying the byte codes. By doing these checks first, we - // limit the number of functions that require redirection from @@ -5466,6 +5288,29 @@ index eb52388..432e15a 100644 - scratch_class); - if (res != JVMTI_ERROR_NONE) { - return res; ++ switch (method_was) { ++ case matched: ++ // methods match, be sure modifiers do too ++ old_flags = (jushort) k_old_method->access_flags().get_flags(); ++ new_flags = (jushort) k_new_method->access_flags().get_flags(); ++ if ((old_flags ^ new_flags) & ~(JVM_ACC_NATIVE)) { ++ // (tw) Can this have any effects? Probably yes on vtables? ++ result = result | Klass::ModifyClass; ++ } ++ { ++ u2 new_num = k_new_method->method_idnum(); ++ u2 old_num = k_old_method->method_idnum(); ++ if (new_num != old_num) { ++ methodOop idnum_owner = new_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); ++ TRACE_RC2("swapping idnum of new and old method %d / %d!", new_num, old_num); ++ swap_all_method_annotations(old_num, new_num, new_class); ++ } ++ } + TRACE_RC3("Method matched: new: %s [%d] == old: %s [%d]", + k_new_method->name_and_sig_as_C_string(), ni, + k_old_method->name_and_sig_as_C_string(), oi); @@ -5482,10 +5327,75 @@ index eb52388..432e15a 100644 + ) { + // new methods must be private + result = result | Klass::ModifyClass; ++ } ++ { ++ u2 num = the_class->next_method_idnum(); ++ if (num == constMethodOopDesc::UNSET_IDNUM) { ++ // cannot add any more methods ++ result = result | Klass::ModifyClass; ++ } ++ u2 new_num = k_new_method->method_idnum(); ++ methodOop idnum_owner = new_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, new_class); ++ } ++ TRACE_RC1("Method added: new: %s [%d]", ++ k_new_method->name_and_sig_as_C_string(), ni); ++ ++ni; // advance to next new method ++ break; ++ case deleted: ++ // method deleted, see if it is OK ++ old_flags = (jushort) k_old_method->access_flags().get_flags(); ++ if ((old_flags & JVM_ACC_PRIVATE) == 0 ++ // hack: private should be treated as final, but alas ++ || (old_flags & (JVM_ACC_FINAL|JVM_ACC_STATIC)) == 0 ++ ) { ++ // deleted methods must be private ++ result = result | Klass::ModifyClass; ++ } ++ TRACE_RC1("Method deleted: old: %s [%d]", ++ k_old_method->name_and_sig_as_C_string(), oi); ++ ++oi; // advance to next old method ++ break; ++ default: ++ ShouldNotReachHere(); ++ } ++ } ++ ++ if (new_class()->size() != new_class->old_version()->size()) { ++ result |= Klass::ModifyClassSize; ++ } ++ ++ if (new_class->size_helper() != ((instanceKlass*)(new_class->old_version()->klass_part()))->size_helper()) { ++ result |= Klass::ModifyInstanceSize; ++ } ++ ++ // (tw) Check method bodies to be able to return NoChange? ++ return result; ++} ++ ++void VM_RedefineClasses::calculate_instance_update_information(klassOop new_version) { ++ ++ class CalculateFieldUpdates : public FieldClosure { ++ ++ private: ++ instanceKlass* _old_ik; ++ GrowableArray<int> _update_info; ++ int _position; ++ bool _copy_backwards; ++ ++ public: ++ ++ bool does_copy_backwards() { ++ return _copy_backwards; } -- + - // verify what the caller passed us - { +- { - // The bug 6214132 caused the verification to fail. - // Information about the_class and scratch_class is temporarily - // recorded into jvmtiThreadState. This data is used to redirect @@ -5495,8 +5405,12 @@ index eb52388..432e15a 100644 - RedefineVerifyMark rvm(&the_class, &scratch_class, state); - Verifier::verify( - scratch_class, Verifier::ThrowException, true, THREAD); -- } -- ++ CalculateFieldUpdates(instanceKlass* old_ik) : ++ _old_ik(old_ik), _position(instanceOopDesc::base_offset_in_bytes()), _copy_backwards(false) { ++ _update_info.append(_position); ++ _update_info.append(0); + } + - if (HAS_PENDING_EXCEPTION) { - Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); - // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark @@ -5505,24 +5419,65 @@ index eb52388..432e15a 100644 - CLEAR_PENDING_EXCEPTION; - if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { - return JVMTI_ERROR_OUT_OF_MEMORY; -- } else { ++ GrowableArray<int> &finish() { ++ _update_info.append(0); ++ return _update_info; ++ } ++ ++ void do_field(fieldDescriptor* fd) { ++ int alignment = fd->offset() - _position; ++ if (alignment > 0) { ++ // This field was aligned, so we need to make sure that we fill the gap ++ fill(alignment); ++ } ++ ++ assert(_position == fd->offset(), "must be correct offset!"); ++ ++ fieldDescriptor old_fd; ++ if (_old_ik->find_field(fd->name(), fd->signature(), false, &old_fd) != NULL) { ++ // Found field in the old class, copy ++ copy(old_fd.offset(), type2aelembytes(fd->field_type())); ++ ++ if (old_fd.offset() < fd->offset()) { ++ _copy_backwards = true; ++ } ++ ++ // Transfer special flags ++ fd->set_is_field_modification_watched(old_fd.is_field_modification_watched()); ++ fd->set_is_field_access_watched(old_fd.is_field_access_watched()); + } else { - // tell the caller the bytecodes are bad - return JVMTI_ERROR_FAILS_VERIFICATION; -- } -- } -- ++ // New field, fill ++ fill(type2aelembytes(fd->field_type())); + } + } + - res = merge_cp_and_rewrite(the_class, scratch_class, THREAD); - if (res != JVMTI_ERROR_NONE) { - return res; -- } -- ++ private: ++ ++ void fill(int size) { ++ if (_update_info.length() > 0 && _update_info.at(_update_info.length() - 1) < 0) { ++ (*_update_info.adr_at(_update_info.length() - 1)) -= size; ++ } else { ++ _update_info.append(-size); ++ } ++ _position += size; + } + - if (VerifyMergedCPBytecodes) { - // verify what we have done during constant pool merging - { - RedefineVerifyMark rvm(&the_class, &scratch_class, state); - Verifier::verify(scratch_class, Verifier::ThrowException, true, THREAD); -- } -- ++ void copy(int offset, int size) { ++ int prev_end = -1; ++ if (_update_info.length() > 0 && _update_info.at(_update_info.length() - 1) > 0) { ++ prev_end = _update_info.at(_update_info.length() - 2) + _update_info.at(_update_info.length() - 1); + } + - if (HAS_PENDING_EXCEPTION) { - Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); - // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark @@ -5535,14 +5490,134 @@ index eb52388..432e15a 100644 - } else { - // tell the caller that constant pool merging screwed up - return JVMTI_ERROR_INTERNAL; -- } -- } -- } -- ++ if (prev_end == offset) { ++ (*_update_info.adr_at(_update_info.length() - 2)) += size; ++ } else { ++ _update_info.append(size); ++ _update_info.append(offset); ++ } ++ ++ _position += size; ++ } ++ }; ++ ++ instanceKlass* ik = instanceKlass::cast(new_version); ++ instanceKlass* old_ik = instanceKlass::cast(new_version->klass_part()->old_version()); ++ CalculateFieldUpdates cl(old_ik); ++ ik->do_nonstatic_fields(&cl); ++ ++ GrowableArray<int> result = cl.finish(); ++ ik->store_update_information(result); ++ ik->set_copying_backwards(cl.does_copy_backwards()); ++ ++ IF_TRACE_RC2 { ++ TRACE_RC2("Instance update information for %s:", new_version->klass_part()->name()->as_C_string()); ++ if (cl.does_copy_backwards()) { ++ TRACE_RC2("\tDoes copy backwards!"); ++ } ++ for (int i=0; i<result.length(); i++) { ++ int curNum = result.at(i); ++ if (curNum < 0) { ++ TRACE_RC2("\t%d CLEAN", curNum); ++ } else if (curNum > 0) { ++ TRACE_RC2("\t%d COPY from %d", curNum, result.at(i + 1)); ++ i++; ++ } else { ++ TRACE_RC2("\tEND"); ++ } ++ } ++ } ++} ++ ++void VM_RedefineClasses::rollback() { ++ TRACE_RC1("Rolling back redefinition!"); ++ SystemDictionary::rollback_redefinition(); ++ ++ TRACE_RC1("After rolling back system dictionary!"); ++ for (int i=0; i<_new_classes->length(); i++) { ++ SystemDictionary::remove_from_hierarchy(_new_classes->at(i)); ++ } ++ ++ for (int i=0; i<_new_classes->length(); i++) { ++ instanceKlassHandle new_class = _new_classes->at(i); ++ new_class->set_redefining(false); ++ new_class->old_version()->klass_part()->set_new_version(NULL); ++ new_class->set_old_version(NULL); ++ } ++ ++} ++ ++void VM_RedefineClasses::swap_marks(oop first, oop second) { ++ markOop first_mark = first->mark(); ++ markOop second_mark = second->mark(); ++ first->set_mark(second_mark); ++ second->set_mark(first_mark); ++} ++ ++ ++class FieldCopier : public FieldClosure { ++ public: ++ void do_field(fieldDescriptor* fd) { ++ instanceKlass* cur = instanceKlass::cast(fd->field_holder()); ++ oop cur_oop = cur->java_mirror(); ++ ++ instanceKlass* old = instanceKlass::cast(cur->old_version()); ++ oop old_oop = old->java_mirror(); ++ ++ fieldDescriptor result; ++ bool found = old->find_local_field(fd->name(), fd->signature(), &result); ++ if (found && result.is_static()) { ++ TRACE_RC3("Copying static field value for field %s old_offset=%d new_offset=%d", ++ fd->name()->as_C_string(), result.offset(), fd->offset()); ++ memcpy(cur_oop->obj_field_addr<HeapWord>(fd->offset()), ++ old_oop->obj_field_addr<HeapWord>(result.offset()), ++ type2aelembytes(fd->field_type())); ++ ++ // Static fields may have references to java.lang.Class ++ if (fd->field_type() == T_OBJECT) { ++ oop oop = cur_oop->obj_field(fd->offset()); ++ if (oop != NULL && oop->is_instanceMirror()) { ++ klassOop klass = java_lang_Class::as_klassOop(oop); ++ if (klass != NULL && klass->klass_part()->oop_is_instance()) { ++ assert(oop == instanceKlass::cast(klass)->java_mirror(), "just checking"); ++ if (klass->klass_part()->new_version() != NULL) { ++ oop = instanceKlass::cast(klass->klass_part()->new_version())->java_mirror(); ++ ++ cur_oop->obj_field_put(fd->offset(), oop); ++ } ++ } + } + } + } ++ } ++}; + - Rewriter::rewrite(scratch_class, THREAD); - if (!HAS_PENDING_EXCEPTION) { - Rewriter::relocate_and_link(scratch_class, THREAD); -- } ++void VM_RedefineClasses::mark_as_scavengable(nmethod* nm) { ++ if (!nm->on_scavenge_root_list()) { ++ CodeCache::add_scavenge_root_nmethod(nm); ++ } ++} ++ ++struct StoreBarrier { ++ template <class T> static void oop_store(T* p, oop v) { ::oop_store(p, v); } ++}; ++ ++struct StoreNoBarrier { ++ template <class T> static void oop_store(T* p, oop v) { oopDesc::encode_store_heap_oop_not_null(p, v); } ++}; ++ ++template <class S> ++class ChangePointersOopClosure : public OopClosureNoHeader { ++ // Forward pointers to instanceKlass and mirror class to new versions ++ template <class T> ++ inline void do_oop_work(T* p) { ++ oop oop = oopDesc::load_decode_heap_oop(p); ++ if (oop == NULL) { ++ return; + } - if (HAS_PENDING_EXCEPTION) { - Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); - CLEAR_PENDING_EXCEPTION; @@ -5550,21 +5625,244 @@ index eb52388..432e15a 100644 - return JVMTI_ERROR_OUT_OF_MEMORY; - } else { - return JVMTI_ERROR_INTERNAL; -- } -- } -- ++ if (oop->is_instanceKlass()) { ++ klassOop klass = (klassOop) oop; ++ if (klass->klass_part()->new_version() != NULL) { ++ oop = klass->klass_part()->new_version(); ++ S::oop_store(p, oop); ++ } ++ } else if (oop->is_instanceMirror()) { ++ klassOop klass = java_lang_Class::as_klassOop(oop); ++ if (klass != NULL && klass->klass_part()->oop_is_instance()) { ++ assert(oop == instanceKlass::cast(klass)->java_mirror(), "just checking"); ++ if (klass->klass_part()->new_version() != NULL) { ++ oop = instanceKlass::cast(klass->klass_part()->new_version())->java_mirror(); ++ S::oop_store(p, oop); ++ } ++ } ++ } ++ } ++ ++ virtual void do_oop(oop* o) { ++ do_oop_work(o); ++ } ++ ++ virtual void do_oop(narrowOop* o) { ++ do_oop_work(o); ++ } ++}; ++ ++void VM_RedefineClasses::doit() { ++ Thread *thread = Thread::current(); ++ ++ TRACE_RC1("Entering doit!"); ++ ++ assert((_max_redefinition_flags & Klass::RemoveSuperType) == 0, "removing super types not allowed"); ++ ++ if (UseSharedSpaces) { ++ // Sharing is enabled so we remap the shared readonly space to ++ // 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()) { ++ TRACE_RC1("failed to remap shared readonly space to readwrite, private"); ++ _result = JVMTI_ERROR_INTERNAL; ++ return; ++ } ++ } ++ ++ RC_TIMER_START(_timer_prepare_redefinition); ++ for (int i = 0; i < _new_classes->length(); i++) { ++ redefine_single_class(_new_classes->at(i), thread); ++ } ++ ++ // Deoptimize all compiled code that depends on this class ++ flush_dependent_code(instanceKlassHandle(Thread::current(), (klassOop)NULL), Thread::current()); ++ ++ // Adjust constantpool caches and vtables for all classes ++ // that reference methods of the evolved class. ++ SystemDictionary::classes_do(adjust_cpool_cache, Thread::current()); ++ ++ RC_TIMER_STOP(_timer_prepare_redefinition); ++ RC_TIMER_START(_timer_heap_iteration); ++ ++ class ChangePointersObjectClosure : public ObjectClosure { ++ ++ private: ++ ++ OopClosureNoHeader *_closure; ++ bool _needs_instance_update; ++ oop _tmp_obj; ++ int _tmp_obj_size; ++ ++ public: ++ ChangePointersObjectClosure(OopClosureNoHeader *closure) : _closure(closure), _needs_instance_update(false), _tmp_obj(NULL), _tmp_obj_size(0) {} ++ ++ bool needs_instance_update() { ++ return _needs_instance_update; ++ } ++ ++ void copy_to_tmp(oop o) { ++ int size = o->size(); ++ if (_tmp_obj_size < size) { ++ _tmp_obj_size = size; ++ _tmp_obj = (oop)resource_allocate_bytes(size * HeapWordSize); ++ } ++ Copy::aligned_disjoint_words((HeapWord*)o, (HeapWord*)_tmp_obj, size); ++ } ++ ++ virtual void do_object(oop obj) { ++ if (obj->is_instanceKlass()) return; ++ if (obj->is_instanceMirror()) { ++ // static fields may have references to old java.lang.Class instances, update them ++ // at the same time, we don't want to update other oops in the java.lang.Class ++ // Causes SIGSEGV? ++ //instanceMirrorKlass::oop_fields_iterate(obj, _closure); ++ } else { ++ obj->oop_iterate(_closure); ++ } ++ ++ if (obj->blueprint()->new_version() != NULL) { ++ Klass* new_klass = obj->blueprint()->new_version()->klass_part(); ++ if (obj->is_perm()) { ++ _needs_instance_update = true; ++ } else if(new_klass->update_information() != NULL) { ++ int size_diff = obj->size() - obj->size_given_klass(new_klass); ++ ++ // Either new size is bigger or gap is to small to be filled ++ if (size_diff < 0 || (size_diff > 0 && (size_t) size_diff < CollectedHeap::min_fill_size())) { ++ // We need an instance update => set back to old klass ++ _needs_instance_update = true; ++ } else { ++ oop src = obj; ++ if (new_klass->is_copying_backwards()) { ++ copy_to_tmp(obj); ++ src = _tmp_obj; ++ } ++ src->set_klass_no_check(obj->blueprint()->new_version()); ++ MarkSweep::update_fields(obj, src, new_klass->update_information()); ++ ++ if (size_diff > 0) { ++ HeapWord* dead_space = ((HeapWord *)obj) + obj->size(); ++ CollectedHeap::fill_with_object(dead_space, size_diff); ++ } ++ } ++ } else { ++ obj->set_klass_no_check(obj->blueprint()->new_version()); ++ } ++ } ++ } ++ }; ++ ++ ChangePointersOopClosure<StoreNoBarrier> oopClosureNoBarrier; ++ ChangePointersOopClosure<StoreBarrier> oopClosure; ++ ChangePointersObjectClosure objectClosure(&oopClosure); ++ ++ { ++ // Since we may update oops inside nmethod's code blob to point to java.lang.Class in new generation, we need to ++ // make sure such references are properly recognized by GC. For that, If ScavengeRootsInCode is true, we need to ++ // mark such nmethod's as "scavengable". ++ // For now, mark all nmethod's as scavengable that are not scavengable already ++ if (ScavengeRootsInCode) { ++ CodeCache::nmethods_do(mark_as_scavengable); ++ } ++ ++ SharedHeap::heap()->gc_prologue(true); ++ Universe::heap()->object_iterate(&objectClosure); ++ Universe::root_oops_do(&oopClosureNoBarrier); ++ SharedHeap::heap()->gc_epilogue(false); ++ } ++ ++ ++ for (int i=0; i<_new_classes->length(); i++) { ++ klassOop cur_oop = _new_classes->at(i)(); ++ instanceKlass* cur = instanceKlass::cast(cur_oop); ++ klassOop old_oop = cur->old_version(); ++ instanceKlass* old = instanceKlass::cast(old_oop); ++ ++ // Swap marks to have same hashcodes ++ swap_marks(cur_oop, old_oop); ++ swap_marks(cur->java_mirror(), old->java_mirror()); ++ ++ // Revert pool holder for old version of klass (it was updated by one of ours closure!) ++ old->constants()->set_pool_holder(old_oop); ++ ++ ++ if (old->array_klasses() != NULL) { ++ // Transfer the array classes, otherwise we might get cast exceptions when casting array types. ++ assert(cur->array_klasses() == NULL, "just checking"); ++ cur->set_array_klasses(old->array_klasses()); ++ } ++ ++ // Initialize the new class! Special static initialization that does not execute the ++ // static constructor but copies static field values from the old class if name ++ // and signature of a static field match. ++ FieldCopier copier; ++ cur->do_local_static_fields(&copier); // TODO (tw): What about internal static fields?? ++ old->set_java_mirror(cur->java_mirror()); ++ ++ // Transfer init state ++ instanceKlass::ClassState state = old->init_state(); ++ if (state > instanceKlass::linked) { ++ cur->set_init_state(state); + } + } + - _scratch_classes[i] = scratch_class; -- ++ RC_TIMER_STOP(_timer_heap_iteration); ++ RC_TIMER_START(_timer_redefinition); ++ if (objectClosure.needs_instance_update()){ + - // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark - RC_TRACE_WITH_THREAD(0x00000001, THREAD, - ("loaded name=%s (avail_mem=" UINT64_FORMAT "K)", - the_class->external_name(), os::available_memory() >> 10)); -- } -- ++ // Do a full garbage collection to update the instance sizes accordingly ++ TRACE_RC1("Before performing full GC!"); ++ Universe::set_redefining_gc_run(true); ++ notify_gc_begin(true); ++ Universe::heap()->collect_as_vm_thread(GCCause::_heap_inspection); ++ notify_gc_end(); ++ Universe::set_redefining_gc_run(false); ++ TRACE_RC1("GC done!"); + } + - return JVMTI_ERROR_NONE; --} -- -- ++ // Unmark klassOops as "redefining" ++ for (int i=0; i<_new_classes->length(); i++) { ++ klassOop cur_klass = _new_classes->at(i)(); ++ instanceKlass* cur = (instanceKlass*)cur_klass->klass_part(); ++ cur->set_redefining(false); ++ cur->clear_update_information(); ++ } ++ ++ // Disable any dependent concurrent compilations ++ SystemDictionary::notice_modification(); ++ ++ // Set flag indicating that some invariants are no longer true. ++ // See jvmtiExport.hpp for detailed explanation. ++ JvmtiExport::set_has_redefined_a_class(); ++ ++ // Clean up caches in the compiler interface and compiler threads ++ ciObjectFactory::resort_shared_ci_objects(); ++ ++#ifdef ASSERT ++ ++ // Universe::verify(); ++ // JNIHandles::verify(); ++ ++ SystemDictionary::classes_do(check_class, thread); ++#endif ++ ++ RC_TIMER_STOP(_timer_redefinition); ++ ++ if (TraceRedefineClasses > 0) { ++ tty->flush(); ++ } + } + ++void VM_RedefineClasses::doit_epilogue() { + -// Map old_index to new_index as needed. scratch_cp is only needed -// for RC_TRACE() calls. -void VM_RedefineClasses::map_index(constantPoolHandle scratch_cp, @@ -5572,20 +5870,74 @@ index eb52388..432e15a 100644 - if (find_new_index(old_index) != 0) { - // old_index is already mapped - return; -- } -- ++ RC_TIMER_START(_timer_vm_op_epilogue); ++ ++ //unlock_threads(); ++ ++ ResourceMark mark; ++ ++ VM_GC_Operation::doit_epilogue(); ++ TRACE_RC1("GC Operation epilogue finished! "); ++ ++ // Free the array of scratch classes ++ delete _new_classes; ++ _new_classes = NULL; ++ ++ // Free the array of affected classes ++ delete _affected_klasses; ++ _affected_klasses = NULL; ++ ++ TRACE_RC1("Redefinition finished!"); ++ ++ RC_TIMER_STOP(_timer_vm_op_epilogue); ++} ++ ++bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) { ++ // classes for primitives cannot be redefined ++ if (java_lang_Class::is_primitive(klass_mirror)) { ++ return false; + } ++ klassOop the_class_oop = java_lang_Class::as_klassOop(klass_mirror); ++ // classes for arrays cannot be redefined ++ if (the_class_oop == NULL || !Klass::cast(the_class_oop)->oop_is_instance()) { ++ return false; ++ } ++ return true; ++} + - if (old_index == new_index) { - // no mapping is needed - return; -- } -- ++#ifdef ASSERT ++ ++void VM_RedefineClasses::verify_classes(klassOop k_oop_latest, oop initiating_loader, TRAPS) { ++ klassOop k_oop = k_oop_latest; ++ while (k_oop != NULL) { ++ ++ instanceKlassHandle k_handle(THREAD, k_oop); ++ Verifier::verify(k_handle, Verifier::ThrowException, true, true, THREAD); ++ k_oop = k_oop->klass_part()->old_version(); + } ++} + - _index_map_p->at_put(old_index, new_index); - _index_map_count++; -- ++#endif + - RC_TRACE(0x00040000, ("mapped tag %d at index %d to %d", - scratch_cp->tag_at(old_index).value(), old_index, new_index)); -} // end map_index() -- ++// Rewrite faster byte-codes back to their slower equivalent. Undoes rewriting happening in templateTable_xxx.cpp ++// The reason is that once we zero cpool caches, we need to re-resolve all entries again. Faster bytecodes do not ++// do that, they assume that cache entry is resolved already. ++void VM_RedefineClasses::unpatch_bytecode(methodOop method) { ++ RawBytecodeStream bcs(method); ++ Bytecodes::Code code; ++ Bytecodes::Code java_code; ++ while (!bcs.is_last_bytecode()) { ++ code = bcs.raw_next(); ++ address bcp = bcs.bcp(); + - -// Merge old_cp and scratch_cp and return the results of the merge via -// merge_cp_p. The number of entries in *merge_cp_p is returned via @@ -5655,7 +6007,17 @@ index eb52388..432e15a 100644 - // just copy the entry to *merge_cp_p - constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0); - break; -- } ++ if (code == Bytecodes::_breakpoint) { ++ int bci = method->bci_from(bcp); ++ code = method->orig_bytecode_at(bci); ++ java_code = Bytecodes::java_code(code); ++ if (code != java_code && ++ (java_code == Bytecodes::_getfield || ++ java_code == Bytecodes::_putfield || ++ java_code == Bytecodes::_aload_0)) { ++ // Let breakpoint table handling unpatch bytecode ++ method->set_orig_bytecode_at(bci, java_code); + } - } // end for each old_cp entry - - // We don't need to sanity check that *merge_cp_length_p is within @@ -5862,7 +6224,7 @@ index eb52388..432e15a 100644 - - merge_cp()->set_is_conc_safe(true); - merge_cp = constantPoolHandle(); // toss the merged constant pool -- } else { + } 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 - // and merged constant pools are supersets of the new constant @@ -5889,9 +6251,15 @@ index eb52388..432e15a 100644 - ("index_map[%d]: old=%d new=%d", count, i, value)); - count++; - } -- } -- } -- ++ java_code = Bytecodes::java_code(code); ++ if (code != java_code && ++ (java_code == Bytecodes::_getfield || ++ java_code == Bytecodes::_putfield || ++ java_code == Bytecodes::_aload_0)) { ++ *bcp = java_code; + } + } + - // We have entries mapped between the new and merged constant pools - // so we have to rewrite some constant pool references. - if (!rewrite_cp_refs(scratch_class, THREAD)) { @@ -5978,12 +6346,19 @@ index eb52388..432e15a 100644 - if (!new_method.is_null()) { - // the method has been replaced so save the new method version - methods->obj_at_put(i, new_method()); -- } -- } ++ // Additionally, we need to unpatch bytecode at bcp+1 for fast_xaccess (which would be fast field access) ++ if (code == Bytecodes::_fast_iaccess_0 || code == Bytecodes::_fast_aaccess_0 || code == Bytecodes::_fast_faccess_0) { ++ Bytecodes::Code code2 = Bytecodes::code_or_bp_at(bcp + 1); ++ assert(code2 == Bytecodes::_fast_igetfield || ++ code2 == Bytecodes::_fast_agetfield || ++ code2 == Bytecodes::_fast_fgetfield, ""); ++ *(bcp + 1) = Bytecodes::java_code(code2); + } + } - - return true; --} -- + } + - -// Rewrite constant pool references in the specific method. This code -// was adapted from Rewriter::rewrite_method(). @@ -6113,20 +6488,7 @@ index eb52388..432e15a 100644 - Bytes::put_Java_u2(p, new_index); - } - } break; -+ u2 num = the_class->next_method_idnum(); -+ if (num == constMethodOopDesc::UNSET_IDNUM) { -+ // cannot add any more methods -+ result = result | Klass::ModifyClass; -+ } -+ u2 new_num = k_new_method->method_idnum(); -+ methodOop idnum_owner = new_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, new_class); - } +- } - } // end for each bytecode -} // end rewrite_cp_refs_in_method() - @@ -6134,53 +6496,23 @@ index eb52388..432e15a 100644 -// Rewrite constant pool references in the class_annotations field. -bool VM_RedefineClasses::rewrite_cp_refs_in_class_annotations( - instanceKlassHandle scratch_class, TRAPS) { -+ TRACE_RC1("Method added: new: %s [%d]", -+ k_new_method->name_and_sig_as_C_string(), ni); -+ ++ni; // advance to next new method -+ break; -+ case deleted: -+ // method deleted, see if it is OK -+ old_flags = (jushort) k_old_method->access_flags().get_flags(); -+ if ((old_flags & JVM_ACC_PRIVATE) == 0 -+ // hack: private should be treated as final, but alas -+ || (old_flags & (JVM_ACC_FINAL|JVM_ACC_STATIC)) == 0 -+ ) { -+ // deleted methods must be private -+ result = result | Klass::ModifyClass; -+ } -+ TRACE_RC1("Method deleted: old: %s [%d]", -+ k_old_method->name_and_sig_as_C_string(), oi); -+ ++oi; // advance to next old method -+ break; -+ default: -+ ShouldNotReachHere(); -+ } -+ } - +- - typeArrayHandle class_annotations(THREAD, - scratch_class->class_annotations()); - if (class_annotations.is_null() || class_annotations->length() == 0) { - // no class_annotations so nothing to do - return true; -+ if (new_class()->size() != new_class->old_version()->size()) { -+ result |= Klass::ModifyClassSize; - } - +- } +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("class_annotations length=%d", class_annotations->length())); -+ if (new_class->size_helper() != ((instanceKlass*)(new_class->old_version()->klass_part()))->size_helper()) { -+ result |= Klass::ModifyInstanceSize; -+ } - +- - int byte_i = 0; // byte index into class_annotations - return rewrite_cp_refs_in_annotations_typeArray(class_annotations, byte_i, - THREAD); -+ // (tw) Check method bodies to be able to return NoChange? -+ return result; - } - -+void VM_RedefineClasses::calculate_instance_update_information(klassOop new_version) { - +-} +- +- -// Rewrite constant pool references in an annotations typeArray. This -// "structure" is adapted from the RuntimeVisibleAnnotations_attribute -// that is described in section 4.8.15 of the 2nd-edition of the VM spec: @@ -6199,21 +6531,14 @@ index eb52388..432e15a 100644 - ("length() is too small for num_annotations field")); - return false; - } -+ class CalculateFieldUpdates : public FieldClosure { - +- - u2 num_annotations = Bytes::get_Java_u2((address) - annotations_typeArray->byte_at_addr(byte_i_ref)); - byte_i_ref += 2; -+ private: -+ instanceKlass* _old_ik; -+ GrowableArray<int> _update_info; -+ int _position; -+ bool _copy_backwards; - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("num_annotations=%d", num_annotations)); -+ public: - +- - int calc_num_annotations = 0; - for (; calc_num_annotations < num_annotations; calc_num_annotations++) { - if (!rewrite_cp_refs_in_annotation_struct(annotations_typeArray, @@ -6222,25 +6547,14 @@ index eb52388..432e15a 100644 - ("bad annotation_struct at %d", calc_num_annotations)); - // propagate failure back to caller - return false; -+ bool does_copy_backwards() { -+ return _copy_backwards; - } +- } - } - assert(num_annotations == calc_num_annotations, "sanity check"); - +- - return true; -} // end rewrite_cp_refs_in_annotations_typeArray() -+ CalculateFieldUpdates(instanceKlass* old_ik) : -+ _old_ik(old_ik), _position(instanceOopDesc::base_offset_in_bytes()), _copy_backwards(false) { -+ _update_info.append(_position); -+ _update_info.append(0); -+ } - -+ GrowableArray<int> &finish() { -+ _update_info.append(0); -+ return _update_info; -+ } - +- +- -// Rewrite constant pool references in the annotation struct portion of -// an annotations_typeArray. This "structure" is from section 4.8.15 of -// the 2nd-edition of the VM spec: @@ -6262,33 +6576,19 @@ index eb52388..432e15a 100644 - ("length() is too small for annotation_struct")); - return false; - } -+ void do_field(fieldDescriptor* fd) { -+ int alignment = fd->offset() - _position; -+ if (alignment > 0) { -+ // This field was aligned, so we need to make sure that we fill the gap -+ fill(alignment); -+ } - +- - u2 type_index = rewrite_cp_ref_in_annotation_data(annotations_typeArray, - byte_i_ref, "mapped old type_index=%d", THREAD); -+ assert(_position == fd->offset(), "must be correct offset!"); - +- - u2 num_element_value_pairs = Bytes::get_Java_u2((address) - annotations_typeArray->byte_at_addr( - byte_i_ref)); - byte_i_ref += 2; -+ fieldDescriptor old_fd; -+ if (_old_ik->find_field(fd->name(), fd->signature(), false, &old_fd) != NULL) { -+ // Found field in the old class, copy -+ copy(old_fd.offset(), type2aelembytes(fd->field_type())); - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("type_index=%d num_element_value_pairs=%d", type_index, - num_element_value_pairs)); -+ if (old_fd.offset() < fd->offset()) { -+ _copy_backwards = true; -+ } - +- - int calc_num_element_value_pairs = 0; - for (; calc_num_element_value_pairs < num_element_value_pairs; - calc_num_element_value_pairs++) { @@ -6298,20 +6598,12 @@ index eb52388..432e15a 100644 - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("length() is too small for element_name_index")); - return false; -+ // Transfer special flags -+ fd->set_is_field_modification_watched(old_fd.is_field_modification_watched()); -+ fd->set_is_field_access_watched(old_fd.is_field_access_watched()); -+ } else { -+ // New field, fill -+ fill(type2aelembytes(fd->field_type())); -+ } - } - +- } +- - u2 element_name_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old element_name_index=%d", THREAD); -+ private: - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("element_name_index=%d", element_name_index)); - @@ -6321,14 +6613,7 @@ index eb52388..432e15a 100644 - ("bad element_value at %d", calc_num_element_value_pairs)); - // propagate failure back to caller - return false; -+ void fill(int size) { -+ if (_update_info.length() > 0 && _update_info.at(_update_info.length() - 1) < 0) { -+ (*_update_info.adr_at(_update_info.length() - 1)) -= size; -+ } else { -+ _update_info.append(-size); -+ } -+ _position += size; - } +- } - } // end for each component - assert(num_element_value_pairs == calc_num_element_value_pairs, - "sanity check"); @@ -6382,19 +6667,14 @@ index eb52388..432e15a 100644 -// -bool VM_RedefineClasses::rewrite_cp_refs_in_element_value( - typeArrayHandle 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 - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("length() is too small for a tag")); - return false; - } -+ void copy(int offset, int size) { -+ int prev_end = -1; -+ if (_update_info.length() > 0 && _update_info.at(_update_info.length() - 1) > 0) { -+ prev_end = _update_info.at(_update_info.length() - 2) + _update_info.at(_update_info.length() - 1); -+ } - +- - u1 tag = annotations_typeArray->byte_at(byte_i_ref); - byte_i_ref++; - RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("tag='%c'", tag)); @@ -6422,59 +6702,27 @@ index eb52388..432e15a 100644 - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("length() is too small for a const_value_index")); - return false; -+ if (prev_end == offset) { -+ (*_update_info.adr_at(_update_info.length() - 2)) += size; -+ } else { -+ _update_info.append(size); -+ _update_info.append(offset); - } - +- } +- - u2 const_value_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old const_value_index=%d", THREAD); -+ _position += size; -+ } -+ }; - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("const_value_index=%d", const_value_index)); - } break; -+ instanceKlass* ik = instanceKlass::cast(new_version); -+ instanceKlass* old_ik = instanceKlass::cast(new_version->klass_part()->old_version()); -+ CalculateFieldUpdates cl(old_ik); -+ ik->do_nonstatic_fields(&cl); - +- - case 'e': - { - // for the above tag value, value.enum_const_value is right union field -+ GrowableArray<int> result = cl.finish(); -+ ik->store_update_information(result); -+ ik->set_copying_backwards(cl.does_copy_backwards()); - +- - if ((byte_i_ref + 4) > annotations_typeArray->length()) { - // not enough room for a enum_const_value - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("length() is too small for a enum_const_value")); - return false; -+ IF_TRACE_RC2 { -+ TRACE_RC2("Instance update information for %s:", new_version->klass_part()->name()->as_C_string()); -+ if (cl.does_copy_backwards()) { -+ TRACE_RC2("\tDoes copy backwards!"); -+ } -+ for (int i=0; i<result.length(); i++) { -+ int curNum = result.at(i); -+ if (curNum < 0) { -+ TRACE_RC2("\t%d CLEAN", curNum); -+ } else if (curNum > 0) { -+ TRACE_RC2("\t%d COPY from %d", curNum, result.at(i + 1)); -+ i++; -+ } else { -+ TRACE_RC2("\tEND"); - } -+ } -+ } -+} - +- } +- - u2 type_name_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old type_name_index=%d", THREAD); @@ -6482,37 +6730,23 @@ index eb52388..432e15a 100644 - u2 const_name_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old const_name_index=%d", THREAD); -+void VM_RedefineClasses::rollback() { -+ TRACE_RC1("Rolling back redefinition!"); -+ SystemDictionary::rollback_redefinition(); - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("type_name_index=%d const_name_index=%d", type_name_index, - const_name_index)); - } break; -+ TRACE_RC1("After rolling back system dictionary!"); -+ for (int i=0; i<_new_classes->length(); i++) { -+ SystemDictionary::remove_from_hierarchy(_new_classes->at(i)); -+ } - +- - case 'c': - { - // for the above tag value, value.class_info_index is right union field -+ for (int i=0; i<_new_classes->length(); i++) { -+ instanceKlassHandle new_class = _new_classes->at(i); -+ new_class->set_redefining(false); -+ new_class->old_version()->klass_part()->set_new_version(NULL); -+ new_class->set_old_version(NULL); -+ } - +- - if ((byte_i_ref + 2) > annotations_typeArray->length()) { - // not enough room for a class_info_index - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("length() is too small for a class_info_index")); - return false; - } -+} - +- - u2 class_info_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old class_info_index=%d", THREAD); @@ -6530,13 +6764,7 @@ index eb52388..432e15a 100644 - return false; - } - break; -+void VM_RedefineClasses::swap_marks(oop first, oop second) { -+ markOop first_mark = first->mark(); -+ markOop second_mark = second->mark(); -+ first->set_mark(second_mark); -+ second->set_mark(first_mark); -+} - +- - case '[': - { - if ((byte_i_ref + 2) > annotations_typeArray->length()) { @@ -6545,7 +6773,7 @@ index eb52388..432e15a 100644 - ("length() is too small for a num_values field")); - return false; - } - +- - // 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) @@ -6561,39 +6789,8 @@ index eb52388..432e15a 100644 - ("bad nested element_value at %d", calc_num_values)); - // propagate failure back to caller - return false; -+class FieldCopier : public FieldClosure { -+ public: -+ void do_field(fieldDescriptor* fd) { -+ instanceKlass* cur = instanceKlass::cast(fd->field_holder()); -+ oop cur_oop = cur->java_mirror(); -+ -+ instanceKlass* old = instanceKlass::cast(cur->old_version()); -+ oop old_oop = old->java_mirror(); -+ -+ fieldDescriptor result; -+ bool found = old->find_local_field(fd->name(), fd->signature(), &result); -+ if (found && result.is_static()) { -+ TRACE_RC3("Copying static field value for field %s old_offset=%d new_offset=%d", -+ fd->name()->as_C_string(), result.offset(), fd->offset()); -+ memcpy(cur_oop->obj_field_addr<HeapWord>(fd->offset()), -+ old_oop->obj_field_addr<HeapWord>(result.offset()), -+ type2aelembytes(fd->field_type())); -+ -+ // Static fields may have references to java.lang.Class -+ if (fd->field_type() == T_OBJECT) { -+ oop oop = cur_oop->obj_field(fd->offset()); -+ if (oop != NULL && oop->is_instanceMirror()) { -+ klassOop klass = java_lang_Class::as_klassOop(oop); -+ if (klass != NULL && klass->klass_part()->oop_is_instance()) { -+ assert(oop == instanceKlass::cast(klass)->java_mirror(), "just checking"); -+ if (klass->klass_part()->new_version() != NULL) { -+ oop = instanceKlass::cast(klass->klass_part()->new_version())->java_mirror(); -+ -+ cur_oop->obj_field_put(fd->offset(), oop); -+ } -+ } - } - } +- } +- } - assert(num_values == calc_num_values, "sanity check"); - } break; - @@ -6612,25 +6809,15 @@ index eb52388..432e15a 100644 - - objArrayHandle fields_annotations(THREAD, - scratch_class->fields_annotations()); -+ } -+ } -+}; - +- - if (fields_annotations.is_null() || fields_annotations->length() == 0) { - // no fields_annotations so nothing to do - return true; -+void VM_RedefineClasses::mark_as_scavengable(nmethod* nm) { -+ if (!nm->on_scavenge_root_list()) { -+ CodeCache::add_scavenge_root_nmethod(nm); - } -+} - +- } +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("fields_annotations length=%d", fields_annotations->length())); -+struct StoreBarrier { -+ template <class T> static void oop_store(T* p, oop v) { ::oop_store(p, v); } -+}; - +- - for (int i = 0; i < fields_annotations->length(); i++) { - typeArrayHandle field_annotations(THREAD, - (typeArrayOop)fields_annotations->obj_at(i)); @@ -6638,10 +6825,7 @@ index eb52388..432e15a 100644 - // this field does not have any annotations so skip it - continue; - } -+struct StoreNoBarrier { -+ template <class T> static void oop_store(T* p, oop v) { oopDesc::encode_store_heap_oop_not_null(p, v); } -+}; - +- - int byte_i = 0; // byte index into field_annotations - if (!rewrite_cp_refs_in_annotations_typeArray(field_annotations, byte_i, - THREAD)) { @@ -6649,33 +6833,9 @@ index eb52388..432e15a 100644 - ("bad field_annotations at %d", i)); - // propagate failure back to caller - return false; -+template <class S> -+class ChangePointersOopClosure : public OopClosureNoHeader { -+ // Forward pointers to instanceKlass and mirror class to new versions -+ template <class T> -+ inline void do_oop_work(T* p) { -+ oop oop = oopDesc::load_decode_heap_oop(p); -+ if (oop == NULL) { -+ return; -+ } -+ if (oop->is_instanceKlass()) { -+ klassOop klass = (klassOop) oop; -+ if (klass->klass_part()->new_version() != NULL) { -+ oop = klass->klass_part()->new_version(); -+ S::oop_store(p, oop); -+ } -+ } else if (oop->is_instanceMirror()) { -+ klassOop klass = java_lang_Class::as_klassOop(oop); -+ if (klass != NULL && klass->klass_part()->oop_is_instance()) { -+ assert(oop == instanceKlass::cast(klass)->java_mirror(), "just checking"); -+ if (klass->klass_part()->new_version() != NULL) { -+ oop = instanceKlass::cast(klass->klass_part()->new_version())->java_mirror(); -+ S::oop_store(p, oop); -+ } -+ } - } - } - +- } +- } +- - return true; -} // end rewrite_cp_refs_in_fields_annotations() - @@ -6686,25 +6846,15 @@ index eb52388..432e15a 100644 - - objArrayHandle methods_annotations(THREAD, - scratch_class->methods_annotations()); -+ virtual void do_oop(oop* o) { -+ do_oop_work(o); -+ } - +- - if (methods_annotations.is_null() || methods_annotations->length() == 0) { - // no methods_annotations so nothing to do - return true; -+ virtual void do_oop(narrowOop* o) { -+ do_oop_work(o); - } -+}; - +- } +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_annotations length=%d", methods_annotations->length())); -+void VM_RedefineClasses::doit() { -+ Thread *thread = Thread::current(); -+ -+ TRACE_RC1("Entering doit!"); - +- - for (int i = 0; i < methods_annotations->length(); i++) { - typeArrayHandle method_annotations(THREAD, - (typeArrayOop)methods_annotations->obj_at(i)); @@ -6712,8 +6862,7 @@ index eb52388..432e15a 100644 - // this method does not have any annotations so skip it - continue; - } -+ assert((_max_redefinition_flags & Klass::RemoveSuperType) == 0, "removing super types not allowed"); - +- - int byte_i = 0; // byte index into method_annotations - if (!rewrite_cp_refs_in_annotations_typeArray(method_annotations, byte_i, - THREAD)) { @@ -6721,35 +6870,13 @@ index eb52388..432e15a 100644 - ("bad method_annotations at %d", i)); - // propagate failure back to caller - return false; -+ if (UseSharedSpaces) { -+ // Sharing is enabled so we remap the shared readonly space to -+ // 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()) { -+ TRACE_RC1("failed to remap shared readonly space to readwrite, private"); -+ _result = JVMTI_ERROR_INTERNAL; -+ return; - } - } -+ -+ RC_TIMER_START(_timer_prepare_redefinition); -+ for (int i = 0; i < _new_classes->length(); i++) { -+ redefine_single_class(_new_classes->at(i), thread); -+ } -+ -+ // Deoptimize all compiled code that depends on this class -+ flush_dependent_code(instanceKlassHandle(Thread::current(), (klassOop)NULL), Thread::current()); - +- } +- } +- - return true; -} // end rewrite_cp_refs_in_methods_annotations() -+ // Adjust constantpool caches and vtables for all classes -+ // that reference methods of the evolved class. -+ SystemDictionary::classes_do(adjust_cpool_cache, Thread::current()); - -+ RC_TIMER_STOP(_timer_prepare_redefinition); -+ RC_TIMER_START(_timer_heap_iteration); - +- +- -// Rewrite constant pool references in a methods_parameter_annotations -// field. This "structure" is adapted from the -// RuntimeVisibleParameterAnnotations_attribute described in section @@ -6765,28 +6892,20 @@ index eb52388..432e15a 100644 -// -bool VM_RedefineClasses::rewrite_cp_refs_in_methods_parameter_annotations( - instanceKlassHandle scratch_class, TRAPS) { -+ class ChangePointersObjectClosure : public ObjectClosure { - +- - objArrayHandle methods_parameter_annotations(THREAD, - scratch_class->methods_parameter_annotations()); -+ private: - +- - if (methods_parameter_annotations.is_null() - || methods_parameter_annotations->length() == 0) { - // no methods_parameter_annotations so nothing to do - return true; - } -+ OopClosureNoHeader *_closure; -+ bool _needs_instance_update; -+ oop _tmp_obj; -+ int _tmp_obj_size; - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_parameter_annotations length=%d", - methods_parameter_annotations->length())); -+ public: -+ ChangePointersObjectClosure(OopClosureNoHeader *closure) : _closure(closure), _needs_instance_update(false), _tmp_obj(NULL), _tmp_obj_size(0) {} - +- - for (int i = 0; i < methods_parameter_annotations->length(); i++) { - typeArrayHandle method_parameter_annotations(THREAD, - (typeArrayOop)methods_parameter_annotations->obj_at(i)); @@ -6795,77 +6914,22 @@ index eb52388..432e15a 100644 - // this method does not have any parameter annotations so skip it - continue; - } -+ bool needs_instance_update() { -+ return _needs_instance_update; -+ } - +- - if (method_parameter_annotations->length() < 1) { - // not enough room for a num_parameters field - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("length() is too small for a num_parameters field at %d", i)); - return false; - } -+ void copy_to_tmp(oop o) { -+ int size = o->size(); -+ if (_tmp_obj_size < size) { -+ _tmp_obj_size = size; -+ _tmp_obj = (oop)resource_allocate_bytes(size * HeapWordSize); -+ } -+ Copy::aligned_disjoint_words((HeapWord*)o, (HeapWord*)_tmp_obj, size); -+ } - +- - int byte_i = 0; // byte index into method_parameter_annotations -+ virtual void do_object(oop obj) { -+ if (obj->is_instanceKlass()) return; -+ if (obj->is_instanceMirror()) { -+ // static fields may have references to old java.lang.Class instances, update them -+ // at the same time, we don't want to update other oops in the java.lang.Class -+ // Causes SIGSEGV? -+ //instanceMirrorKlass::oop_fields_iterate(obj, _closure); -+ } else { -+ obj->oop_iterate(_closure); -+ } - +- - u1 num_parameters = method_parameter_annotations->byte_at(byte_i); - byte_i++; -+ if (obj->blueprint()->new_version() != NULL) { -+ Klass* new_klass = obj->blueprint()->new_version()->klass_part(); -+ if (obj->is_perm()) { -+ _needs_instance_update = true; -+ } else if(new_klass->update_information() != NULL) { -+ int size_diff = obj->size() - obj->size_given_klass(new_klass); -+ -+ // Either new size is bigger or gap is to small to be filled -+ if (size_diff < 0 || (size_diff > 0 && (size_t) size_diff < CollectedHeap::min_fill_size())) { -+ // We need an instance update => set back to old klass -+ _needs_instance_update = true; -+ } else { -+ oop src = obj; -+ if (new_klass->is_copying_backwards()) { -+ copy_to_tmp(obj); -+ src = _tmp_obj; -+ } -+ src->set_klass_no_check(obj->blueprint()->new_version()); -+ MarkSweep::update_fields(obj, src, new_klass->update_information()); - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("num_parameters=%d", num_parameters)); -+ if (size_diff > 0) { -+ HeapWord* dead_space = ((HeapWord *)obj) + obj->size(); -+ CollectedHeap::fill_with_object(dead_space, size_diff); -+ } -+ } -+ } else { -+ obj->set_klass_no_check(obj->blueprint()->new_version()); -+ } -+ } -+ } -+ }; -+ -+ ChangePointersOopClosure<StoreNoBarrier> oopClosureNoBarrier; -+ ChangePointersOopClosure<StoreBarrier> oopClosure; -+ ChangePointersObjectClosure objectClosure(&oopClosure); - +- - int calc_num_parameters = 0; - for (; calc_num_parameters < num_parameters; calc_num_parameters++) { - if (!rewrite_cp_refs_in_annotations_typeArray( @@ -6874,32 +6938,15 @@ index eb52388..432e15a 100644 - ("bad method_parameter_annotations at %d", calc_num_parameters)); - // propagate failure back to caller - return false; -+ { -+ // Since we may update oops inside nmethod's code blob to point to java.lang.Class in new generation, we need to -+ // make sure such references are properly recognized by GC. For that, If ScavengeRootsInCode is true, we need to -+ // mark such nmethod's as "scavengable". -+ // For now, mark all nmethod's as scavengable that are not scavengable already -+ if (ScavengeRootsInCode) { -+ CodeCache::nmethods_do(mark_as_scavengable); - } -+ -+ SharedHeap::heap()->gc_prologue(true); -+ Universe::heap()->object_iterate(&objectClosure); -+ Universe::root_oops_do(&oopClosureNoBarrier); -+ SharedHeap::heap()->gc_epilogue(false); - } +- } +- } - assert(num_parameters == calc_num_parameters, "sanity check"); - } - +- - return true; -} // end rewrite_cp_refs_in_methods_parameter_annotations() - -+ for (int i=0; i<_new_classes->length(); i++) { -+ klassOop cur_oop = _new_classes->at(i)(); -+ instanceKlass* cur = instanceKlass::cast(cur_oop); -+ klassOop old_oop = cur->old_version(); -+ instanceKlass* old = instanceKlass::cast(old_oop); - +- +- -// Rewrite constant pool references in a methods_default_annotations -// field. This "structure" is adapted from the AnnotationDefault_attribute -// that is described in section 4.8.19 of the 2nd-edition of the VM spec: @@ -6910,30 +6957,20 @@ index eb52388..432e15a 100644 -// -bool VM_RedefineClasses::rewrite_cp_refs_in_methods_default_annotations( - instanceKlassHandle scratch_class, TRAPS) { -+ // Swap marks to have same hashcodes -+ swap_marks(cur_oop, old_oop); -+ swap_marks(cur->java_mirror(), old->java_mirror()); - +- - objArrayHandle methods_default_annotations(THREAD, - scratch_class->methods_default_annotations()); -+ // Revert pool holder for old version of klass (it was updated by one of ours closure!) -+ old->constants()->set_pool_holder(old_oop); - +- - if (methods_default_annotations.is_null() - || methods_default_annotations->length() == 0) { - // no methods_default_annotations so nothing to do - return true; - } - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_default_annotations length=%d", - methods_default_annotations->length())); -+ if (old->array_klasses() != NULL) { -+ // Transfer the array classes, otherwise we might get cast exceptions when casting array types. -+ assert(cur->array_klasses() == NULL, "just checking"); -+ cur->set_array_klasses(old->array_klasses()); -+ } - +- - for (int i = 0; i < methods_default_annotations->length(); i++) { - typeArrayHandle method_default_annotations(THREAD, - (typeArrayOop)methods_default_annotations->obj_at(i)); @@ -6941,25 +6978,10 @@ index eb52388..432e15a 100644 - || method_default_annotations->length() == 0) { - // this method does not have any default annotations so skip it - continue; -+ // Initialize the new class! Special static initialization that does not execute the -+ // static constructor but copies static field values from the old class if name -+ // and signature of a static field match. -+ FieldCopier copier; -+ cur->do_local_static_fields(&copier); // TODO (tw): What about internal static fields?? -+ old->set_java_mirror(cur->java_mirror()); -+ -+ // Transfer init state -+ instanceKlass::ClassState state = old->init_state(); -+ if (state > instanceKlass::linked) { -+ cur->set_init_state(state); -+ } - } - +- } +- - int byte_i = 0; // byte index into method_default_annotations -+ RC_TIMER_STOP(_timer_heap_iteration); -+ RC_TIMER_START(_timer_redefinition); -+ if (objectClosure.needs_instance_update()){ - +- - if (!rewrite_cp_refs_in_element_value( - method_default_annotations, byte_i, THREAD)) { - RC_TRACE_WITH_THREAD(0x02000000, THREAD, @@ -6967,29 +6989,12 @@ index eb52388..432e15a 100644 - // propagate failure back to caller - return false; - } -+ // Do a full garbage collection to update the instance sizes accordingly -+ TRACE_RC1("Before performing full GC!"); -+ Universe::set_redefining_gc_run(true); -+ notify_gc_begin(true); -+ Universe::heap()->collect_as_vm_thread(GCCause::_heap_inspection); -+ notify_gc_end(); -+ Universe::set_redefining_gc_run(false); -+ TRACE_RC1("GC done!"); - } - +- } +- - return true; -} // end rewrite_cp_refs_in_methods_default_annotations() -+ // Unmark klassOops as "redefining" -+ for (int i=0; i<_new_classes->length(); i++) { -+ klassOop cur_klass = _new_classes->at(i)(); -+ instanceKlass* cur = (instanceKlass*)cur_klass->klass_part(); -+ cur->set_redefining(false); -+ cur->clear_update_information(); -+ } - -+ // Disable any dependent concurrent compilations -+ SystemDictionary::notice_modification(); - +- +- -// Rewrite constant pool references in the method's stackmap table. -// These "structures" are adapted from the StackMapTable_attribute that -// is described in section 4.8.4 of the 6.0 version of the VM spec @@ -7003,16 +7008,11 @@ index eb52388..432e15a 100644 -// -void VM_RedefineClasses::rewrite_cp_refs_in_stack_map_table( - methodHandle method, TRAPS) { -+ // Set flag indicating that some invariants are no longer true. -+ // See jvmtiExport.hpp for detailed explanation. -+ JvmtiExport::set_has_redefined_a_class(); - +- - if (!method->has_stackmap_table()) { - return; - } -+ // Clean up caches in the compiler interface and compiler threads -+ ciObjectFactory::resort_shared_ci_objects(); - +- - typeArrayOop stackmap_data = method->stackmap_data(); - address stackmap_p = (address)stackmap_data->byte_at_addr(0); - address stackmap_end = stackmap_p + stackmap_data->length(); @@ -7112,8 +7112,7 @@ index eb52388..432e15a 100644 - calc_number_of_entries, frame_type, THREAD); - } - } -+#ifdef ASSERT - +- - // full_frame { - // u1 frame_type = FULL_FRAME; /* 255 */ - // u2 offset_delta; @@ -7134,16 +7133,12 @@ index eb52388..432e15a 100644 - rewrite_cp_refs_in_verification_type_info(stackmap_p, stackmap_end, - calc_number_of_entries, frame_type, THREAD); - } -+ // Universe::verify(); -+ // JNIHandles::verify(); - +- - // Use the largest size for the number_of_stack_items, but only get - // the right number of bytes. - u2 number_of_stack_items = Bytes::get_Java_u2(stackmap_p); - stackmap_p += 2; -+ SystemDictionary::classes_do(check_class, thread); -+#endif - +- - for (u2 stack_i = 0; stack_i < number_of_stack_items; stack_i++) { - rewrite_cp_refs_in_verification_type_info(stackmap_p, stackmap_end, - calc_number_of_entries, frame_type, THREAD); @@ -7152,13 +7147,8 @@ index eb52388..432e15a 100644 - } // end while there is a stack_map_frame - assert(number_of_entries == calc_number_of_entries, "sanity check"); -} // end rewrite_cp_refs_in_stack_map_table() -+ RC_TIMER_STOP(_timer_redefinition); - -+ if (TraceRedefineClasses > 0) { -+ tty->flush(); -+ } -+} - +- +- -// Rewrite constant pool references in the verification type info -// portion of the method's stackmap table. These "structures" are -// adapted from the StackMapTable_attribute that is described in @@ -7226,8 +7216,7 @@ index eb52388..432e15a 100644 - case ITEM_UninitializedThis: - // nothing more to do for the above tag types - break; -+void VM_RedefineClasses::doit_epilogue() { - +- - // Object_variable_info { - // u1 tag = ITEM_Object; /* 7 */ - // u2 cpool_index; @@ -7258,8 +7247,7 @@ index eb52388..432e15a 100644 - assert(stackmap_p_ref + 2 <= stackmap_end, "no room for offset"); - stackmap_p_ref += 2; - break; -+ RC_TIMER_START(_timer_vm_op_epilogue); - +- - default: - RC_TRACE_WITH_THREAD(0x04000000, THREAD, - ("frame_i=%u, frame_type=%u, bad tag=0x%x", frame_i, frame_type, tag)); @@ -7464,33 +7452,36 @@ index eb52388..432e15a 100644 - } - } // end for each local variable table entry - } // end if there are local variable table entries -+ //unlock_threads(); - +- - 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() -+ ResourceMark mark; - -+ VM_GC_Operation::doit_epilogue(); -+ TRACE_RC1("GC Operation epilogue finished! "); - +- +- -// 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 ++// Unevolving classes may point to old methods directly + // from their constant pool caches, itables, and/or vtables. We + // use the SystemDictionary::classes_do() facility and this helper -// to fix up these pointers. --// --// Note: We currently don't support updating the vtable in --// arrayKlassOops. See Open Issues in jvmtiRedefineClasses.hpp. ++// to fix up these pointers. Additional field offsets and vtable indices ++// in the constant pool cache entries are fixed. + // + // 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(); - if (k->oop_is_instance()) { - HandleMark hm(THREAD); - instanceKlass *ik = (instanceKlass *) k; -+ // Free the array of scratch classes -+ delete _new_classes; -+ _new_classes = NULL; ++void VM_RedefineClasses::adjust_cpool_cache(klassOop k_oop_latest, oop initiating_loader, TRAPS) { ++ klassOop k_oop = k_oop_latest; ++ while (k_oop != NULL) { ++ Klass *k = k_oop->klass_part(); ++ if (k->oop_is_instance()) { ++ HandleMark hm(THREAD); ++ instanceKlass *ik = (instanceKlass *) k; - // HotSpot specific optimization! HotSpot does not currently - // support delegation from the bootstrap class loader to a @@ -7509,21 +7500,25 @@ index eb52388..432e15a 100644 - if (is_user_defined && ik->class_loader() == NULL) { - return; - } -+ // Free the array of affected classes -+ delete _affected_klasses; -+ _affected_klasses = NULL; ++ constantPoolHandle other_cp; ++ constantPoolCacheOop cp_cache; - // This is a very busy routine. We don't want too much tracing - // printed out. - bool trace_name_printed = false; -- ++ other_cp = constantPoolHandle(ik->constants()); + - // Very noisy: only enable this call if you are trying to determine - // that a specific class gets found by this routine. - // RC_TRACE macro has an embedded ResourceMark - // RC_TRACE_WITH_THREAD(0x00100000, THREAD, - // ("adjust check: name=%s", ik->external_name())); - // trace_name_printed = true; -- ++ for (int i=0; i<other_cp->length(); i++) { ++ if (other_cp->tag_at(i).is_klass()) { ++ klassOop klass = other_cp->klass_at(i, THREAD); ++ if (klass->klass_part()->new_version() != NULL) { + - // 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 @@ -7537,7 +7532,14 @@ index eb52388..432e15a 100644 - _matching_methods_length, - &trace_name_printed); - } -- ++ // (tw) TODO: check why/if this is necessary ++ other_cp->klass_at_put(i, klass->klass_part()->new_version()); ++ } ++ klass = other_cp->klass_at(i, THREAD); ++ assert(klass->klass_part()->new_version() == NULL, "Must be new klass!"); ++ } ++ } + - // If the current class has an itable and we are either redefining an - // 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 @@ -7553,7 +7555,8 @@ index eb52388..432e15a 100644 - _matching_methods_length, - &trace_name_printed); - } -- ++ cp_cache = other_cp->cache(); + - // The constant pools in other classes (other_cp) can refer to - // methods in the_class. We have to update method information in - // other_cp's cache. If other_cp has a previous version, then we @@ -7569,7 +7572,10 @@ index eb52388..432e15a 100644 - // that case. - constantPoolHandle other_cp; - constantPoolCacheOop cp_cache; -- ++ if (cp_cache != NULL) { ++ cp_cache->adjust_entries(); ++ } + - if (k_oop != _the_class_oop) { - // this klass' constant pool cache may need adjustment - other_cp = constantPoolHandle(ik->constants()); @@ -7579,8 +7585,11 @@ index eb52388..432e15a 100644 - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); -- } -- } ++ // If bytecode rewriting is enabled, we also need to unpatch bytecode to force resolution of zeroed entries ++ if (RewriteBytecodes) { ++ ik->methods_do(unpatch_bytecode); + } + } - { - ResourceMark rm(THREAD); - // PreviousVersionInfo objects returned via PreviousVersionWalker @@ -7603,23 +7612,48 @@ index eb52388..432e15a 100644 - } - } // pvw is cleaned up - } // rm is cleaned up -- } --} -+ TRACE_RC1("Redefinition finished!"); ++ k_oop = k_oop->klass_part()->old_version(); + } + } --void VM_RedefineClasses::update_jmethod_ids() { -- for (int j = 0; j < _matching_methods_length; ++j) { + void VM_RedefineClasses::update_jmethod_ids() { + for (int j = 0; j < _matching_methods_length; ++j) { - methodOop 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 ++ methodOop old_method = (methodOop)_old_methods->obj_at(_matching_old_methods[j]); ++ TRACE_RC3("matching method %s", old_method->name_and_sig_as_C_string()); ++ + jmethodID jmid = old_method->find_jmethod_id_or_null(); ++ if (old_method->new_version() != NULL && jmid == NULL) { ++ // (tw) Have to create jmethodID in this case ++ jmid = old_method->jmethod_id(); ++ } ++ + 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); ++ methodHandle new_method_h((methodOop)_new_methods->obj_at(_matching_new_methods[j])); ++ if (old_method->new_version() == NULL) { ++ methodHandle old_method_h((methodOop)_old_methods->obj_at(_matching_old_methods[j])); ++ jmethodID new_jmethod_id = JNIHandles::make_jmethod_id(old_method_h); ++ bool result = instanceKlass::cast(old_method_h->method_holder())->update_jmethod_id(old_method_h(), new_jmethod_id); ++ //TRACE_RC3("Changed jmethodID for old method assigned to %d / result=%d", new_jmethod_id, result); ++ //TRACE_RC3("jmethodID new method: %d jmethodID old method: %d", new_method_h->jmethod_id(), old_method->jmethod_id()); ++ } else { ++ jmethodID mid = new_method_h->jmethod_id(); ++ bool result = instanceKlass::cast(new_method_h->method_holder())->update_jmethod_id(new_method_h(), jmid); ++ //TRACE_RC3("Changed jmethodID for new method assigned to %d / result=%d", jmid, result); ++ } + JNIHandles::change_method_associated_with_jmethod_id(jmid, new_method_h); - assert(JNIHandles::resolve_jmethod_id(jmid) == _matching_new_methods[j], - "should be replaced"); -- } -- } -+ RC_TIMER_STOP(_timer_vm_op_epilogue); ++ //TRACE_RC3("changing method associated with jmethod id %d to %s", (int)jmid, new_method_h->name()->as_C_string()); ++ assert(JNIHandles::resolve_jmethod_id(jmid) == (methodOop)_new_methods->obj_at(_matching_new_methods[j]), "should be replaced"); ++ jmethodID mid = ((methodOop)_new_methods->obj_at(_matching_new_methods[j]))->jmethod_id(); ++ assert(JNIHandles::resolve_non_null((jobject)mid) == new_method_h(), "must match!"); ++ ++ //TRACE_RC3("jmethodID new method: %d jmethodID old method: %d", new_method_h->jmethod_id(), old_method->jmethod_id()); + } + } } -void VM_RedefineClasses::check_methods_and_mark_as_obsolete( @@ -7631,14 +7665,116 @@ index eb52388..432e15a 100644 - methodOop old_method = _matching_old_methods[j]; - methodOop new_method = _matching_new_methods[j]; - methodOop 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) { - ++old_index; -- } -- ++// Deoptimize all compiled code that depends on this class. ++// ++// If the can_redefine_classes capability is obtained in the onload ++// phase then the compiler has recorded all dependencies from startup. ++// In that case we need only deoptimize and throw away all compiled code ++// that depends on the class. ++// ++// If can_redefine_classes is obtained sometime after the onload ++// phase then the dependency information may be incomplete. In that case ++// the first call to RedefineClasses causes all compiled code to be ++// thrown away. As can_redefine_classes has been obtained then ++// all future compilations will record dependencies so second and ++// subsequent calls to RedefineClasses need only throw away code ++// that depends on the class. ++// ++void VM_RedefineClasses::flush_dependent_code(instanceKlassHandle k_h, TRAPS) { ++ assert_locked_or_safepoint(Compile_lock); ++ ++ // All dependencies have been recorded from startup or this is a second or ++ // subsequent use of RedefineClasses ++ ++ // For now deopt all ++ // (tw) TODO: Improve the dependency system such that we can safely deopt only a subset of the methods ++ if (0 && JvmtiExport::all_dependencies_are_recorded()) { ++ Universe::flush_evol_dependents_on(k_h); ++ } else { ++ CodeCache::mark_all_nmethods_for_deoptimization(); ++ ++ ResourceMark rm(THREAD); ++ DeoptimizationMarker dm; ++ ++ // Deoptimize all activations depending on marked nmethods ++ Deoptimization::deoptimize_dependents(); ++ ++ // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies) ++ CodeCache::make_marked_nmethods_not_entrant(); ++ ++ // From now on we know that the dependency information is complete ++ JvmtiExport::set_all_dependencies_are_recorded(true); ++ } ++} ++ ++void VM_RedefineClasses::compute_added_deleted_matching_methods() { ++ methodOop old_method; ++ methodOop new_method; ++ ++ _matching_old_methods = NEW_RESOURCE_ARRAY(int, _old_methods->length()); ++ _matching_new_methods = NEW_RESOURCE_ARRAY(int, _old_methods->length()); ++ _added_methods = NEW_RESOURCE_ARRAY(int, _new_methods->length()); ++ _deleted_methods = NEW_RESOURCE_ARRAY(int, _old_methods->length()); ++ ++ _matching_methods_length = 0; ++ _deleted_methods_length = 0; ++ _added_methods_length = 0; ++ ++ int nj = 0; ++ int oj = 0; ++ while (true) { ++ if (oj >= _old_methods->length()) { ++ if (nj >= _new_methods->length()) { ++ break; // we've looked at everything, done ++ } ++ // New method at the end ++ new_method = (methodOop) _new_methods->obj_at(nj); ++ _added_methods[_added_methods_length++] = nj; ++ ++nj; ++ } else if (nj >= _new_methods->length()) { ++ // Old method, at the end, is deleted ++ old_method = (methodOop) _old_methods->obj_at(oj); ++ _deleted_methods[_deleted_methods_length++] = oj; ++ ++oj; ++ } else { ++ old_method = (methodOop) _old_methods->obj_at(oj); ++ new_method = (methodOop) _new_methods->obj_at(nj); ++ if (old_method->name() == new_method->name()) { ++ if (old_method->signature() == new_method->signature()) { ++ _matching_old_methods[_matching_methods_length ] = oj;//old_method; ++ _matching_new_methods[_matching_methods_length++] = nj;//new_method; ++ ++nj; ++ ++oj; ++ } else { ++ // added overloaded have already been moved to the end, ++ // so this is a deleted overloaded method ++ _deleted_methods[_deleted_methods_length++] = oj;//old_method; ++ ++oj; ++ } ++ } else { // names don't match ++ if (old_method->name()->fast_compare(new_method->name()) > 0) { ++ // new method ++ _added_methods[_added_methods_length++] = nj;//new_method; ++ ++nj; ++ } else { ++ // deleted method ++ _deleted_methods[_deleted_methods_length++] = oj;//old_method; ++ ++oj; ++ } ++ } + } ++ } ++ assert(_matching_methods_length + _deleted_methods_length == _old_methods->length(), "sanity"); ++ assert(_matching_methods_length + _added_methods_length == _new_methods->length(), "sanity"); ++ TRACE_RC3("Matching methods = %d / deleted methods = %d / added methods = %d", _matching_methods_length, _deleted_methods_length, _added_methods_length); ++} + - if (MethodComparator::methods_EMCP(old_method, new_method)) { - // The EMCP definition from JSR-163 requires the bytecodes to be - // the same with the exception of constant pool indices which may @@ -7698,11 +7834,11 @@ index eb52388..432e15a 100644 - // It looks like we will have to live with the limited savings - // that we get from effectively overwriting the old methods - // when the new methods are attached to the_class. -- + - // track which methods are EMCP for add_previous_version() call - emcp_methods->set_bit(old_index); - (*emcp_method_count_p)++; -- + - // An EMCP method is _not_ obsolete. An obsolete method has a - // different jmethodID than the current method. An EMCP method - // has the same jmethodID as the current method. Having the @@ -7713,7 +7849,168 @@ index eb52388..432e15a 100644 - // versions of the method including the current one. - } else { - // mark obsolete methods as such -- old_method->set_is_obsolete(); ++// Install the redefinition of a class: ++// - house keeping (flushing breakpoints and caches, deoptimizing ++// dependent compiled code) ++// - adjusting constant pool caches and vtables in other classes ++void VM_RedefineClasses::redefine_single_class(instanceKlassHandle the_new_class, TRAPS) { ++ ++ ResourceMark rm(THREAD); ++ ++ assert(the_new_class->old_version() != NULL, "Must not be null"); ++ assert(the_new_class->old_version()->klass_part()->new_version() == the_new_class(), "Must equal"); ++ ++ instanceKlassHandle the_old_class = instanceKlassHandle(THREAD, the_new_class->old_version()); ++ ++#ifndef JVMTI_KERNEL ++ // Remove all breakpoints in methods of this class ++ JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints(); ++ jvmti_breakpoints.clearall_in_class_at_safepoint(the_old_class()); ++#endif // !JVMTI_KERNEL ++ ++ if (the_old_class() == Universe::reflect_invoke_cache()->klass()) { ++ // We are redefining java.lang.reflect.Method. Method.invoke() is ++ // cached and users of the cache care about each active version of ++ // the method so we have to track this previous version. ++ // Do this before methods get switched ++ Universe::reflect_invoke_cache()->add_previous_version( ++ the_old_class->method_with_idnum(Universe::reflect_invoke_cache()->method_idnum())); ++ } ++ ++ _old_methods = the_old_class->methods(); ++ _new_methods = the_new_class->methods(); ++ compute_added_deleted_matching_methods(); ++ ++ // track which methods are EMCP for add_previous_version() call below ++ ++ // (tw) TODO: Check if we need the concept of EMCP? ++ BitMap emcp_methods(_old_methods->length()); ++ int emcp_method_count = 0; ++ emcp_methods.clear(); // clears 0..(length() - 1) ++ ++ // We need to mark methods as old!! ++ check_methods_and_mark_as_obsolete(&emcp_methods, &emcp_method_count); ++ update_jmethod_ids(); ++ ++ // TODO: ++ transfer_old_native_function_registrations(the_old_class); ++ ++ ++ ++#ifdef ASSERT ++ ++// klassOop systemLookup1 = SystemDictionary::resolve_or_null(the_old_class->name(), the_old_class->class_loader(), the_old_class->protection_domain(), THREAD); ++// assert(systemLookup1 == the_new_class(), "New class must be in system dictionary!"); ++ ++ //JNIHandles::verify(); ++ ++// klassOop systemLookup = SystemDictionary::resolve_or_null(the_old_class->name(), the_old_class->class_loader(), the_old_class->protection_domain(), THREAD); ++ ++// assert(systemLookup == the_new_class(), "New class must be in system dictionary!"); ++ assert(the_new_class->old_version() != NULL, "Must not be null"); ++ assert(the_new_class->old_version()->klass_part()->new_version() == the_new_class(), "Must equal"); ++ ++ for (int i=0; i<the_new_class->methods()->length(); i++) { ++ assert(((methodOop)the_new_class->methods()->obj_at(i))->method_holder() == the_new_class(), "method holder must match!"); ++ } ++ ++ _old_methods->verify(); ++ _new_methods->verify(); ++ ++ the_new_class->vtable()->verify(tty); ++ the_old_class->vtable()->verify(tty); ++ ++#endif ++ ++ // increment the classRedefinedCount field in the_class and in any ++ // direct and indirect subclasses of the_class ++ increment_class_counter((instanceKlass *)the_old_class()->klass_part(), THREAD); ++ ++} ++ ++ ++void VM_RedefineClasses::check_methods_and_mark_as_obsolete(BitMap *emcp_methods, int * emcp_method_count_p) { ++ TRACE_RC3("Checking matching methods for EMCP"); ++ *emcp_method_count_p = 0; ++ int obsolete_count = 0; ++ int old_index = 0; ++ for (int j = 0; j < _matching_methods_length; ++j, ++old_index) { ++ methodOop old_method = (methodOop)_old_methods->obj_at(_matching_old_methods[j]); ++ methodOop new_method = (methodOop)_new_methods->obj_at(_matching_new_methods[j]); ++ methodOop 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) { ++ ++old_index; ++ } ++ ++ if (MethodComparator::methods_EMCP(old_method, new_method)) { ++ // The EMCP definition from JSR-163 requires the bytecodes to be ++ // the same with the exception of constant pool indices which may ++ // differ. However, the constants referred to by those indices ++ // must be the same. ++ // ++ // We use methods_EMCP() for comparison since constant pool ++ // merging can remove duplicate constant pool entries that were ++ // present in the old method and removed from the rewritten new ++ // method. A faster binary comparison function would consider the ++ // old and new methods to be different when they are actually ++ // EMCP. ++ ++ // track which methods are EMCP for add_previous_version() call ++ emcp_methods->set_bit(old_index); ++ (*emcp_method_count_p)++; ++ ++ // An EMCP method is _not_ obsolete. An obsolete method has a ++ // different jmethodID than the current method. An EMCP method ++ // has the same jmethodID as the current method. Having the ++ // same jmethodID for all EMCP versions of a method allows for ++ // a consistent view of the EMCP methods regardless of which ++ // EMCP method you happen to have in hand. For example, a ++ // breakpoint set in one EMCP method will work for all EMCP ++ // versions of the method including the current one. ++ ++ old_method->set_new_version(new_method); ++ new_method->set_old_version(old_method); ++ ++ TRACE_RC3("Found EMCP method %s", old_method->name_and_sig_as_C_string()); ++ ++ // Transfer breakpoints ++ instanceKlass *ik = instanceKlass::cast(old_method->method_holder()); ++ for (BreakpointInfo* bp = ik->breakpoints(); bp != NULL; bp = bp->next()) { ++ TRACE_RC2("Checking breakpoint"); ++ TRACE_RC2("%d / %d", bp->match(old_method), bp->match(new_method)); ++ if (bp->match(old_method)) { ++ assert(bp->match(new_method), "if old method is method, then new method must match too"); ++ TRACE_RC2("Found a breakpoint in an old EMCP method"); ++ new_method->set_breakpoint(bp->bci()); ++ } ++ } ++ } else { ++ // mark obsolete methods as such ++ old_method->set_is_obsolete(); ++ obsolete_count++; ++ ++ // With tracing we try not to "yack" too much. The position of ++ // this trace assumes there are fewer obsolete methods than ++ // EMCP methods. ++ TRACE_RC3("mark %s(%s) as obsolete", ++ old_method->name()->as_C_string(), ++ old_method->signature()->as_C_string()); ++ } ++ old_method->set_is_old(); ++ } ++ for (int i = 0; i < _deleted_methods_length; ++i) { ++ methodOop old_method = (methodOop)_old_methods->obj_at(_deleted_methods[i]); ++ ++ //assert(old_method->vtable_index() < 0, ++ // "cannot delete methods with vtable entries");; ++ ++ // Mark all deleted methods as old and obsolete ++ old_method->set_is_old(); + old_method->set_is_obsolete(); - obsolete_count++; - - // obsolete methods need a unique idnum @@ -7723,21 +8020,58 @@ index eb52388..432e15a 100644 - old_method->set_method_idnum(num); -// TO DO: attach obsolete annotations to obsolete method's new idnum - } -- // With tracing we try not to "yack" too much. The position of -- // this trace assumes there are fewer obsolete methods than -- // EMCP methods. ++ ++obsolete_count; + // With tracing we try not to "yack" too much. The position of + // this trace assumes there are fewer obsolete methods than + // EMCP methods. - RC_TRACE(0x00000100, ("mark %s(%s) as obsolete", -- old_method->name()->as_C_string(), ++ TRACE_RC3("mark deleted %s(%s) as obsolete", + old_method->name()->as_C_string(), - old_method->signature()->as_C_string())); -- } ++ old_method->signature()->as_C_string()); + } - old_method->set_is_old(); -- } ++ //assert((*emcp_method_count_p + obsolete_count) == _old_methods->length(), "sanity check"); ++ TRACE_RC3("EMCP_cnt=%d, obsolete_cnt=%d !", *emcp_method_count_p, obsolete_count); ++} ++ ++// Increment the classRedefinedCount field in the specific instanceKlass ++// and in all direct and indirect subclasses. ++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); ++ int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1; ++ java_lang_Class::set_classRedefinedCount(class_mirror, new_count); ++ TRACE_RC3("updated count for class=%s to %d", ik->external_name(), new_count); ++} ++ ++#ifndef PRODUCT ++void VM_RedefineClasses::check_class(klassOop k_oop, TRAPS) { ++ Klass *k = k_oop->klass_part(); ++ if (k->oop_is_instance()) { ++ HandleMark hm(THREAD); ++ instanceKlass *ik = (instanceKlass *) k; ++ assert(ik->is_newest_version(), "must be latest version in system dictionary"); ++ ++ if (ik->vtable_length() > 0) { ++ ResourceMark rm(THREAD); ++ if (!ik->vtable()->check_no_old_or_obsolete_entries()) { ++ TRACE_RC1("size of class: %d\n", k_oop->size()); ++ TRACE_RC1("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); ++ assert(false, "OLD method found"); ++ } ++ ++ ik->vtable()->verify(tty, true); ++ } + } - for (int i = 0; i < _deleted_methods_length; ++i) { - methodOop old_method = _deleted_methods[i]; -- ++} + - assert(old_method->vtable_index() < 0, - "cannot delete methods with vtable entries");; -- ++#endif + - // Mark all deleted methods as old and obsolete - old_method->set_is_old(); - old_method->set_is_obsolete(); @@ -7748,58 +8082,128 @@ index eb52388..432e15a 100644 - RC_TRACE(0x00000100, ("mark deleted %s(%s) as obsolete", - old_method->name()->as_C_string(), - old_method->signature()->as_C_string())); -- } ++static bool match_right(void* value, Pair<klassOop, klassOop> elem) { ++ return elem.right() == value; ++} ++ ++jvmtiError VM_RedefineClasses::do_topological_class_sorting( const jvmtiClassDefinition *class_defs, int class_count, TRAPS) ++{ ++ GrowableArray< Pair<klassOop, klassOop> > links; ++ ++ for (int i=0; i<class_count; i++) { ++ ++ oop mirror = JNIHandles::resolve_non_null(class_defs[i].klass); ++ instanceKlassHandle the_class(THREAD, java_lang_Class::as_klassOop(mirror)); ++ Handle the_class_loader(THREAD, the_class->class_loader()); ++ Handle protection_domain(THREAD, the_class->protection_domain()); ++ ++ ClassFileStream st((u1*) class_defs[i].class_bytes, ++ class_defs[i].class_byte_count, (char *)"__VM_RedefineClasses__"); ++ ClassFileParser cfp(&st); ++ ++ GrowableArray<Symbol*> symbolArr; ++ TempNewSymbol parsed_name; ++ TRACE_RC2("Before find super symbols of class %s", the_class->name()->as_C_string()); ++ cfp.parseClassFile(the_class->name(), the_class_loader, protection_domain, the_class, KlassHandle(), NULL, &symbolArr, parsed_name, false, THREAD); ++ ++ for (int j=0; j<symbolArr.length(); j++) { ++ Symbol* sym = symbolArr.at(j); ++ TRACE_RC3("Before adding link to super class %s", sym->as_C_string()); ++ klassOop super_klass = SystemDictionary::resolve_or_null(sym, the_class_loader, protection_domain, THREAD); ++ if (super_klass != NULL) { ++ instanceKlassHandle the_super_class(THREAD, super_klass); ++ if (_affected_klasses->contains(the_super_class)) { ++ TRACE_RC2("Found class to link"); ++ links.append(Pair<klassOop, klassOop>(super_klass, the_class())); ++ } ++ } ++ } ++ ++ assert(the_class->check_redefinition_flag(Klass::MarkedAsAffected), ""); ++ the_class->clear_redefinition_flag(Klass::MarkedAsAffected); + } - assert((*emcp_method_count_p + obsolete_count) == _old_methods->length(), - "sanity check"); - RC_TRACE(0x00000100, ("EMCP_cnt=%d, obsolete_cnt=%d", *emcp_method_count_p, - obsolete_count)); -+bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) { -+ // classes for primitives cannot be redefined -+ if (java_lang_Class::is_primitive(klass_mirror)) { -+ return false; ++ ++ ++ TRACE_RC1("Identified links between classes! "); ++ ++ for (int i=0; i < _affected_klasses->length(); i++) { ++ instanceKlassHandle klass = _affected_klasses->at(i); ++ ++ if (klass->check_redefinition_flag(Klass::MarkedAsAffected)) { ++ klass->clear_redefinition_flag(Klass::MarkedAsAffected); ++ klassOop superKlass = klass->super(); ++ if (_affected_klasses->contains(superKlass)) { ++ links.append(Pair<klassOop, klassOop>(superKlass, klass())); ++ } ++ ++ objArrayOop superInterfaces = klass->local_interfaces(); ++ for (int j=0; j<superInterfaces->length(); j++) { ++ klassOop interfaceKlass = (klassOop)superInterfaces->obj_at(j); ++ if (_affected_klasses->contains(interfaceKlass)) { ++ links.append(Pair<klassOop, klassOop>(interfaceKlass, klass())); ++ } ++ } ++ } + } -+ klassOop the_class_oop = java_lang_Class::as_klassOop(klass_mirror); -+ // classes for arrays cannot be redefined -+ if (the_class_oop == NULL || !Klass::cast(the_class_oop)->oop_is_instance()) { -+ return false; ++ ++ IF_TRACE_RC2 { ++ TRACE_RC2("Identified links: "); ++ for (int i=0; i<links.length(); i++) { ++ TRACE_RC2("%s to %s", links.at(i).left()->klass_part()->name()->as_C_string(), ++ links.at(i).right()->klass_part()->name()->as_C_string()); ++ } + } -+ return true; ++ ++ for (int i = 0; i < _affected_klasses->length(); i++) { ++ int j; ++ for (j = i; j < _affected_klasses->length(); j++) { ++ // Search for node with no incoming edges ++ klassOop oop = _affected_klasses->at(j)(); ++ int k = links.find(oop, match_right); ++ if (k == -1) break; ++ } ++ if (j == _affected_klasses->length()) { ++ return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; ++ } ++ ++ // Remove all links from this node ++ klassOop oop = _affected_klasses->at(j)(); ++ int k = 0; ++ while (k < links.length()) { ++ if (links.adr_at(k)->left() == oop) { ++ links.delete_at(k); ++ } else { ++ k++; ++ } ++ } ++ ++ // Swap node ++ instanceKlassHandle tmp = _affected_klasses->at(j); ++ _affected_klasses->at_put(j, _affected_klasses->at(i)); ++ _affected_klasses->at_put(i, tmp); ++ } ++ ++ return JVMTI_ERROR_NONE; } --// This internal class transfers the native function registration from old methods --// to new methods. It is designed to handle both the simple case of unchanged --// native methods and the complex cases of native method prefixes being added and/or --// removed. --// It expects only to be used during the VM_RedefineClasses op (a safepoint). --// --// This class is used after the new methods have been installed in "the_class". --// --// So, for example, the following must be handled. Where 'm' is a method and --// a number followed by an underscore is a prefix. --// --// Old Name New Name --// Simple transfer to new method m -> m --// Add prefix m -> 1_m --// Remove prefix 1_m -> m --// Simultaneous add of prefixes m -> 3_2_1_m --// Simultaneous removal of prefixes 3_2_1_m -> m --// Simultaneous add and remove 1_m -> 2_m --// Same, caused by prefix removal only 3_2_1_m -> 3_2_m --// --class TransferNativeFunctionRegistration { + // This internal class transfers the native function registration from old methods +@@ -2832,7 +2253,7 @@ + // Same, caused by prefix removal only 3_2_1_m -> 3_2_m + // + class TransferNativeFunctionRegistration { - private: -- instanceKlassHandle the_class; -- int prefix_count; -- char** prefixes; -- -- // Recursively search the binary tree of possibly prefixed method names. -- // Iteration could be used if all agents were well behaved. Full tree walk is -- // more resilent to agents not cleaning up intermediate methods. -- // Branch at each depth in the binary tree is: -- // (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, ++private: + instanceKlassHandle the_class; + int prefix_count; + char** prefixes; +@@ -2845,42 +2266,42 @@ + // (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, - Symbol* signature) { - TempNewSymbol name_symbol = SymbolTable::probe(name_str, (int)name_len); - if (name_symbol != NULL) { @@ -7815,8 +8219,23 @@ index eb52388..432e15a 100644 - method = search_prefix_name_space(depth+1, name_str, name_len, signature); - if (method != NULL) { - return method; // found -- } -- ++ Symbol* signature) { ++ Symbol* name_symbol = SymbolTable::probe(name_str, (int)name_len); ++ if (name_symbol != NULL) { ++ methodOop method = Klass::cast(the_class()->klass_part()->new_version())->lookup_method(name_symbol, signature); ++ if (method != NULL) { ++ // Even if prefixed, intermediate methods must exist. ++ if (method->is_native()) { ++ // Wahoo, we found a (possibly prefixed) version of the method, return it. ++ return method; + } ++ if (depth < prefix_count) { ++ // Try applying further prefixes (other than this one). ++ method = search_prefix_name_space(depth+1, name_str, name_len, signature); ++ if (method != NULL) { ++ return method; // found ++ } + - // Try adding this prefix to the method name and see if it matches - // another method name. - char* prefix = prefixes[depth]; @@ -7831,288 +8250,189 @@ index eb52388..432e15a 100644 - // If found along this branch, it was prefixed, mark as such - method->set_is_prefixed_native(); - return method; // found -- } -- } -- } ++ // Try adding this prefix to the method name and see if it matches ++ // another method name. ++ char* prefix = prefixes[depth]; ++ size_t prefix_len = strlen(prefix); ++ size_t trial_len = name_len + prefix_len; ++ char* trial_name_str = NEW_RESOURCE_ARRAY(char, trial_len + 1); ++ strcpy(trial_name_str, prefix); ++ strcat(trial_name_str, name_str); ++ method = search_prefix_name_space(depth+1, trial_name_str, trial_len, ++ signature); ++ if (method != NULL) { ++ // If found along this branch, it was prefixed, mark as such ++ method->set_is_prefixed_native(); ++ return method; // found ++ } + } + } + } - } - return NULL; // This whole branch bore nothing -+#ifdef ASSERT -+ -+void VM_RedefineClasses::verify_classes(klassOop k_oop_latest, oop initiating_loader, TRAPS) { -+ klassOop k_oop = k_oop_latest; -+ while (k_oop != NULL) { -+ -+ instanceKlassHandle k_handle(THREAD, k_oop); -+ Verifier::verify(k_handle, Verifier::ThrowException, true, true, THREAD); -+ k_oop = k_oop->klass_part()->old_version(); ++ return NULL; // This whole branch bore nothing } -+} -- // Return the method name with old prefixes stripped away. -- char* method_name_without_prefixes(methodOop method) { -- Symbol* name = method->name(); -- char* name_str = name->as_utf8(); -+#endif - -- // Old prefixing may be defunct, strip prefixes, if any. -- for (int i = prefix_count-1; i >= 0; i--) { -- char* prefix = prefixes[i]; -- size_t prefix_len = strlen(prefix); -- if (strncmp(prefix, name_str, prefix_len) == 0) { -- name_str += prefix_len; -+// Rewrite faster byte-codes back to their slower equivalent. Undoes rewriting happening in templateTable_xxx.cpp -+// The reason is that once we zero cpool caches, we need to re-resolve all entries again. Faster bytecodes do not -+// do that, they assume that cache entry is resolved already. -+void VM_RedefineClasses::unpatch_bytecode(methodOop method) { -+ RawBytecodeStream bcs(method); -+ Bytecodes::Code code; -+ Bytecodes::Code java_code; -+ while (!bcs.is_last_bytecode()) { -+ code = bcs.raw_next(); -+ address bcp = bcs.bcp(); -+ -+ if (code == Bytecodes::_breakpoint) { -+ int bci = method->bci_from(bcp); -+ code = method->orig_bytecode_at(bci); -+ java_code = Bytecodes::java_code(code); -+ if (code != java_code && -+ (java_code == Bytecodes::_getfield || -+ java_code == Bytecodes::_putfield || -+ java_code == Bytecodes::_aload_0)) { -+ // Let breakpoint table handling unpatch bytecode -+ method->set_orig_bytecode_at(bci, java_code); -+ } -+ } else { -+ java_code = Bytecodes::java_code(code); -+ if (code != java_code && -+ (java_code == Bytecodes::_getfield || -+ java_code == Bytecodes::_putfield || -+ java_code == Bytecodes::_aload_0)) { -+ *bcp = java_code; - } - } -- return name_str; -- } - -- // 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) { -- ResourceMark rm; -- char* name_str = method_name_without_prefixes(method); -- return search_prefix_name_space(0, name_str, strlen(name_str), + // Return the method name with old prefixes stripped away. +@@ -2905,10 +2326,10 @@ + ResourceMark rm; + char* name_str = method_name_without_prefixes(method); + return search_prefix_name_space(0, name_str, strlen(name_str), - method->signature()); -+ // Additionally, we need to unpatch bytecode at bcp+1 for fast_xaccess (which would be fast field access) -+ if (code == Bytecodes::_fast_iaccess_0 || code == Bytecodes::_fast_aaccess_0 || code == Bytecodes::_fast_faccess_0) { -+ Bytecodes::Code code2 = Bytecodes::code_or_bp_at(bcp + 1); -+ assert(code2 == Bytecodes::_fast_igetfield || -+ code2 == Bytecodes::_fast_agetfield || -+ code2 == Bytecodes::_fast_fgetfield, ""); -+ *(bcp + 1) = Bytecodes::java_code(code2); -+ } ++ method->signature()); } -+} - public: -+// Unevolving classes may point to old methods directly -+// from their constant pool caches, itables, and/or vtables. We -+// use the SystemDictionary::classes_do() facility and this helper -+// to fix up these pointers. Additional field offsets and vtable indices -+// in the constant pool cache entries are fixed. -+// -+// Note: We currently don't support updating the vtable in -+// arrayKlassOops. See Open Issues in jvmtiRedefineClasses.hpp. -+void VM_RedefineClasses::adjust_cpool_cache(klassOop k_oop_latest, oop initiating_loader, TRAPS) { -+ klassOop k_oop = k_oop_latest; -+ while (k_oop != NULL) { -+ Klass *k = k_oop->klass_part(); -+ if (k->oop_is_instance()) { -+ HandleMark hm(THREAD); -+ instanceKlass *ik = (instanceKlass *) k; - -- // Construct a native method transfer processor for this class. -- TransferNativeFunctionRegistration(instanceKlassHandle _the_class) { -- assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); -+ constantPoolHandle other_cp; -+ constantPoolCacheOop cp_cache; ++public: -- the_class = _the_class; -- prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count); -- } -+ other_cp = constantPoolHandle(ik->constants()); + // Construct a native method transfer processor for this class. + TransferNativeFunctionRegistration(instanceKlassHandle _the_class) { +@@ -2919,9 +2340,9 @@ + } -- // Attempt to transfer any of the old or deleted methods that are native + // Attempt to transfer any of the old or deleted methods that are native - void transfer_registrations(methodOop* old_methods, int methods_length) { -- for (int j = 0; j < methods_length; j++) { ++ void transfer_registrations(instanceKlassHandle old_klass, int* old_methods, int methods_length) { + for (int j = 0; j < methods_length; j++) { - methodOop old_method = old_methods[j]; -+ for (int i=0; i<other_cp->length(); i++) { -+ if (other_cp->tag_at(i).is_klass()) { -+ klassOop klass = other_cp->klass_at(i, THREAD); -+ if (klass->klass_part()->new_version() != NULL) { ++ methodOop old_method = (methodOop)old_klass->methods()->obj_at(old_methods[j]); -- if (old_method->is_native() && old_method->has_native_function()) { -- methodOop 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(), + if (old_method->is_native() && old_method->has_native_function()) { + methodOop new_method = strip_and_search_for_new_native(old_method); +@@ -2930,7 +2351,9 @@ + // 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); -+ // (tw) TODO: check why/if this is necessary -+ other_cp->klass_at_put(i, klass->klass_part()->new_version()); -+ } -+ klass = other_cp->klass_at(i, THREAD); -+ assert(klass->klass_part()->new_version() == NULL, "Must be new klass!"); ++ !methodOopDesc::native_bind_event_is_interesting); ++ ++ TRACE_RC3("Transfering native function for method %s", old_method->name()->as_C_string()); } } -+ -+ cp_cache = other_cp->cache(); -+ -+ if (cp_cache != NULL) { -+ cp_cache->adjust_entries(); -+ } -+ -+ // If bytecode rewriting is enabled, we also need to unpatch bytecode to force resolution of zeroed entries -+ if (RewriteBytecodes) { -+ ik->methods_do(unpatch_bytecode); -+ } } -+ k_oop = k_oop->klass_part()->old_version(); - } --}; -+} +@@ -2938,534 +2361,8 @@ + }; --// Don't lose the association between a native method and its JNI function. + // Don't lose the association between a native method and its JNI function. -void VM_RedefineClasses::transfer_old_native_function_registrations(instanceKlassHandle the_class) { - TransferNativeFunctionRegistration transfer(the_class); - transfer.transfer_registrations(_deleted_methods, _deleted_methods_length); - transfer.transfer_registrations(_matching_old_methods, _matching_methods_length); -+void VM_RedefineClasses::update_jmethod_ids() { -+ for (int j = 0; j < _matching_methods_length; ++j) { -+ methodOop old_method = (methodOop)_old_methods->obj_at(_matching_old_methods[j]); -+ TRACE_RC3("matching method %s", old_method->name_and_sig_as_C_string()); -+ -+ jmethodID jmid = old_method->find_jmethod_id_or_null(); -+ if (old_method->new_version() != NULL && jmid == NULL) { -+ // (tw) Have to create jmethodID in this case -+ jmid = old_method->jmethod_id(); -+ } -+ -+ if (jmid != NULL) { -+ // There is a jmethodID, change it to point to the new method -+ methodHandle new_method_h((methodOop)_new_methods->obj_at(_matching_new_methods[j])); -+ if (old_method->new_version() == NULL) { -+ methodHandle old_method_h((methodOop)_old_methods->obj_at(_matching_old_methods[j])); -+ jmethodID new_jmethod_id = JNIHandles::make_jmethod_id(old_method_h); -+ bool result = instanceKlass::cast(old_method_h->method_holder())->update_jmethod_id(old_method_h(), new_jmethod_id); -+ //TRACE_RC3("Changed jmethodID for old method assigned to %d / result=%d", new_jmethod_id, result); -+ //TRACE_RC3("jmethodID new method: %d jmethodID old method: %d", new_method_h->jmethod_id(), old_method->jmethod_id()); -+ } else { -+ jmethodID mid = new_method_h->jmethod_id(); -+ bool result = instanceKlass::cast(new_method_h->method_holder())->update_jmethod_id(new_method_h(), jmid); -+ //TRACE_RC3("Changed jmethodID for new method assigned to %d / result=%d", jmid, result); -+ } -+ JNIHandles::change_method_associated_with_jmethod_id(jmid, new_method_h); -+ //TRACE_RC3("changing method associated with jmethod id %d to %s", (int)jmid, new_method_h->name()->as_C_string()); -+ assert(JNIHandles::resolve_jmethod_id(jmid) == (methodOop)_new_methods->obj_at(_matching_new_methods[j]), "should be replaced"); -+ jmethodID mid = ((methodOop)_new_methods->obj_at(_matching_new_methods[j]))->jmethod_id(); -+ assert(JNIHandles::resolve_non_null((jobject)mid) == new_method_h(), "must match!"); -+ -+ //TRACE_RC3("jmethodID new method: %d jmethodID old method: %d", new_method_h->jmethod_id(), old_method->jmethod_id()); -+ } -+ } ++void VM_RedefineClasses::transfer_old_native_function_registrations(instanceKlassHandle old_klass) { ++ TransferNativeFunctionRegistration transfer(old_klass); ++ transfer.transfer_registrations(old_klass, _deleted_methods, _deleted_methods_length); ++ transfer.transfer_registrations(old_klass, _matching_old_methods, _matching_methods_length); } - -+ - // Deoptimize all compiled code that depends on this class. - // - // If the can_redefine_classes capability is obtained in the onload -@@ -2964,7 +1835,10 @@ void VM_RedefineClasses::flush_dependent_code(instanceKlassHandle k_h, TRAPS) { - - // All dependencies have been recorded from startup or this is a second or - // subsequent use of RedefineClasses +- +-// Deoptimize all compiled code that depends on this class. +-// +-// If the can_redefine_classes capability is obtained in the onload +-// phase then the compiler has recorded all dependencies from startup. +-// In that case we need only deoptimize and throw away all compiled code +-// that depends on the class. +-// +-// If can_redefine_classes is obtained sometime after the onload +-// phase then the dependency information may be incomplete. In that case +-// the first call to RedefineClasses causes all compiled code to be +-// thrown away. As can_redefine_classes has been obtained then +-// all future compilations will record dependencies so second and +-// subsequent calls to RedefineClasses need only throw away code +-// that depends on the class. +-// +-void VM_RedefineClasses::flush_dependent_code(instanceKlassHandle k_h, TRAPS) { +- assert_locked_or_safepoint(Compile_lock); +- +- // All dependencies have been recorded from startup or this is a second or +- // subsequent use of RedefineClasses - if (JvmtiExport::all_dependencies_are_recorded()) { -+ -+ // For now deopt all -+ // (tw) TODO: Improve the dependency system such that we can safely deopt only a subset of the methods -+ if (0 && JvmtiExport::all_dependencies_are_recorded()) { - Universe::flush_evol_dependents_on(k_h); - } else { - CodeCache::mark_all_nmethods_for_deoptimization(); -@@ -2987,10 +1861,10 @@ void VM_RedefineClasses::compute_added_deleted_matching_methods() { - methodOop old_method; - methodOop new_method; - +- Universe::flush_evol_dependents_on(k_h); +- } else { +- CodeCache::mark_all_nmethods_for_deoptimization(); +- +- ResourceMark rm(THREAD); +- DeoptimizationMarker dm; +- +- // Deoptimize all activations depending on marked nmethods +- Deoptimization::deoptimize_dependents(); +- +- // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies) +- CodeCache::make_marked_nmethods_not_entrant(); +- +- // From now on we know that the dependency information is complete +- JvmtiExport::set_all_dependencies_are_recorded(true); +- } +-} +- +-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()); -+ _matching_old_methods = NEW_RESOURCE_ARRAY(int, _old_methods->length()); -+ _matching_new_methods = NEW_RESOURCE_ARRAY(int, _old_methods->length()); -+ _added_methods = NEW_RESOURCE_ARRAY(int, _new_methods->length()); -+ _deleted_methods = NEW_RESOURCE_ARRAY(int, _old_methods->length()); - - _matching_methods_length = 0; - _deleted_methods_length = 0; -@@ -3005,36 +1879,36 @@ void VM_RedefineClasses::compute_added_deleted_matching_methods() { - } - // New method at the end - new_method = (methodOop) _new_methods->obj_at(nj); +- +- _matching_methods_length = 0; +- _deleted_methods_length = 0; +- _added_methods_length = 0; +- +- int nj = 0; +- int oj = 0; +- while (true) { +- if (oj >= _old_methods->length()) { +- if (nj >= _new_methods->length()) { +- break; // we've looked at everything, done +- } +- // New method at the end +- new_method = (methodOop) _new_methods->obj_at(nj); - _added_methods[_added_methods_length++] = new_method; -+ _added_methods[_added_methods_length++] = nj; - ++nj; - } else if (nj >= _new_methods->length()) { - // Old method, at the end, is deleted - old_method = (methodOop) _old_methods->obj_at(oj); +- ++nj; +- } else if (nj >= _new_methods->length()) { +- // Old method, at the end, is deleted +- old_method = (methodOop) _old_methods->obj_at(oj); - _deleted_methods[_deleted_methods_length++] = old_method; -+ _deleted_methods[_deleted_methods_length++] = oj; - ++oj; - } else { - old_method = (methodOop) _old_methods->obj_at(oj); - new_method = (methodOop) _new_methods->obj_at(nj); - if (old_method->name() == new_method->name()) { - if (old_method->signature() == new_method->signature()) { +- ++oj; +- } else { +- old_method = (methodOop) _old_methods->obj_at(oj); +- new_method = (methodOop) _new_methods->obj_at(nj); +- if (old_method->name() == new_method->name()) { +- if (old_method->signature() == new_method->signature()) { - _matching_old_methods[_matching_methods_length ] = old_method; - _matching_new_methods[_matching_methods_length++] = new_method; -+ _matching_old_methods[_matching_methods_length ] = oj;//old_method; -+ _matching_new_methods[_matching_methods_length++] = nj;//new_method; - ++nj; - ++oj; - } else { - // added overloaded have already been moved to the end, - // so this is a deleted overloaded method +- ++nj; +- ++oj; +- } else { +- // added overloaded have already been moved to the end, +- // so this is a deleted overloaded method - _deleted_methods[_deleted_methods_length++] = old_method; -+ _deleted_methods[_deleted_methods_length++] = oj;//old_method; - ++oj; - } - } else { // names don't match - if (old_method->name()->fast_compare(new_method->name()) > 0) { - // new method +- ++oj; +- } +- } else { // names don't match +- if (old_method->name()->fast_compare(new_method->name()) > 0) { +- // new method - _added_methods[_added_methods_length++] = new_method; -+ _added_methods[_added_methods_length++] = nj;//new_method; - ++nj; - } else { - // deleted method +- ++nj; +- } else { +- // deleted method - _deleted_methods[_deleted_methods_length++] = old_method; -+ _deleted_methods[_deleted_methods_length++] = oj;//old_method; - ++oj; - } - } -@@ -3042,6 +1916,7 @@ void VM_RedefineClasses::compute_added_deleted_matching_methods() { - } - assert(_matching_methods_length + _deleted_methods_length == _old_methods->length(), "sanity"); - assert(_matching_methods_length + _added_methods_length == _new_methods->length(), "sanity"); -+ TRACE_RC3("Matching methods = %d / deleted methods = %d / added methods = %d", _matching_methods_length, _deleted_methods_length, _added_methods_length); - } - - -@@ -3049,287 +1924,176 @@ void VM_RedefineClasses::compute_added_deleted_matching_methods() { - // Install the redefinition of a class: - // - house keeping (flushing breakpoints and caches, deoptimizing - // dependent compiled code) +- ++oj; +- } +- } +- } +- } +- assert(_matching_methods_length + _deleted_methods_length == _old_methods->length(), "sanity"); +- assert(_matching_methods_length + _added_methods_length == _new_methods->length(), "sanity"); +-} +- +- +- +-// Install the redefinition of a class: +-// - house keeping (flushing breakpoints and caches, deoptimizing +-// dependent compiled code) -// - replacing parts in the_class with parts from scratch_class -// - adding a weak reference to track the obsolete but interesting -// parts of the_class - // - adjusting constant pool caches and vtables in other classes +-// - adjusting constant pool caches and vtables in other classes -// that refer to methods in the_class. These adjustments use the -// SystemDictionary::classes_do() facility which only allows -// a helper method to be specified. The interesting parameters @@ -8120,46 +8440,33 @@ index eb52388..432e15a 100644 -// static global fields in the VM operation. -void VM_RedefineClasses::redefine_single_class(jclass the_jclass, - instanceKlassHandle scratch_class, TRAPS) { -+void VM_RedefineClasses::redefine_single_class(instanceKlassHandle the_new_class, TRAPS) { -+ -+ ResourceMark rm(THREAD); - +- - RC_TIMER_START(_timer_rsc_phase1); -+ assert(the_new_class->old_version() != NULL, "Must not be null"); -+ assert(the_new_class->old_version()->klass_part()->new_version() == the_new_class(), "Must equal"); - +- - oop the_class_mirror = JNIHandles::resolve_non_null(the_jclass); - klassOop the_class_oop = java_lang_Class::as_klassOop(the_class_mirror); - instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop); -+ instanceKlassHandle the_old_class = instanceKlassHandle(THREAD, the_new_class->old_version()); - -+#ifndef JVMTI_KERNEL - // Remove all breakpoints in methods of this class - JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints(); +- +- // 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_old_class()); -+#endif // !JVMTI_KERNEL - +- - if (the_class_oop == Universe::reflect_invoke_cache()->klass()) { -+ if (the_old_class() == Universe::reflect_invoke_cache()->klass()) { - // We are redefining java.lang.reflect.Method. Method.invoke() is - // cached and users of the cache care about each active version of - // the method so we have to track this previous version. - // Do this before methods get switched - Universe::reflect_invoke_cache()->add_previous_version( +- // We are redefining java.lang.reflect.Method. Method.invoke() is +- // cached and users of the cache care about each active version of +- // the method so we have to track this previous version. +- // Do this before methods get switched +- Universe::reflect_invoke_cache()->add_previous_version( - the_class->method_with_idnum(Universe::reflect_invoke_cache()->method_idnum())); -+ the_old_class->method_with_idnum(Universe::reflect_invoke_cache()->method_idnum())); - } - +- } +- - // 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; -+ _old_methods = the_old_class->methods(); -+ _new_methods = the_new_class->methods(); - compute_added_deleted_matching_methods(); +- compute_added_deleted_matching_methods(); - update_jmethod_ids(); - - // Attach new constant pool to the original klass. The original @@ -8255,17 +8562,12 @@ index eb52388..432e15a 100644 - - old_constants->set_pool_holder(scratch_class()); -#endif - - // track which methods are EMCP for add_previous_version() call below +- +- // track which methods are EMCP for add_previous_version() call below - BitMap emcp_methods(_old_methods->length()); -+ -+ // (tw) TODO: Check if we need the concept of EMCP? -+ BitMap emcp_methods(_old_methods->length()); - int emcp_method_count = 0; - emcp_methods.clear(); // clears 0..(length() - 1) -+ -+ // We need to mark methods as old!! - check_methods_and_mark_as_obsolete(&emcp_methods, &emcp_method_count); +- int emcp_method_count = 0; +- emcp_methods.clear(); // clears 0..(length() - 1) +- check_methods_and_mark_as_obsolete(&emcp_methods, &emcp_method_count); - transfer_old_native_function_registrations(the_class); - - // The class file bytes from before any retransformable agents mucked @@ -8286,15 +8588,12 @@ index eb52388..432e15a 100644 - scratch_class->get_cached_class_file_len(), "cache lens must match"); - } -#endif -+ update_jmethod_ids(); - +- - // Replace inner_classes - typeArrayOop old_inner_classes = the_class->inner_classes(); - the_class->set_inner_classes(scratch_class->inner_classes()); - scratch_class->set_inner_classes(old_inner_classes); -+ // TODO: -+ transfer_old_native_function_registrations(the_old_class); - +- - // Initialize the vtable and interface table after - // methods have been rewritten - { @@ -8386,156 +8685,39 @@ index eb52388..432e15a 100644 - - RC_TIMER_STOP(_timer_rsc_phase1); - RC_TIMER_START(_timer_rsc_phase2); - +- - // Adjust constantpool caches and vtables for all classes - // that reference methods of the evolved class. - SystemDictionary::classes_do(adjust_cpool_cache_and_vtable, THREAD); - +- - 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. - the_class->oop_map_cache()->flush_obsolete_entries(); -+#ifdef ASSERT -+ -+// klassOop systemLookup1 = SystemDictionary::resolve_or_null(the_old_class->name(), the_old_class->class_loader(), the_old_class->protection_domain(), THREAD); -+// assert(systemLookup1 == the_new_class(), "New class must be in system dictionary!"); -+ -+ //JNIHandles::verify(); -+ -+// klassOop systemLookup = SystemDictionary::resolve_or_null(the_old_class->name(), the_old_class->class_loader(), the_old_class->protection_domain(), THREAD); -+ -+// assert(systemLookup == the_new_class(), "New class must be in system dictionary!"); -+ assert(the_new_class->old_version() != NULL, "Must not be null"); -+ assert(the_new_class->old_version()->klass_part()->new_version() == the_new_class(), "Must equal"); -+ -+ for (int i=0; i<the_new_class->methods()->length(); i++) { -+ assert(((methodOop)the_new_class->methods()->obj_at(i))->method_holder() == the_new_class(), "method holder must match!"); - } - -+ _old_methods->verify(); -+ _new_methods->verify(); -+ -+ the_new_class->vtable()->verify(tty); -+ the_old_class->vtable()->verify(tty); -+ -+#endif -+ - // increment the classRedefinedCount field in the_class and in any - // direct and indirect subclasses of the_class +- } +- +- // 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_old_class()->klass_part(), THREAD); -+ -+} -+ -+ -+void VM_RedefineClasses::check_methods_and_mark_as_obsolete(BitMap *emcp_methods, int * emcp_method_count_p) { -+ TRACE_RC3("Checking matching methods for EMCP"); -+ *emcp_method_count_p = 0; -+ int obsolete_count = 0; -+ int old_index = 0; -+ for (int j = 0; j < _matching_methods_length; ++j, ++old_index) { -+ methodOop old_method = (methodOop)_old_methods->obj_at(_matching_old_methods[j]); -+ methodOop new_method = (methodOop)_new_methods->obj_at(_matching_new_methods[j]); -+ methodOop 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) { -+ ++old_index; -+ } - +- - // RC_TRACE macro has an embedded ResourceMark - RC_TRACE_WITH_THREAD(0x00000001, THREAD, - ("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)); -+ if (MethodComparator::methods_EMCP(old_method, new_method)) { -+ // The EMCP definition from JSR-163 requires the bytecodes to be -+ // the same with the exception of constant pool indices which may -+ // differ. However, the constants referred to by those indices -+ // must be the same. -+ // -+ // We use methods_EMCP() for comparison since constant pool -+ // merging can remove duplicate constant pool entries that were -+ // present in the old method and removed from the rewritten new -+ // method. A faster binary comparison function would consider the -+ // old and new methods to be different when they are actually -+ // EMCP. -+ -+ // track which methods are EMCP for add_previous_version() call -+ emcp_methods->set_bit(old_index); -+ (*emcp_method_count_p)++; -+ -+ // An EMCP method is _not_ obsolete. An obsolete method has a -+ // different jmethodID than the current method. An EMCP method -+ // has the same jmethodID as the current method. Having the -+ // same jmethodID for all EMCP versions of a method allows for -+ // a consistent view of the EMCP methods regardless of which -+ // EMCP method you happen to have in hand. For example, a -+ // breakpoint set in one EMCP method will work for all EMCP -+ // versions of the method including the current one. -+ -+ old_method->set_new_version(new_method); -+ new_method->set_old_version(old_method); -+ -+ TRACE_RC3("Found EMCP method %s", old_method->name_and_sig_as_C_string()); -+ -+ // Transfer breakpoints -+ instanceKlass *ik = instanceKlass::cast(old_method->method_holder()); -+ for (BreakpointInfo* bp = ik->breakpoints(); bp != NULL; bp = bp->next()) { -+ TRACE_RC2("Checking breakpoint"); -+ TRACE_RC2("%d / %d", bp->match(old_method), bp->match(new_method)); -+ if (bp->match(old_method)) { -+ assert(bp->match(new_method), "if old method is method, then new method must match too"); -+ TRACE_RC2("Found a breakpoint in an old EMCP method"); -+ new_method->set_breakpoint(bp->bci()); -+ } -+ } -+ } else { -+ // mark obsolete methods as such -+ old_method->set_is_obsolete(); -+ obsolete_count++; -+ -+ // With tracing we try not to "yack" too much. The position of -+ // this trace assumes there are fewer obsolete methods than -+ // EMCP methods. -+ TRACE_RC3("mark %s(%s) as obsolete", -+ old_method->name()->as_C_string(), -+ old_method->signature()->as_C_string()); -+ } -+ old_method->set_is_old(); -+ } -+ for (int i = 0; i < _deleted_methods_length; ++i) { -+ methodOop old_method = (methodOop)_old_methods->obj_at(_deleted_methods[i]); - +- - RC_TIMER_STOP(_timer_rsc_phase2); -} // end redefine_single_class() -+ //assert(old_method->vtable_index() < 0, -+ // "cannot delete methods with vtable entries");; - -+ // Mark all deleted methods as old and obsolete -+ old_method->set_is_old(); -+ old_method->set_is_obsolete(); -+ ++obsolete_count; -+ // With tracing we try not to "yack" too much. The position of -+ // this trace assumes there are fewer obsolete methods than -+ // EMCP methods. -+ TRACE_RC3("mark deleted %s(%s) as obsolete", -+ old_method->name()->as_C_string(), -+ old_method->signature()->as_C_string()); -+ } -+ //assert((*emcp_method_count_p + obsolete_count) == _old_methods->length(), "sanity check"); -+ TRACE_RC3("EMCP_cnt=%d, obsolete_cnt=%d !", *emcp_method_count_p, obsolete_count); -+} - - // Increment the classRedefinedCount field in the specific instanceKlass - // and in all direct and indirect subclasses. -@@ -3338,134 +2102,267 @@ void VM_RedefineClasses::increment_class_counter(instanceKlass *ik, TRAPS) { - klassOop class_oop = java_lang_Class::as_klassOop(class_mirror); - int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1; - java_lang_Class::set_classRedefinedCount(class_mirror, new_count); +- +- +-// Increment the classRedefinedCount field in the specific instanceKlass +-// and in all direct and indirect subclasses. +-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); +- int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1; +- java_lang_Class::set_classRedefinedCount(class_mirror, new_count); - - if (class_oop != _the_class_oop) { - // _the_class_oop count is printed at end of redefine_single_class() @@ -8552,36 +8734,17 @@ index eb52388..432e15a 100644 - increment_class_counter(subik, THREAD); - } - } -+ TRACE_RC3("updated count for class=%s to %d", ik->external_name(), new_count); - } - +-} +- -void VM_RedefineClasses::check_class(klassOop k_oop, - oop initiating_loader, TRAPS) { -+#ifndef PRODUCT -+void VM_RedefineClasses::check_class(klassOop k_oop, TRAPS) { - Klass *k = k_oop->klass_part(); - if (k->oop_is_instance()) { - HandleMark hm(THREAD); - instanceKlass *ik = (instanceKlass *) k; +- Klass *k = k_oop->klass_part(); +- if (k->oop_is_instance()) { +- HandleMark hm(THREAD); +- instanceKlass *ik = (instanceKlass *) k; - bool no_old_methods = true; // be optimistic - ResourceMark rm(THREAD); -+ assert(ik->is_newest_version(), "must be latest version in system dictionary"); -+ -+ if (ik->vtable_length() > 0) { -+ ResourceMark rm(THREAD); -+ if (!ik->vtable()->check_no_old_or_obsolete_entries()) { -+ TRACE_RC1("size of class: %d\n", k_oop->size()); -+ TRACE_RC1("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); -+ assert(false, "OLD method found"); -+ } -+ -+ ik->vtable()->verify(tty, true); -+ } -+ } -+} -+ -+#endif - +- - // a vtable should never contain old or obsolete methods - if (ik->vtable_length() > 0 && - !ik->vtable()->check_no_old_or_obsolete_entries()) { @@ -8591,41 +8754,7 @@ index eb52388..432e15a 100644 - " -- OLD or OBSOLETE method found -- class: %s", - ik->signature_name())); - ik->vtable()->dump_vtable(); -+static bool match_right(void* value, Pair<klassOop, klassOop> elem) { -+ return elem.right() == value; -+} -+ -+jvmtiError VM_RedefineClasses::do_topological_class_sorting( const jvmtiClassDefinition *class_defs, int class_count, TRAPS) -+{ -+ GrowableArray< Pair<klassOop, klassOop> > links; -+ -+ for (int i=0; i<class_count; i++) { -+ -+ oop mirror = JNIHandles::resolve_non_null(class_defs[i].klass); -+ instanceKlassHandle the_class(THREAD, java_lang_Class::as_klassOop(mirror)); -+ Handle the_class_loader(THREAD, the_class->class_loader()); -+ Handle protection_domain(THREAD, the_class->protection_domain()); -+ -+ ClassFileStream st((u1*) class_defs[i].class_bytes, -+ class_defs[i].class_byte_count, (char *)"__VM_RedefineClasses__"); -+ ClassFileParser cfp(&st); -+ -+ GrowableArray<Symbol*> symbolArr; -+ TempNewSymbol parsed_name; -+ TRACE_RC2("Before find super symbols of class %s", the_class->name()->as_C_string()); -+ cfp.parseClassFile(the_class->name(), the_class_loader, protection_domain, the_class, KlassHandle(), NULL, &symbolArr, parsed_name, false, THREAD); -+ -+ for (int j=0; j<symbolArr.length(); j++) { -+ Symbol* sym = symbolArr.at(j); -+ TRACE_RC3("Before adding link to super class %s", sym->as_C_string()); -+ klassOop super_klass = SystemDictionary::resolve_or_null(sym, the_class_loader, protection_domain, THREAD); -+ if (super_klass != NULL) { -+ instanceKlassHandle the_super_class(THREAD, super_klass); -+ if (_affected_klasses->contains(the_super_class)) { -+ TRACE_RC2("Found class to link"); -+ links.append(Pair<klassOop, klassOop>(super_klass, the_class())); -+ } - } +- } - no_old_methods = false; - } - @@ -8638,24 +8767,7 @@ index eb52388..432e15a 100644 - " -- OLD or OBSOLETE method found -- class: %s", - ik->signature_name())); - ik->itable()->dump_itable(); -+ } -+ -+ assert(the_class->check_redefinition_flag(Klass::MarkedAsAffected), ""); -+ the_class->clear_redefinition_flag(Klass::MarkedAsAffected); -+ } -+ -+ -+ TRACE_RC1("Identified links between classes! "); -+ -+ for (int i=0; i < _affected_klasses->length(); i++) { -+ instanceKlassHandle klass = _affected_klasses->at(i); -+ -+ if (klass->check_redefinition_flag(Klass::MarkedAsAffected)) { -+ klass->clear_redefinition_flag(Klass::MarkedAsAffected); -+ klassOop superKlass = klass->super(); -+ if (_affected_klasses->contains(superKlass)) { -+ links.append(Pair<klassOop, klassOop>(superKlass, klass())); - } +- } - no_old_methods = false; - } - @@ -8669,64 +8781,22 @@ index eb52388..432e15a 100644 - " -- OLD or OBSOLETE method found -- class: %s", - ik->signature_name())); - ik->constants()->cache()->dump_cache(); -+ -+ objArrayOop superInterfaces = klass->local_interfaces(); -+ for (int j=0; j<superInterfaces->length(); j++) { -+ klassOop interfaceKlass = (klassOop)superInterfaces->obj_at(j); -+ if (_affected_klasses->contains(interfaceKlass)) { -+ links.append(Pair<klassOop, klassOop>(interfaceKlass, klass())); -+ } - } +- } - no_old_methods = false; -+ } -+ } -+ -+ IF_TRACE_RC2 { -+ TRACE_RC2("Identified links: "); -+ for (int i=0; i<links.length(); i++) { -+ TRACE_RC2("%s to %s", links.at(i).left()->klass_part()->name()->as_C_string(), -+ links.at(i).right()->klass_part()->name()->as_C_string()); -+ } -+ } -+ -+ for (int i = 0; i < _affected_klasses->length(); i++) { -+ int j; -+ for (j = i; j < _affected_klasses->length(); j++) { -+ // Search for node with no incoming edges -+ klassOop oop = _affected_klasses->at(j)(); -+ int k = links.find(oop, match_right); -+ if (k == -1) break; -+ } -+ if (j == _affected_klasses->length()) { -+ return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; - } - +- } +- - if (!no_old_methods) { - if (RC_TRACE_ENABLED(0x00004000)) { - dump_methods(); -+ // Remove all links from this node -+ klassOop oop = _affected_klasses->at(j)(); -+ int k = 0; -+ while (k < links.length()) { -+ if (links.adr_at(k)->left() == oop) { -+ links.delete_at(k); - } else { +- } else { - tty->print_cr("INFO: use the '-XX:TraceRedefineClasses=16384' option " - "to see more info about the following guarantee() failure."); -+ k++; - } +- } - guarantee(false, "OLD and/or OBSOLETE method(s) found"); - } -+ -+ // Swap node -+ instanceKlassHandle tmp = _affected_klasses->at(j); -+ _affected_klasses->at_put(j, _affected_klasses->at(i)); -+ _affected_klasses->at_put(i, tmp); - } -+ -+ return JVMTI_ERROR_NONE; - } - +- } +- } +-} +- -void VM_RedefineClasses::dump_methods() { - int j; - RC_TRACE(0x00004000, ("_old_methods --")); @@ -8777,142 +8847,9 @@ index eb52388..432e15a 100644 - tty->print(" -- "); - m->print_name(tty); - tty->cr(); -+// This internal class transfers the native function registration from old methods -+// to new methods. It is designed to handle both the simple case of unchanged -+// native methods and the complex cases of native method prefixes being added and/or -+// removed. -+// It expects only to be used during the VM_RedefineClasses op (a safepoint). -+// -+// This class is used after the new methods have been installed in "the_class". -+// -+// So, for example, the following must be handled. Where 'm' is a method and -+// a number followed by an underscore is a prefix. -+// -+// Old Name New Name -+// Simple transfer to new method m -> m -+// Add prefix m -> 1_m -+// Remove prefix 1_m -> m -+// Simultaneous add of prefixes m -> 3_2_1_m -+// Simultaneous removal of prefixes 3_2_1_m -> m -+// Simultaneous add and remove 1_m -> 2_m -+// Same, caused by prefix removal only 3_2_1_m -> 3_2_m -+// -+class TransferNativeFunctionRegistration { -+private: -+ instanceKlassHandle the_class; -+ int prefix_count; -+ char** prefixes; -+ -+ // Recursively search the binary tree of possibly prefixed method names. -+ // Iteration could be used if all agents were well behaved. Full tree walk is -+ // more resilent to agents not cleaning up intermediate methods. -+ // Branch at each depth in the binary tree is: -+ // (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, -+ Symbol* signature) { -+ Symbol* name_symbol = SymbolTable::probe(name_str, (int)name_len); -+ if (name_symbol != NULL) { -+ methodOop method = Klass::cast(the_class()->klass_part()->new_version())->lookup_method(name_symbol, signature); -+ if (method != NULL) { -+ // Even if prefixed, intermediate methods must exist. -+ if (method->is_native()) { -+ // Wahoo, we found a (possibly prefixed) version of the method, return it. -+ return method; -+ } -+ if (depth < prefix_count) { -+ // Try applying further prefixes (other than this one). -+ method = search_prefix_name_space(depth+1, name_str, name_len, signature); -+ if (method != NULL) { -+ return method; // found -+ } -+ -+ // Try adding this prefix to the method name and see if it matches -+ // another method name. -+ char* prefix = prefixes[depth]; -+ size_t prefix_len = strlen(prefix); -+ size_t trial_len = name_len + prefix_len; -+ char* trial_name_str = NEW_RESOURCE_ARRAY(char, trial_len + 1); -+ strcpy(trial_name_str, prefix); -+ strcat(trial_name_str, name_str); -+ method = search_prefix_name_space(depth+1, trial_name_str, trial_len, -+ signature); -+ if (method != NULL) { -+ // If found along this branch, it was prefixed, mark as such -+ method->set_is_prefixed_native(); -+ return method; // found -+ } -+ } -+ } -+ } -+ return NULL; // This whole branch bore nothing -+ } -+ -+ // Return the method name with old prefixes stripped away. -+ char* method_name_without_prefixes(methodOop method) { -+ Symbol* name = method->name(); -+ char* name_str = name->as_utf8(); -+ -+ // Old prefixing may be defunct, strip prefixes, if any. -+ for (int i = prefix_count-1; i >= 0; i--) { -+ char* prefix = prefixes[i]; -+ size_t prefix_len = strlen(prefix); -+ if (strncmp(prefix, name_str, prefix_len) == 0) { -+ name_str += prefix_len; -+ } -+ } -+ return name_str; -+ } -+ -+ // 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) { -+ ResourceMark rm; -+ char* name_str = method_name_without_prefixes(method); -+ return search_prefix_name_space(0, name_str, strlen(name_str), -+ method->signature()); -+ } -+ -+public: -+ -+ // Construct a native method transfer processor for this class. -+ TransferNativeFunctionRegistration(instanceKlassHandle _the_class) { -+ assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); -+ -+ the_class = _the_class; -+ prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count); -+ } -+ -+ // Attempt to transfer any of the old or deleted methods that are native -+ void transfer_registrations(instanceKlassHandle old_klass, int* old_methods, int methods_length) { -+ for (int j = 0; j < methods_length; j++) { -+ methodOop old_method = (methodOop)old_klass->methods()->obj_at(old_methods[j]); -+ -+ if (old_method->is_native() && old_method->has_native_function()) { -+ methodOop 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); -+ -+ TRACE_RC3("Transfering native function for method %s", old_method->name()->as_C_string()); -+ } -+ } -+ } - } -+}; -+ -+// Don't lose the association between a native method and its JNI function. -+void VM_RedefineClasses::transfer_old_native_function_registrations(instanceKlassHandle old_klass) { -+ TransferNativeFunctionRegistration transfer(old_klass); -+ transfer.transfer_registrations(old_klass, _deleted_methods, _deleted_methods_length); -+ transfer.transfer_registrations(old_klass, _matching_old_methods, _matching_methods_length); - } +- } +-} diff --git a/src/share/vm/prims/jvmtiRedefineClasses.hpp b/src/share/vm/prims/jvmtiRedefineClasses.hpp -index 671f2ae..8333cee 100644 --- a/src/share/vm/prims/jvmtiRedefineClasses.hpp +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp @@ -1,5 +1,5 @@ @@ -8929,7 +8866,8 @@ index 671f2ae..8333cee 100644 +#include "oops/fieldStreams.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" -#include "runtime/vm_operations.hpp" -- ++#include "gc_implementation/shared/vmGCOperations.hpp" + -// Introduction: -// -// The RedefineClasses() API is used to change the definition of one or @@ -9238,14 +9176,12 @@ index 671f2ae..8333cee 100644 -// The same literal values are also used in elsewhere. We need to -// coordinate a cleanup of these constants with Runtime. -// -- --class VM_RedefineClasses: public VM_Operation { -+#include "gc_implementation/shared/vmGCOperations.hpp" -+ +// New version that allows arbitrary changes to already loaded classes. +class VM_RedefineClasses: public VM_GC_Operation { - private: -+ ++ private: + +-class VM_RedefineClasses: public VM_Operation { +- private: // These static fields are needed by SystemDictionary::classes_do() // facility and the adjust_cpool_cache_and_vtable() helper: static objArrayOop _old_methods; @@ -9269,7 +9205,7 @@ index 671f2ae..8333cee 100644 // The instance fields are used to pass information from // doit_prologue() to doit() and doit_epilogue(). -@@ -366,40 +63,28 @@ class VM_RedefineClasses: public VM_Operation { +@@ -366,40 +63,28 @@ // RetransformClasses. Indicate which. JvmtiClassLoadKind _class_load_kind; @@ -9290,13 +9226,6 @@ index 671f2ae..8333cee 100644 - elapsedTimer _timer_rsc_phase1; - elapsedTimer _timer_rsc_phase2; - elapsedTimer _timer_vm_op_prologue; -- -- // These routines are roughly in call order unless otherwise noted. -- -- // Load the caller's new class definition(s) into _scratch_classes. -- // Constant pool merging work is done here as needed. Also calls -- // compare_and_normalize_class_versions() to verify the class -- // definition(s). + elapsedTimer _timer_total; + elapsedTimer _timer_prologue; + elapsedTimer _timer_class_linking; @@ -9306,7 +9235,13 @@ index 671f2ae..8333cee 100644 + elapsedTimer _timer_heap_iteration; + elapsedTimer _timer_redefinition; + elapsedTimer _timer_vm_op_epilogue; -+ + +- // These routines are roughly in call order unless otherwise noted. +- +- // Load the caller's new class definition(s) into _scratch_classes. +- // Constant pool merging work is done here as needed. Also calls +- // compare_and_normalize_class_versions() to verify the class +- // definition(s). + jvmtiError check_redefinition_allowed(instanceKlassHandle new_class); + jvmtiError find_sorted_affected_classes( ); + jvmtiError find_class_bytes(instanceKlassHandle the_class, const unsigned char **class_bytes, jint *class_byte_count, jboolean *not_changed); @@ -9326,7 +9261,7 @@ index 671f2ae..8333cee 100644 // Figure out which new methods match old methods in name and signature, // which methods have been added, and which are no longer present void compute_added_deleted_matching_methods(); -@@ -407,95 +92,71 @@ class VM_RedefineClasses: public VM_Operation { +@@ -407,95 +92,71 @@ // Change jmethodIDs to point to the new methods void update_jmethod_ids(); @@ -9340,14 +9275,14 @@ index 671f2ae..8333cee 100644 - int * emcp_method_count_p); - void transfer_old_native_function_registrations(instanceKlassHandle the_class); + void swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class); -+ -+ static void add_affected_klasses( klassOop obj ); - // 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 - // to fix up these pointers. - static void adjust_cpool_cache_and_vtable(klassOop k_oop, oop loader, TRAPS); ++ static void add_affected_klasses( klassOop obj ); ++ + static jvmtiError do_topological_class_sorting(const jvmtiClassDefinition *class_definitions, int class_count, TRAPS); // Install the redefinition of a class @@ -9467,7 +9402,6 @@ index 671f2ae..8333cee 100644 #endif // SHARE_VM_PRIMS_JVMTIREDEFINECLASSES_HPP diff --git a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp -index 878d300..9dbe748 100644 --- a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp +++ b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp @@ -1,5 +1,5 @@ @@ -9605,10 +9539,9 @@ index 878d300..9dbe748 100644 - -#endif // SHARE_VM_PRIMS_JVMTIREDEFINECLASSESTRACE_HPP diff --git a/src/share/vm/prims/methodComparator.cpp b/src/share/vm/prims/methodComparator.cpp -index 60eaf97..785dc24 100644 --- a/src/share/vm/prims/methodComparator.cpp +++ b/src/share/vm/prims/methodComparator.cpp -@@ -42,10 +42,9 @@ bool MethodComparator::methods_EMCP(methodOop old_method, methodOop new_method) +@@ -42,10 +42,9 @@ if (old_method->code_size() != new_method->code_size()) return false; if (check_stack_and_locals_size(old_method, new_method) != 0) { @@ -9621,7 +9554,7 @@ index 60eaf97..785dc24 100644 return false; } -@@ -114,10 +113,9 @@ bool MethodComparator::methods_switchable(methodOop old_method, methodOop new_me +@@ -114,10 +113,9 @@ // Now we can test all forward jumps for (int i = 0; i < fwd_jmps.length() / 2; i++) { if (! bci_map.old_and_new_locations_same(fwd_jmps.at(i*2), fwd_jmps.at(i*2+1))) { @@ -9635,7 +9568,6 @@ index 60eaf97..785dc24 100644 } } diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp -index 22d450b..bac1ae6 100644 --- a/src/share/vm/runtime/arguments.cpp +++ b/src/share/vm/runtime/arguments.cpp @@ -54,8 +54,8 @@ @@ -9649,7 +9581,7 @@ index 22d450b..bac1ae6 100644 #define DEFAULT_JAVA_LAUNCHER "generic" char** Arguments::_jvm_flags_array = NULL; -@@ -1792,6 +1792,16 @@ bool Arguments::check_gc_consistency() { +@@ -1792,6 +1792,16 @@ status = false; } @@ -9666,7 +9598,7 @@ index 22d450b..bac1ae6 100644 return status; } -@@ -3208,7 +3218,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { +@@ -3208,7 +3218,7 @@ // Set flags if Aggressive optimization flags (-XX:+AggressiveOpts) enabled. set_aggressive_opts_flags(); @@ -9675,7 +9607,7 @@ index 22d450b..bac1ae6 100644 // Turn off biased locking for locking debug mode flags, // which are subtlely different from each other but neither works with // biased locking. -@@ -3225,6 +3235,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { +@@ -3225,6 +3235,7 @@ } UseBiasedLocking = false; } @@ -9684,10 +9616,9 @@ index 22d450b..bac1ae6 100644 #ifdef CC_INTERP // Clear flags not supported by the C++ interpreter diff --git a/src/share/vm/runtime/fieldDescriptor.cpp b/src/share/vm/runtime/fieldDescriptor.cpp -index 3d5213f..9cc701b 100644 --- a/src/share/vm/runtime/fieldDescriptor.cpp +++ b/src/share/vm/runtime/fieldDescriptor.cpp -@@ -92,7 +92,8 @@ void fieldDescriptor::initialize(klassOop k, int index) { +@@ -92,7 +92,8 @@ instanceKlass* ik = instanceKlass::cast(k); _cp = ik->constants(); FieldInfo* f = ik->field(index); @@ -9698,10 +9629,9 @@ index 3d5213f..9cc701b 100644 _access_flags = accessFlags_from(f->access_flags()); guarantee(f->name_index() != 0 && f->signature_index() != 0, "bad constant pool index for fieldDescriptor"); diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp -index 8df7220..341b399 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp -@@ -1230,6 +1230,11 @@ class CommandLineFlags { +@@ -1230,6 +1230,11 @@ product(intx, TraceRedefineClasses, 0, \ "Trace level for JVMTI RedefineClasses") \ \ @@ -9714,10 +9644,9 @@ index 8df7220..341b399 100644 "run the MethodComparator on all loaded methods") \ \ diff --git a/src/share/vm/runtime/interfaceSupport.hpp b/src/share/vm/runtime/interfaceSupport.hpp -index 2875ee0..61fd8fe 100644 --- a/src/share/vm/runtime/interfaceSupport.hpp +++ b/src/share/vm/runtime/interfaceSupport.hpp -@@ -296,7 +296,7 @@ class ThreadToNativeFromVM : public ThreadStateTransition { +@@ -296,7 +296,7 @@ ThreadToNativeFromVM(JavaThread *thread) : ThreadStateTransition(thread) { // We are leaving the VM at this point and going directly to native code. // Block, if we are in the middle of a safepoint synchronization. @@ -9727,10 +9656,9 @@ index 2875ee0..61fd8fe 100644 trans_and_fence(_thread_in_vm, _thread_in_native); // Check for pending. async. exceptions or suspends. diff --git a/src/share/vm/runtime/javaCalls.cpp b/src/share/vm/runtime/javaCalls.cpp -index edbba98..4a27925 100644 --- a/src/share/vm/runtime/javaCalls.cpp +++ b/src/share/vm/runtime/javaCalls.cpp -@@ -60,7 +60,7 @@ JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, Handle receiver, Ja +@@ -60,7 +60,7 @@ bool clear_pending_exception = true; guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code"); @@ -9740,10 +9668,9 @@ index edbba98..4a27925 100644 _result = result; diff --git a/src/share/vm/runtime/jniHandles.cpp b/src/share/vm/runtime/jniHandles.cpp -index 3cbcaca..30839d7 100644 --- a/src/share/vm/runtime/jniHandles.cpp +++ b/src/share/vm/runtime/jniHandles.cpp -@@ -112,6 +112,10 @@ jobject JNIHandles::make_weak_global(Handle obj) { +@@ -112,6 +112,10 @@ } jmethodID JNIHandles::make_jmethod_id(methodHandle mh) { @@ -9755,10 +9682,9 @@ index 3cbcaca..30839d7 100644 } diff --git a/src/share/vm/runtime/mutex.cpp b/src/share/vm/runtime/mutex.cpp -index 2095237..c541434 100644 --- a/src/share/vm/runtime/mutex.cpp +++ b/src/share/vm/runtime/mutex.cpp -@@ -1227,7 +1227,7 @@ Monitor * Monitor::get_least_ranked_lock(Monitor * locks) { +@@ -1227,7 +1227,7 @@ // in increasing rank order (modulo any native ranks) for (tmp = locks; tmp != NULL; tmp = tmp->next()) { if (tmp->next() != NULL) { @@ -9767,7 +9693,7 @@ index 2095237..c541434 100644 tmp->rank() <= tmp->next()->rank(), "mutex rank anomaly?"); } } -@@ -1247,7 +1247,7 @@ Monitor* Monitor::get_least_ranked_lock_besides_this(Monitor* locks) { +@@ -1247,7 +1247,7 @@ // in increasing rank order (modulo any native ranks) for (tmp = locks; tmp != NULL; tmp = tmp->next()) { if (tmp->next() != NULL) { @@ -9776,7 +9702,7 @@ index 2095237..c541434 100644 tmp->rank() <= tmp->next()->rank(), "mutex rank anomaly?"); } } -@@ -1310,6 +1310,7 @@ void Monitor::set_owner_implementation(Thread *new_owner) { +@@ -1310,6 +1310,7 @@ // already hold Terminator_lock - may happen because of periodic safepoints if (this->rank() != Mutex::native && this->rank() != Mutex::suspend_resume && @@ -9785,10 +9711,9 @@ index 2095237..c541434 100644 !SafepointSynchronize::is_at_safepoint() && this != Interrupt_lock && diff --git a/src/share/vm/runtime/mutex.hpp b/src/share/vm/runtime/mutex.hpp -index 7d2cd82..11eb32e 100644 --- a/src/share/vm/runtime/mutex.hpp +++ b/src/share/vm/runtime/mutex.hpp -@@ -109,7 +109,8 @@ class Monitor : public CHeapObj<mtInternal> { +@@ -109,7 +109,8 @@ barrier = safepoint + 1, nonleaf = barrier + 1, max_nonleaf = nonleaf + 900, @@ -9799,7 +9724,6 @@ index 7d2cd82..11eb32e 100644 // The WaitSet and EntryList linked lists are composed of ParkEvents. diff --git a/src/share/vm/runtime/mutexLocker.cpp b/src/share/vm/runtime/mutexLocker.cpp -index d9184c7..cfd1f3a 100644 --- a/src/share/vm/runtime/mutexLocker.cpp +++ b/src/share/vm/runtime/mutexLocker.cpp @@ -49,6 +49,7 @@ @@ -9810,7 +9734,7 @@ index d9184c7..cfd1f3a 100644 Monitor* SystemDictionary_lock = NULL; Mutex* PackageTable_lock = NULL; Mutex* CompiledIC_lock = NULL; -@@ -281,6 +282,7 @@ void mutex_init() { +@@ -281,6 +282,7 @@ def(Debug3_lock , Mutex , nonleaf+4, true ); def(CompileThread_lock , Monitor, nonleaf+5, false); def(PeriodicTask_lock , Monitor, nonleaf+5, true); @@ -9819,7 +9743,6 @@ index d9184c7..cfd1f3a 100644 #ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true); diff --git a/src/share/vm/runtime/mutexLocker.hpp b/src/share/vm/runtime/mutexLocker.hpp -index 90011d8..d6b0c54 100644 --- a/src/share/vm/runtime/mutexLocker.hpp +++ b/src/share/vm/runtime/mutexLocker.hpp @@ -43,6 +43,7 @@ @@ -9831,10 +9754,9 @@ index 90011d8..d6b0c54 100644 extern Mutex* PackageTable_lock; // a lock on the class loader package table extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access diff --git a/src/share/vm/runtime/reflection.cpp b/src/share/vm/runtime/reflection.cpp -index 1665d93..6baabba 100644 --- a/src/share/vm/runtime/reflection.cpp +++ b/src/share/vm/runtime/reflection.cpp -@@ -468,7 +468,8 @@ bool Reflection::verify_class_access(klassOop current_class, klassOop new_class, +@@ -468,7 +468,8 @@ // sun/reflect/MagicAccessorImpl subclasses to succeed trivially. if ( JDK_Version::is_gte_jdk14x_version() && UseNewReflection @@ -9844,7 +9766,7 @@ index 1665d93..6baabba 100644 return true; } -@@ -519,6 +520,12 @@ bool Reflection::verify_field_access(klassOop current_class, +@@ -519,6 +520,12 @@ AccessFlags access, bool classloader_only, bool protected_restriction) { @@ -9857,7 +9779,7 @@ index 1665d93..6baabba 100644 // Verify that current_class can access a field of field_class, where that // field's access bits are "access". We assume that we've already verified // that current_class can access field_class. -@@ -560,7 +567,8 @@ bool Reflection::verify_field_access(klassOop current_class, +@@ -560,7 +567,8 @@ // sun/reflect/MagicAccessorImpl subclasses to succeed trivially. if ( JDK_Version::is_gte_jdk14x_version() && UseNewReflection @@ -9868,10 +9790,9 @@ index 1665d93..6baabba 100644 } diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp -index 709d783..689b9a2 100644 --- a/src/share/vm/runtime/sharedRuntime.cpp +++ b/src/share/vm/runtime/sharedRuntime.cpp -@@ -603,21 +603,13 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread *thread, Symbol* n +@@ -603,21 +603,13 @@ // JRT_LEAF(int, SharedRuntime::rc_trace_method_entry( JavaThread* thread, methodOopDesc* method)) @@ -9895,7 +9816,7 @@ index 709d783..689b9a2 100644 } return 0; JRT_END -@@ -1137,7 +1129,20 @@ methodHandle SharedRuntime::resolve_helper(JavaThread *thread, +@@ -1137,7 +1129,20 @@ if (JvmtiExport::can_hotswap_or_post_breakpoint()) { int retry_count = 0; while (!HAS_PENDING_EXCEPTION && callee_method->is_old() && @@ -9918,10 +9839,9 @@ index 709d783..689b9a2 100644 // resolve this method. // If the method has been redefined, we need to try again. diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp -index ae28b65..bb0681e 100644 --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp -@@ -216,6 +216,8 @@ Thread::Thread() { +@@ -216,6 +216,8 @@ set_self_raw_id(0); set_lgrp_id(-1); @@ -9930,7 +9850,7 @@ index ae28b65..bb0681e 100644 // allocated data structures set_osthread(NULL); set_resource_area(new (mtThread)ResourceArea()); -@@ -249,6 +251,7 @@ Thread::Thread() { +@@ -249,6 +251,7 @@ omFreeProvision = 32 ; omInUseList = NULL ; omInUseCount = 0 ; @@ -9938,7 +9858,7 @@ index ae28b65..bb0681e 100644 #ifdef ASSERT _visited_for_critical_count = false; -@@ -884,6 +887,15 @@ bool Thread::owns_locks_but_compiled_lock() const { +@@ -884,6 +887,15 @@ return false; } @@ -9954,7 +9874,7 @@ index ae28b65..bb0681e 100644 #endif -@@ -1637,7 +1649,7 @@ void JavaThread::run() { +@@ -1637,7 +1649,7 @@ ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm); assert(JavaThread::current() == this, "sanity check"); @@ -9963,7 +9883,7 @@ index ae28b65..bb0681e 100644 DTRACE_THREAD_PROBE(start, this); -@@ -3193,7 +3205,7 @@ static void compiler_thread_entry(JavaThread* thread, TRAPS) { +@@ -3193,7 +3205,7 @@ // Create a CompilerThread CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters) @@ -9972,7 +9892,7 @@ index ae28b65..bb0681e 100644 _env = NULL; _log = NULL; _task = NULL; -@@ -3201,6 +3213,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters) +@@ -3201,6 +3213,7 @@ _counters = counters; _buffer_blob = NULL; _scanned_nmethod = NULL; @@ -9981,10 +9901,9 @@ index ae28b65..bb0681e 100644 #ifndef PRODUCT _ideal_graph_printer = NULL; diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp -index 774bd27..4620820 100644 --- a/src/share/vm/runtime/thread.hpp +++ b/src/share/vm/runtime/thread.hpp -@@ -202,12 +202,15 @@ class Thread: public ThreadShadow { +@@ -202,12 +202,15 @@ public: void enter_signal_handler() { _num_nested_signal++; } void leave_signal_handler() { _num_nested_signal--; } @@ -10001,7 +9920,7 @@ index 774bd27..4620820 100644 // Active_handles points to a block of handles JNIHandleBlock* _active_handles; -@@ -530,10 +533,15 @@ public: +@@ -530,10 +533,15 @@ uintptr_t _self_raw_id; // used by get_thread (mutable) int _lgrp_id; @@ -10017,7 +9936,7 @@ index 774bd27..4620820 100644 void set_stack_base(address base) { _stack_base = base; } size_t stack_size() const { return _stack_size; } void set_stack_size(size_t size) { _stack_size = size; } -@@ -570,6 +578,7 @@ public: +@@ -570,6 +578,7 @@ void print_owned_locks() const { print_owned_locks_on(tty); } Monitor* owned_locks() const { return _owned_locks; } bool owns_locks() const { return owned_locks() != NULL; } @@ -10025,7 +9944,7 @@ index 774bd27..4620820 100644 bool owns_locks_but_compiled_lock() const; // Deadlock detection -@@ -1793,6 +1802,8 @@ class CompilerThread : public JavaThread { +@@ -1793,6 +1802,8 @@ CompileTask* _task; CompileQueue* _queue; BufferBlob* _buffer_blob; @@ -10034,7 +9953,7 @@ index 774bd27..4620820 100644 nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper -@@ -1802,12 +1813,16 @@ class CompilerThread : public JavaThread { +@@ -1802,12 +1813,16 @@ CompilerThread(CompileQueue* queue, CompilerCounters* counters); @@ -10052,10 +9971,9 @@ index 774bd27..4620820 100644 // Get/set the thread's compilation environment. ciEnv* env() { return _env; } diff --git a/src/share/vm/runtime/vmThread.cpp b/src/share/vm/runtime/vmThread.cpp -index 7643670..0d3cd70 100644 --- a/src/share/vm/runtime/vmThread.cpp +++ b/src/share/vm/runtime/vmThread.cpp -@@ -691,6 +691,9 @@ void VMThread::execute(VM_Operation* op) { +@@ -691,6 +691,9 @@ void VMThread::oops_do(OopClosure* f, CodeBlobClosure* cf) { Thread::oops_do(f, cf); _vm_queue->oops_do(f); @@ -10066,10 +9984,9 @@ index 7643670..0d3cd70 100644 //------------------------------------------------------------------------------------------------------------------ diff --git a/src/share/vm/utilities/exceptions.cpp b/src/share/vm/utilities/exceptions.cpp -index 03f254d..18e324b 100644 --- a/src/share/vm/utilities/exceptions.cpp +++ b/src/share/vm/utilities/exceptions.cpp -@@ -254,6 +254,8 @@ Handle Exceptions::new_exception(Thread *thread, Symbol* name, +@@ -254,6 +254,8 @@ assert(thread->is_Java_thread(), "can only be called by a Java thread"); assert(!thread->has_pending_exception(), "already has exception"); @@ -10078,7 +9995,7 @@ index 03f254d..18e324b 100644 Handle h_exception; // Resolve exception klass -@@ -285,6 +287,7 @@ Handle Exceptions::new_exception(Thread *thread, Symbol* name, +@@ -285,6 +287,7 @@ h_exception = Handle(thread, thread->pending_exception()); thread->clear_pending_exception(); } @@ -10087,10 +10004,9 @@ index 03f254d..18e324b 100644 } diff --git a/src/share/vm/utilities/growableArray.hpp b/src/share/vm/utilities/growableArray.hpp -index 2a6d6b8..4b6927f 100644 --- a/src/share/vm/utilities/growableArray.hpp +++ b/src/share/vm/utilities/growableArray.hpp -@@ -145,6 +145,33 @@ class GenericGrowableArray : public ResourceObj { +@@ -145,6 +145,33 @@ assert(on_stack(), "fast ResourceObj path only"); return (void*)resource_allocate_bytes(thread, elementSize * _max); } |