diff options
-rw-r--r-- | build.gradle | 70 | ||||
-rw-r--r-- | hotspot/.hg/patches/arguments-java8.patch | 57 | ||||
-rw-r--r-- | hotspot/.hg/patches/distro-name.patch | 13 | ||||
-rw-r--r-- | hotspot/.hg/patches/full-jdk7u11-b21.patch (renamed from patches/full-jdk7u11-b21.patch) | 5817 | ||||
-rw-r--r-- | hotspot/.hg/patches/full-jdk7u45-b08.patch (renamed from patches/full-jdk7u45-b08.patch) | 12 | ||||
-rw-r--r-- | hotspot/.hg/patches/full-jdk7u51-b13.patch (renamed from patches/full-jdk7u51-b13.patch) | 11 | ||||
-rw-r--r-- | hotspot/.hg/patches/gc-java8.patch | 613 | ||||
-rw-r--r-- | hotspot/.hg/patches/light-jdk7u40-b43.patch (renamed from patches/light-jdk7u40-b43.patch) | 12 | ||||
-rw-r--r-- | hotspot/.hg/patches/light-jdk7u51-b13.patch (renamed from patches/light-jdk7u51-b13.patch) | 12 | ||||
-rw-r--r-- | hotspot/.hg/patches/light-jdk8u5-b13.patch | 886 | ||||
-rw-r--r-- | hotspot/.hg/patches/series | 16 | ||||
-rw-r--r-- | patches/light-jdk8u5-b13.patch | 4258 |
12 files changed, 3850 insertions, 7927 deletions
diff --git a/build.gradle b/build.gradle index efa1d056..500cb9b5 100644 --- a/build.gradle +++ b/build.gradle @@ -33,47 +33,63 @@ project('hotspot') { } } - task clone(description: 'Clone HotSpot repository') { - onlyIf { !file('hotspot').exists() } + task init(description: 'Initialize HotSpot repository') << { + file('hotspot').mkdir() + exec { + executable 'hg' + args 'init' + ignoreExitValue = true + } + } + + task pull(description: 'Pull OpenJDK HotSpot changes') { doLast { def hotspotRepository = hotspotTag.contains('jdk7') ? 'http://hg.openjdk.java.net/jdk7u/jdk7u/hotspot' : 'http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot' exec { - workingDir '..' executable 'hg' - args 'clone', hotspotRepository + args 'pull', hotspotRepository } } } - task patch(description: 'Patch HotSpot sources', dependsOn: clone) << { - exec { - executable 'hg' - args 'pull' - } - exec { - executable 'hg' - args 'update', '-C', '-r', hotspotTag - } - new ByteArrayOutputStream().withStream { os -> + task patch(description: 'Patch HotSpot sources', dependsOn: pull) { + + doLast { exec { - workingDir 'hotspot' executable 'hg' - args 'status' - standardOutput os + args 'qpop', '-a' } - // Purge unversioned files - def str = os.toString() - def matcher = str =~ /(?m)^\?\s+(.*)$/ - matcher.each { - ant.delete(file: new File(file('hotspot'), it[1])) + exec { + executable 'hg' + args 'update', '-C', '-r', hotspotTag + } + new ByteArrayOutputStream().withStream { os -> + exec { + workingDir 'hotspot' + executable 'hg' + args 'status' + standardOutput os + } + // Purge unversioned files + def str = os.toString() + def matcher = str =~ /(?m)^\?\s+(.*)$/ + matcher.each { + ant.delete(file: new File(file('hotspot'), it[1])) + } + } + def guards = [flavor, hotspotTag.contains('jdk7') ? 'jdk7' : 'jdk8', + hotspotTag, flavor + '-' + hotspotTag] + exec { + executable 'hg' + args 'qselect' + args guards + } + exec { + executable 'hg' + args 'qpush', '-a' } - } - // Use hg import since ant.patchfile requires 'patch' to be installed - exec { - executable 'hg' - args 'import', '--no-commit', "../patches/${flavor}-${hotspotTag}.patch" } } diff --git a/hotspot/.hg/patches/arguments-java8.patch b/hotspot/.hg/patches/arguments-java8.patch new file mode 100644 index 00000000..fc505020 --- /dev/null +++ b/hotspot/.hg/patches/arguments-java8.patch @@ -0,0 +1,57 @@ +Adds AllowEnhancedClassRedefinition argument. +diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp +--- a/src/share/vm/runtime/arguments.cpp ++++ b/src/share/vm/runtime/arguments.cpp +@@ -59,8 +59,8 @@ + #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" + #endif // INCLUDE_ALL_GCS + +-// Note: This is a special bug reporting site for the JVM +-#define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp" ++// (DCEVM) The DCE VM has its own JIRA bug tracking system. ++#define DEFAULT_VENDOR_URL_BUG "https://github.com/Guidewire/DCEVM/issues" + #define DEFAULT_JAVA_LAUNCHER "generic" + + // Disable options not supported in this release, with a warning if they +@@ -1507,6 +1507,10 @@ + + void Arguments::set_ergonomics_flags() { + ++ if (AllowEnhancedClassRedefinition) { ++ // (DCEVM) enforces serial GC ++ FLAG_SET_ERGO(bool, UseSerialGC, true); ++ } + if (os::is_server_class_machine()) { + // If no other collector is requested explicitly, + // let the VM select the collector based on +@@ -1948,6 +1952,17 @@ + if (UseConcMarkSweepGC || UseParNewGC) i++; + if (UseParallelGC || UseParallelOldGC) i++; + if (UseG1GC) i++; ++ ++ if (AllowEnhancedClassRedefinition) { ++ // (DCEVM) Must use serial GC. This limitation applies because the instance size changing GC modifications ++ // are only built into the mark and compact algorithm. ++ if (!UseSerialGC && i >= 1) { ++ jio_fprintf(defaultStream::error_stream(), ++ "Must use the serial GC in the DCEVM\n"); ++ status = false; ++ } ++ } ++ + if (i > 1) { + jio_fprintf(defaultStream::error_stream(), + "Conflicting collector combinations in option list; " +diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp +--- a/src/share/vm/runtime/globals.hpp ++++ b/src/share/vm/runtime/globals.hpp +@@ -1273,6 +1273,9 @@ + product(intx, TraceRedefineClasses, 0, \ + "Trace level for JVMTI RedefineClasses") \ + \ ++ product(bool, AllowEnhancedClassRedefinition, true, \ ++ "Allow enhanced class redefinition beyond swapping method bodies")\ ++ \ + develop(bool, StressMethodComparator, false, \ + "Run the MethodComparator on all loaded methods") \ + \ diff --git a/hotspot/.hg/patches/distro-name.patch b/hotspot/.hg/patches/distro-name.patch new file mode 100644 index 00000000..62e5edca --- /dev/null +++ b/hotspot/.hg/patches/distro-name.patch @@ -0,0 +1,13 @@ +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 +@@ -27,6 +27,6 @@ + # + + # Don't put quotes (fail windows build). +-HOTSPOT_VM_DISTRO=OpenJDK ++HOTSPOT_VM_DISTRO=Dynamic Code Evolution + COMPANY_NAME= + PRODUCT_NAME=OpenJDK + diff --git a/patches/full-jdk7u11-b21.patch b/hotspot/.hg/patches/full-jdk7u11-b21.patch index 9f8e04e2..76a16fcd 100644 --- a/patches/full-jdk7u11-b21.patch +++ b/hotspot/.hg/patches/full-jdk7u11-b21.patch @@ -1,20 +1,7 @@ -diff --git a/make/openjdk_distro b/make/openjdk_distro -index 520b33d..ea7eff0 100644 ---- a/make/openjdk_distro -+++ b/make/openjdk_distro -@@ -27,6 +27,6 @@ - # - - # Don't put quotes (fail windows build). --HOTSPOT_VM_DISTRO=OpenJDK -+HOTSPOT_VM_DISTRO=Dynamic Code Evolution - COMPANY_NAME= - PRODUCT_NAME=OpenJDK diff --git a/src/cpu/x86/vm/templateTable_x86_32.cpp b/src/cpu/x86/vm/templateTable_x86_32.cpp -index 1cbc67e..2b22724 100644 --- a/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp -@@ -2109,6 +2109,22 @@ void TemplateTable::resolve_cache_and_index(int byte_no, +@@ -2109,6 +2109,22 @@ // resolve first time through address entry; switch (bytecode()) { @@ -37,7 +24,7 @@ index 1cbc67e..2b22724 100644 case Bytecodes::_getstatic : // fall through case Bytecodes::_putstatic : // fall through case Bytecodes::_getfield : // fall through -@@ -2203,6 +2219,7 @@ void TemplateTable::load_invoke_cp_cache_entry(int byte_no, +@@ -2203,6 +2219,7 @@ // Correct values of the cache and index registers are preserved. void TemplateTable::jvmti_post_field_access(Register cache, Register index, @@ -45,7 +32,7 @@ index 1cbc67e..2b22724 100644 bool is_static, bool has_tos) { if (JvmtiExport::can_post_field_access()) { -@@ -2229,7 +2246,11 @@ void TemplateTable::jvmti_post_field_access(Register cache, +@@ -2229,7 +2246,11 @@ // cache: cache entry pointer __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), rax, cache); @@ -58,7 +45,7 @@ index 1cbc67e..2b22724 100644 __ bind(L1); } } -@@ -2250,7 +2271,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) { +@@ -2250,7 +2271,7 @@ const Register flags = rax; resolve_cache_and_index(byte_no, noreg, cache, index, sizeof(u2)); @@ -67,7 +54,7 @@ index 1cbc67e..2b22724 100644 load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); if (!is_static) pop_and_check_object(obj); -@@ -2385,7 +2406,7 @@ void TemplateTable::getstatic(int byte_no) { +@@ -2385,7 +2406,7 @@ // The registers cache and index expected to be set before call. // The function may destroy various registers, just not the cache and index registers. @@ -76,7 +63,7 @@ index 1cbc67e..2b22724 100644 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); -@@ -2443,7 +2464,11 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is +@@ -2443,7 +2464,11 @@ // rcx: jvalue object on the stack __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), rbx, rax, rcx); @@ -89,7 +76,7 @@ index 1cbc67e..2b22724 100644 __ bind(L1); } } -@@ -2459,7 +2484,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static) { +@@ -2459,7 +2484,7 @@ const Register flags = rax; resolve_cache_and_index(byte_no, noreg, cache, index, sizeof(u2)); @@ -98,7 +85,7 @@ index 1cbc67e..2b22724 100644 load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); // Doug Lea believes this is not needed with current Sparcs (TSO) and Intel (PSO). -@@ -2697,6 +2722,11 @@ void TemplateTable::jvmti_post_fast_field_mod() { +@@ -2697,6 +2722,11 @@ // rax,: cache entry pointer // rcx: jvalue object on the stack __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), rbx, rax, rcx); @@ -110,7 +97,7 @@ index 1cbc67e..2b22724 100644 if (bytecode() == Bytecodes::_fast_lputfield) __ pop(rdx); // restore high value __ pop(rax); // restore lower value __ addptr(rsp, sizeof(jvalue)); // release jvalue object space -@@ -2817,6 +2847,11 @@ void TemplateTable::fast_accessfield(TosState state) { +@@ -2817,6 +2847,11 @@ // rcx: cache entry pointer __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), rax, rcx); __ pop_ptr(rax); // restore object pointer @@ -122,7 +109,7 @@ index 1cbc67e..2b22724 100644 __ bind(L1); } -@@ -2987,6 +3022,26 @@ void TemplateTable::invokevirtual_helper(Register index, Register recv, +@@ -2987,6 +3022,26 @@ __ bind(notFinal); @@ -149,7 +136,7 @@ index 1cbc67e..2b22724 100644 // get receiver klass __ null_check(recv, oopDesc::klass_offset_in_bytes()); // Keep recv in rcx for callee expects it there -@@ -3068,6 +3123,31 @@ void TemplateTable::invokeinterface(int byte_no) { +@@ -3068,6 +3123,31 @@ invokevirtual_helper(rbx, rcx, rdx); __ bind(notMethod); @@ -182,10 +169,9 @@ index 1cbc67e..2b22724 100644 __ restore_locals(); // restore rdi __ load_klass(rdx, rcx); diff --git a/src/cpu/x86/vm/templateTable_x86_64.cpp b/src/cpu/x86/vm/templateTable_x86_64.cpp -index 0e5ac27..c77a358 100644 --- a/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp -@@ -2145,6 +2145,22 @@ void TemplateTable::resolve_cache_and_index(int byte_no, +@@ -2145,6 +2145,22 @@ // resolve first time through address entry; switch (bytecode()) { @@ -208,7 +194,7 @@ index 0e5ac27..c77a358 100644 case Bytecodes::_getstatic: case Bytecodes::_putstatic: case Bytecodes::_getfield: -@@ -2251,7 +2267,7 @@ void TemplateTable::load_invoke_cp_cache_entry(int byte_no, +@@ -2251,7 +2267,7 @@ // The registers cache and index expected to be set before call. // Correct values of the cache and index registers are preserved. void TemplateTable::jvmti_post_field_access(Register cache, Register index, @@ -217,7 +203,7 @@ index 0e5ac27..c77a358 100644 // do the JVMTI work here to avoid disturbing the register state below // We use c_rarg registers here because we want to use the register used in // the call to the VM -@@ -2282,7 +2298,11 @@ void TemplateTable::jvmti_post_field_access(Register cache, Register index, +@@ -2282,7 +2298,11 @@ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), c_rarg1, c_rarg2, c_rarg3); @@ -230,7 +216,7 @@ index 0e5ac27..c77a358 100644 __ bind(L1); } } -@@ -2304,7 +2324,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) { +@@ -2304,7 +2324,7 @@ const Register bc = c_rarg3; // uses same reg as obj, so don't mix them resolve_cache_and_index(byte_no, noreg, cache, index, sizeof(u2)); @@ -239,7 +225,7 @@ index 0e5ac27..c77a358 100644 load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); if (!is_static) { -@@ -2438,7 +2458,7 @@ void TemplateTable::getstatic(int byte_no) { +@@ -2438,7 +2458,7 @@ // The registers cache and index expected to be set before call. // The function may destroy various registers, just not the cache and index registers. @@ -248,7 +234,7 @@ index 0e5ac27..c77a358 100644 transition(vtos, vtos); ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); -@@ -2491,7 +2511,11 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is +@@ -2491,7 +2511,11 @@ CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), c_rarg1, c_rarg2, c_rarg3); @@ -261,7 +247,7 @@ index 0e5ac27..c77a358 100644 __ bind(L1); } } -@@ -2507,7 +2531,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static) { +@@ -2507,7 +2531,7 @@ const Register bc = c_rarg3; resolve_cache_and_index(byte_no, noreg, cache, index, sizeof(u2)); @@ -270,7 +256,7 @@ index 0e5ac27..c77a358 100644 load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); // [jk] not needed currently -@@ -2715,6 +2739,11 @@ void TemplateTable::jvmti_post_fast_field_mod() { +@@ -2715,6 +2739,11 @@ CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), rbx, c_rarg2, c_rarg3); @@ -282,7 +268,7 @@ index 0e5ac27..c77a358 100644 __ pop(rax); // restore lower value __ addptr(rsp, sizeof(jvalue)); // release jvalue object space __ bind(L2); -@@ -2815,6 +2844,11 @@ void TemplateTable::fast_accessfield(TosState state) { +@@ -2815,6 +2844,11 @@ InterpreterRuntime::post_field_access), c_rarg1, c_rarg2); __ pop_ptr(rax); // restore object pointer @@ -294,7 +280,7 @@ index 0e5ac27..c77a358 100644 __ bind(L1); } -@@ -3030,6 +3064,26 @@ void TemplateTable::invokevirtual_helper(Register index, +@@ -3030,6 +3064,26 @@ __ bind(notFinal); @@ -321,7 +307,7 @@ index 0e5ac27..c77a358 100644 // get receiver klass __ null_check(recv, oopDesc::klass_offset_in_bytes()); __ load_klass(rax, recv); -@@ -3113,6 +3167,35 @@ void TemplateTable::invokeinterface(int byte_no) { +@@ -3113,6 +3167,35 @@ invokevirtual_helper(rbx, rcx, rdx); __ bind(notMethod); @@ -358,10 +344,9 @@ index 0e5ac27..c77a358 100644 __ restore_locals(); // restore r14 __ load_klass(rdx, rcx); diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp -index 376b6f3..e01d3c7 100644 --- a/src/share/vm/c1/c1_Compilation.hpp +++ b/src/share/vm/c1/c1_Compilation.hpp -@@ -239,8 +239,8 @@ class Compilation: public StackObj { +@@ -239,8 +239,8 @@ #define BAILOUT(msg) { bailout(msg); return; } #define BAILOUT_(msg, res) { bailout(msg); return res; } @@ -373,10 +358,9 @@ index 376b6f3..e01d3c7 100644 class InstructionMark: public StackObj { diff --git a/src/share/vm/ci/ciEnv.cpp b/src/share/vm/ci/ciEnv.cpp -index 1366177..b01c003 100644 --- a/src/share/vm/ci/ciEnv.cpp +++ b/src/share/vm/ci/ciEnv.cpp -@@ -1181,3 +1181,11 @@ void ciEnv::record_out_of_memory_failure() { +@@ -1181,3 +1181,11 @@ // If memory is low, we stop compiling methods. record_method_not_compilable("out of memory"); } @@ -389,10 +373,9 @@ index 1366177..b01c003 100644 + } +} diff --git a/src/share/vm/ci/ciEnv.hpp b/src/share/vm/ci/ciEnv.hpp -index d00c9f7..ca6dace 100644 --- a/src/share/vm/ci/ciEnv.hpp +++ b/src/share/vm/ci/ciEnv.hpp -@@ -419,6 +419,8 @@ public: +@@ -419,6 +419,8 @@ void record_failure(const char* reason); void record_method_not_compilable(const char* reason, bool all_tiers = true); void record_out_of_memory_failure(); @@ -402,10 +385,9 @@ index d00c9f7..ca6dace 100644 #endif // SHARE_VM_CI_CIENV_HPP diff --git a/src/share/vm/ci/ciObjectFactory.cpp b/src/share/vm/ci/ciObjectFactory.cpp -index 9aa6b26..fbbd0be 100644 --- a/src/share/vm/ci/ciObjectFactory.cpp +++ b/src/share/vm/ci/ciObjectFactory.cpp -@@ -294,6 +294,11 @@ ciObject* ciObjectFactory::get(oop key) { +@@ -294,6 +294,11 @@ // into the table. We need to recompute our index. index = find(keyHandle(), _ci_objects); } @@ -417,7 +399,7 @@ index 9aa6b26..fbbd0be 100644 assert(!is_found_at(index, keyHandle(), _ci_objects), "no double insert"); insert(index, new_object, _ci_objects); return new_object; -@@ -758,3 +763,50 @@ void ciObjectFactory::print() { +@@ -758,3 +763,50 @@ _unloaded_instances->length(), _unloaded_klasses->length()); } @@ -469,7 +451,6 @@ index 9aa6b26..fbbd0be 100644 + sort_ci_objects(_ci_objects); +} diff --git a/src/share/vm/ci/ciObjectFactory.hpp b/src/share/vm/ci/ciObjectFactory.hpp -index 26cc2c3..855a4ac 100644 --- a/src/share/vm/ci/ciObjectFactory.hpp +++ b/src/share/vm/ci/ciObjectFactory.hpp @@ -38,6 +38,7 @@ @@ -480,7 +461,7 @@ index 26cc2c3..855a4ac 100644 private: static volatile bool _initialized; -@@ -137,6 +138,11 @@ public: +@@ -137,6 +138,11 @@ void print_contents(); void print(); @@ -493,10 +474,9 @@ index 26cc2c3..855a4ac 100644 #endif // SHARE_VM_CI_CIOBJECTFACTORY_HPP diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp -index 83bd038..fc64571 100644 --- a/src/share/vm/classfile/classFileParser.cpp +++ b/src/share/vm/classfile/classFileParser.cpp -@@ -787,6 +787,7 @@ objArrayHandle ClassFileParser::parse_interfaces(constantPoolHandle cp, +@@ -787,6 +787,7 @@ Handle class_loader, Handle protection_domain, Symbol* class_name, @@ -504,7 +484,7 @@ index 83bd038..fc64571 100644 TRAPS) { ClassFileStream* cfs = stream(); assert(length > 0, "only called for length>0"); -@@ -805,6 +806,9 @@ objArrayHandle ClassFileParser::parse_interfaces(constantPoolHandle cp, +@@ -805,6 +806,9 @@ interface_index, CHECK_(nullHandle)); if (cp->tag_at(interface_index).is_klass()) { interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index)); @@ -514,7 +494,7 @@ index 83bd038..fc64571 100644 } else { Symbol* unresolved_klass = cp->klass_name_at(interface_index); -@@ -817,6 +821,9 @@ objArrayHandle ClassFileParser::parse_interfaces(constantPoolHandle cp, +@@ -817,6 +821,9 @@ klassOop k = SystemDictionary::resolve_super_or_fail(class_name, unresolved_klass, class_loader, protection_domain, false, CHECK_(nullHandle)); @@ -524,7 +504,7 @@ index 83bd038..fc64571 100644 interf = KlassHandle(THREAD, k); if (LinkWellKnownClasses) // my super type is well known to me -@@ -1705,6 +1712,8 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf +@@ -1705,6 +1712,8 @@ int runtime_invisible_parameter_annotations_length = 0; u1* annotation_default = NULL; int annotation_default_length = 0; @@ -533,7 +513,7 @@ index 83bd038..fc64571 100644 // Parse code and exceptions attribute u2 method_attributes_count = cfs->get_u2_fast(); -@@ -1874,6 +1883,24 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf +@@ -1874,6 +1883,24 @@ parse_stackmap_table(code_attribute_length, CHECK_(nullHandle)); stackmap_data = typeArrayHandle(THREAD, sm); parsed_stackmap_attribute = true; @@ -558,7 +538,7 @@ index 83bd038..fc64571 100644 } else { // Skip unknown attributes cfs->skip_u1(code_attribute_length, CHECK_(nullHandle)); -@@ -1994,6 +2021,18 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf +@@ -1994,6 +2021,18 @@ } #endif @@ -577,7 +557,7 @@ index 83bd038..fc64571 100644 // Fill in code attribute information m->set_max_stack(max_stack); m->set_max_locals(max_locals); -@@ -2008,6 +2047,8 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf +@@ -2008,6 +2047,8 @@ */ m->set_exception_table(exception_handlers()); @@ -586,7 +566,7 @@ index 83bd038..fc64571 100644 // Copy byte codes m->set_code(code_start); -@@ -2543,6 +2584,24 @@ void ClassFileParser::parse_classfile_attributes(constantPoolHandle cp, instance +@@ -2543,6 +2584,24 @@ "Invalid Deprecated classfile attribute length %u in class file %s", attribute_length, CHECK); } @@ -611,7 +591,7 @@ index 83bd038..fc64571 100644 } else if (_major_version >= JAVA_1_5_VERSION) { if (tag == vmSymbols::tag_signature()) { if (attribute_length != 2) { -@@ -2634,9 +2693,126 @@ typeArrayHandle ClassFileParser::assemble_annotations(u1* runtime_visible_annota +@@ -2634,9 +2693,126 @@ } @@ -738,7 +718,7 @@ index 83bd038..fc64571 100644 KlassHandle host_klass, GrowableArray<Handle>* cp_patches, TempNewSymbol& parsed_name, -@@ -2688,10 +2864,13 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -2688,10 +2864,13 @@ unsigned char* ptr = cfs->buffer(); unsigned char* end_ptr = cfs->buffer() + cfs->length(); @@ -752,7 +732,7 @@ index 83bd038..fc64571 100644 if (ptr != cfs->buffer()) { // JVMTI agent has modified class file data. -@@ -2847,7 +3026,11 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -2847,7 +3026,11 @@ // However, make sure it is not an array type. bool is_array = false; if (cp->tag_at(super_class_index).is_klass()) { @@ -765,7 +745,7 @@ index 83bd038..fc64571 100644 if (_need_verify) is_array = super_klass->oop_is_array(); } else if (_need_verify) { -@@ -2865,7 +3048,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -2865,7 +3048,7 @@ if (itfs_len == 0) { local_interfaces = objArrayHandle(THREAD, Universe::the_empty_system_obj_array()); } else { @@ -774,7 +754,7 @@ index 83bd038..fc64571 100644 } u2 java_fields_count = 0; -@@ -2912,7 +3095,9 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -2912,7 +3095,9 @@ protection_domain, true, CHECK_(nullHandle)); @@ -785,7 +765,7 @@ index 83bd038..fc64571 100644 KlassHandle kh (THREAD, k); super_klass = instanceKlassHandle(THREAD, kh()); if (LinkWellKnownClasses) // my super class is well known to me -@@ -3303,6 +3488,19 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3303,6 +3488,19 @@ rt = REF_NONE; } else { rt = super_klass->reference_type(); @@ -805,7 +785,7 @@ index 83bd038..fc64571 100644 } // We can now create the basic klassOop for this klass -@@ -3402,7 +3600,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3402,7 +3600,7 @@ // Do final class setup fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts); @@ -814,7 +794,7 @@ index 83bd038..fc64571 100644 // reinitialize modifiers, using the InnerClasses attribute int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle)); -@@ -3425,6 +3623,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, +@@ -3425,6 +3623,10 @@ // Allocate mirror and initialize static fields java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle)); @@ -825,7 +805,7 @@ index 83bd038..fc64571 100644 ClassLoadingService::notify_class_loaded(instanceKlass::cast(this_klass()), false /* not shared class */); -@@ -3567,7 +3769,7 @@ void ClassFileParser::fill_oop_maps(instanceKlassHandle k, +@@ -3567,7 +3769,7 @@ } @@ -834,7 +814,7 @@ index 83bd038..fc64571 100644 klassOop super = k->super(); // Check if this klass has an empty finalize method (i.e. one with return bytecode only), -@@ -3575,7 +3777,9 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) { +@@ -3575,7 +3777,9 @@ if (!_has_empty_finalizer) { if (_has_finalizer || (super != NULL && super->klass_part()->has_finalizer())) { @@ -845,7 +825,7 @@ index 83bd038..fc64571 100644 } } -@@ -3591,7 +3795,7 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) { +@@ -3591,7 +3795,7 @@ // Check if this klass supports the java.lang.Cloneable interface if (SystemDictionary::Cloneable_klass_loaded()) { @@ -855,10 +835,9 @@ index 83bd038..fc64571 100644 } } diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp -index fef48eb..65453dd 100644 --- a/src/share/vm/classfile/classFileParser.hpp +++ b/src/share/vm/classfile/classFileParser.hpp -@@ -78,6 +78,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { +@@ -78,6 +78,7 @@ Handle class_loader, Handle protection_domain, Symbol* class_name, @@ -866,7 +845,7 @@ index fef48eb..65453dd 100644 TRAPS); // Field parsing -@@ -151,7 +152,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { +@@ -151,7 +152,7 @@ unsigned int nonstatic_oop_map_count, int* nonstatic_oop_offsets, unsigned int* nonstatic_oop_counts); @@ -875,7 +854,7 @@ index fef48eb..65453dd 100644 objArrayHandle compute_transitive_interfaces(instanceKlassHandle super, objArrayHandle local_ifs, TRAPS); -@@ -263,21 +264,33 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { +@@ -263,21 +264,33 @@ instanceKlassHandle parseClassFile(Symbol* name, Handle class_loader, Handle protection_domain, @@ -911,10 +890,9 @@ index fef48eb..65453dd 100644 static void check_super_class_access(instanceKlassHandle this_klass, TRAPS); static void check_super_interface_access(instanceKlassHandle this_klass, TRAPS); diff --git a/src/share/vm/classfile/classLoader.cpp b/src/share/vm/classfile/classLoader.cpp -index df42dc7..6c22530 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, @@ -923,10 +901,9 @@ index df42dc7..6c22530 100644 false, CHECK_(h)); diff --git a/src/share/vm/classfile/dictionary.cpp b/src/share/vm/classfile/dictionary.cpp -index 4458f46..7b193db 100644 --- a/src/share/vm/classfile/dictionary.cpp +++ b/src/share/vm/classfile/dictionary.cpp -@@ -326,6 +326,21 @@ void Dictionary::classes_do(void f(klassOop)) { +@@ -326,6 +326,21 @@ } } @@ -948,7 +925,7 @@ index 4458f46..7b193db 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 +448,33 @@ void Dictionary::add_klass(Symbol* class_name, Handle class_loader, +@@ -433,6 +448,33 @@ add_entry(index, entry); } @@ -982,7 +959,7 @@ index 4458f46..7b193db 100644 // This routine does not lock the system dictionary. // -@@ -459,12 +501,22 @@ DictionaryEntry* Dictionary::get_entry(int index, unsigned int hash, +@@ -459,12 +501,22 @@ return NULL; } @@ -1006,7 +983,7 @@ index 4458f46..7b193db 100644 } else { return NULL; } -@@ -477,7 +529,7 @@ klassOop Dictionary::find_class(int index, unsigned int hash, +@@ -477,7 +529,7 @@ assert (index == index_for(name, loader), "incorrect index?"); DictionaryEntry* entry = get_entry(index, hash, name, loader); @@ -1015,7 +992,7 @@ index 4458f46..7b193db 100644 } -@@ -489,7 +541,7 @@ klassOop Dictionary::find_shared_class(int index, unsigned int hash, +@@ -489,7 +541,7 @@ assert (index == index_for(name, Handle()), "incorrect index?"); DictionaryEntry* entry = get_entry(index, hash, name, Handle()); @@ -1025,10 +1002,9 @@ index 4458f46..7b193db 100644 diff --git a/src/share/vm/classfile/dictionary.hpp b/src/share/vm/classfile/dictionary.hpp -index 98e0169..305e039 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); @@ -1039,7 +1015,7 @@ index 98e0169..305e039 100644 klassOop find_class(int index, unsigned int hash, Symbol* name, Handle loader); -@@ -89,6 +93,7 @@ public: +@@ -89,6 +93,7 @@ void classes_do(void f(klassOop, TRAPS), TRAPS); void classes_do(void f(klassOop, oop)); void classes_do(void f(klassOop, oop, TRAPS), TRAPS); @@ -1047,7 +1023,7 @@ index 98e0169..305e039 100644 void methods_do(void f(methodOop)); -@@ -105,6 +110,7 @@ public: +@@ -105,6 +110,7 @@ bool do_unloading(BoolObjectClosure* is_alive); // Protection domains @@ -1056,10 +1032,9 @@ index 98e0169..305e039 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 0c452cf..94f3d3e 100644 --- a/src/share/vm/classfile/javaClasses.cpp +++ b/src/share/vm/classfile/javaClasses.cpp -@@ -1783,7 +1783,7 @@ Handle java_lang_reflect_Method::create(TRAPS) { +@@ -1783,7 +1783,7 @@ klassOop klass = SystemDictionary::reflect_Method_klass(); // This class is eagerly initialized during VM initialization, since we keep a refence // to one of the methods @@ -1069,10 +1044,9 @@ index 0c452cf..94f3d3e 100644 } diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp -index 9ada298..ba5a60e 100644 --- a/src/share/vm/classfile/javaClasses.hpp +++ b/src/share/vm/classfile/javaClasses.hpp -@@ -213,7 +213,6 @@ class java_lang_String : AllStatic { +@@ -213,7 +213,6 @@ class java_lang_Class : AllStatic { friend class VMStructs; @@ -1081,10 +1055,9 @@ index 9ada298..ba5a60e 100644 // The fake offsets are added by the class loader when java.lang.Class is loaded diff --git a/src/share/vm/classfile/loaderConstraints.cpp b/src/share/vm/classfile/loaderConstraints.cpp -index 5e25e4c..c887547 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. @@ -1094,10 +1067,9 @@ index 5e25e4c..c887547 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/loaderConstraints.hpp b/src/share/vm/classfile/loaderConstraints.hpp -index 60612f5..77f955f 100644 --- a/src/share/vm/classfile/loaderConstraints.hpp +++ b/src/share/vm/classfile/loaderConstraints.hpp -@@ -106,7 +106,7 @@ public: +@@ -106,7 +106,7 @@ klassOop klass() { return literal(); } klassOop* klass_addr() { return literal_addr(); } @@ -1107,10 +1079,9 @@ index 60612f5..77f955f 100644 LoaderConstraintEntry* next() { return (LoaderConstraintEntry*)HashtableEntry<klassOop>::next(); diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfile/systemDictionary.cpp -index 0bdc16d..0f5ede5 100644 --- a/src/share/vm/classfile/systemDictionary.cpp +++ b/src/share/vm/classfile/systemDictionary.cpp -@@ -151,6 +151,7 @@ klassOop SystemDictionary::resolve_or_fail(Symbol* class_name, Handle class_load +@@ -151,6 +151,7 @@ // can return a null klass klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD); } @@ -1118,7 +1089,7 @@ index 0bdc16d..0f5ede5 100644 return klass; } -@@ -193,7 +194,8 @@ klassOop SystemDictionary::resolve_or_fail(Symbol* class_name, +@@ -193,7 +194,8 @@ // Forwards to resolve_instance_class_or_null klassOop SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { @@ -1128,7 +1099,7 @@ index 0bdc16d..0f5ede5 100644 if (FieldType::is_array(class_name)) { return resolve_array_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL); } else if (FieldType::is_obj(class_name)) { -@@ -997,6 +999,7 @@ klassOop SystemDictionary::parse_stream(Symbol* class_name, +@@ -997,6 +999,7 @@ instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, class_loader, protection_domain, @@ -1136,7 +1107,7 @@ index 0bdc16d..0f5ede5 100644 host_klass, cp_patches, parsed_name, -@@ -1056,8 +1059,15 @@ klassOop SystemDictionary::resolve_from_stream(Symbol* class_name, +@@ -1056,8 +1059,15 @@ Handle protection_domain, ClassFileStream* st, bool verify, @@ -1152,7 +1123,7 @@ index 0bdc16d..0f5ede5 100644 // Classloaders that support parallelism, e.g. bootstrap classloader, // or all classloaders with UnsyncloadClass do not acquire lock here bool DoObjectLock = true; -@@ -1085,9 +1095,14 @@ klassOop SystemDictionary::resolve_from_stream(Symbol* class_name, +@@ -1085,9 +1095,14 @@ instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, class_loader, protection_domain, @@ -1167,7 +1138,7 @@ index 0bdc16d..0f5ede5 100644 const char* pkg = "java/"; if (!HAS_PENDING_EXCEPTION && -@@ -1122,13 +1137,18 @@ klassOop SystemDictionary::resolve_from_stream(Symbol* class_name, +@@ -1122,13 +1137,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 @@ -1188,7 +1159,7 @@ index 0bdc16d..0f5ede5 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 -@@ -1157,7 +1177,7 @@ klassOop SystemDictionary::resolve_from_stream(Symbol* class_name, +@@ -1157,7 +1177,7 @@ MutexLocker mu(SystemDictionary_lock, THREAD); klassOop check = find_class(parsed_name, class_loader); @@ -1197,7 +1168,7 @@ index 0bdc16d..0f5ede5 100644 klassOop check2 = find_class(h_name, h_loader); assert(check == check2, "name inconsistancy in SystemDictionary"); -@@ -1453,7 +1473,11 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha +@@ -1453,7 +1473,11 @@ } } @@ -1210,7 +1181,7 @@ index 0bdc16d..0f5ede5 100644 Handle class_loader_h(THREAD, k->class_loader()); -@@ -1480,13 +1504,23 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { +@@ -1480,13 +1504,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); @@ -1236,7 +1207,7 @@ index 0bdc16d..0f5ede5 100644 methodHandle m(THREAD, Universe::loader_addClass_method()); JavaValue result(T_VOID); JavaCallArguments args(class_loader_h); -@@ -1512,8 +1546,9 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { +@@ -1512,8 +1546,9 @@ } k->eager_initialize(THREAD); @@ -1247,7 +1218,7 @@ index 0bdc16d..0f5ede5 100644 assert(THREAD->is_Java_thread(), "thread->is_Java_thread()"); JvmtiExport::post_class_load((JavaThread *) THREAD, k()); -@@ -1586,7 +1621,7 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(Symbol* clas +@@ -1586,7 +1621,7 @@ } } @@ -1256,7 +1227,7 @@ index 0bdc16d..0f5ede5 100644 Handle linkage_exception = Handle(); // null handle -@@ -1716,6 +1751,14 @@ void SystemDictionary::add_to_hierarchy(instanceKlassHandle k, TRAPS) { +@@ -1716,6 +1751,14 @@ Universe::flush_dependents_on(k); } @@ -1271,12 +1242,24 @@ index 0bdc16d..0f5ede5 100644 // ---------------------------------------------------------------------------- // GC support -@@ -1804,6 +1847,24 @@ void SystemDictionary::oops_do(OopClosure* f) { +@@ -1804,7 +1847,8 @@ } +-void SystemDictionary::preloaded_oops_do(OopClosure* f) { +// (tw) Iterate over all pre-loaded classes in the dictionary. +void SystemDictionary::preloaded_classes_do(OopClosure *f) { + for (int k = (int)FIRST_WKID; k < (int)WKID_LIMIT; k++) { + f->do_oop((oop*) &_well_known_klasses[k]); + } +@@ -1818,6 +1862,23 @@ + } + } + ++ // TODO: Check if we need to call FilterFieldsMap ++} ++ ++void SystemDictionary::preloaded_oops_do(OopClosure* f) { + for (int k = (int)FIRST_WKID; k < (int)WKID_LIMIT; k++) { + f->do_oop((oop*) &_well_known_klasses[k]); + } @@ -1290,13 +1273,10 @@ index 0bdc16d..0f5ede5 100644 + } + } + -+ // TODO: Check if we need to call FilterFieldsMap -+} -+ - void SystemDictionary::preloaded_oops_do(OopClosure* f) { - for (int k = (int)FIRST_WKID; k < (int)WKID_LIMIT; k++) { - f->do_oop((oop*) &_well_known_klasses[k]); -@@ -1836,6 +1897,11 @@ void SystemDictionary::classes_do(void f(klassOop)) { + // The basic type mirrors would have already been processed in + // Universe::oops_do(), via a call to shared_oops_do(), so should + // not be processed again. +@@ -1836,6 +1897,11 @@ dictionary()->classes_do(f); } @@ -1308,7 +1288,7 @@ index 0bdc16d..0f5ede5 100644 // Added for initialize_itable_for_klass // Just the classes from defining class loaders // Don't iterate over placeholders -@@ -1989,7 +2055,9 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { +@@ -1989,7 +2055,9 @@ // Preload ref klasses and set reference types instanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER); @@ -1319,7 +1299,7 @@ index 0bdc16d..0f5ede5 100644 initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK); instanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT); -@@ -2081,7 +2149,11 @@ void SystemDictionary::check_constraints(int d_index, unsigned int d_hash, +@@ -2081,7 +2149,11 @@ // also holds array classes assert(check->klass_part()->oop_is_instance(), "noninstance in systemdictionary"); @@ -1333,10 +1313,9 @@ index 0bdc16d..0f5ede5 100644 "definition for name: \"%s\""; } else { diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp -index 3abc505..db32aad 100644 --- a/src/share/vm/classfile/systemDictionary.hpp +++ b/src/share/vm/classfile/systemDictionary.hpp -@@ -276,7 +276,7 @@ public: +@@ -276,7 +276,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, @@ -1345,7 +1324,7 @@ index 3abc505..db32aad 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); -@@ -320,6 +320,8 @@ public: +@@ -320,6 +320,8 @@ // Iterate over all klasses in dictionary // Just the classes from defining class loaders static void classes_do(void f(klassOop)); @@ -1354,7 +1333,7 @@ index 3abc505..db32aad 100644 // Added for initialize_itable_for_klass to handle exceptions static void classes_do(void f(klassOop, TRAPS), TRAPS); // All classes, and their class loaders -@@ -427,6 +429,8 @@ public: +@@ -427,6 +429,8 @@ initialize_wk_klasses_until((WKID) limit, start_id, THREAD); } @@ -1363,7 +1342,7 @@ index 3abc505..db32aad 100644 public: #define WK_KLASS_DECLARE(name, symbol, option) \ static klassOop name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); } -@@ -608,7 +612,7 @@ private: +@@ -608,7 +612,7 @@ // after waiting, but before reentering SystemDictionary_lock // to preserve lock order semantics. static void double_lock_wait(Handle lockObject, TRAPS); @@ -1372,7 +1351,7 @@ index 3abc505..db32aad 100644 static instanceKlassHandle find_or_define_instance_class(Symbol* class_name, Handle class_loader, instanceKlassHandle k, TRAPS); -@@ -627,6 +631,11 @@ private: +@@ -627,6 +631,11 @@ // Setup link to hierarchy static void add_to_hierarchy(instanceKlassHandle k, TRAPS); @@ -1385,10 +1364,9 @@ index 3abc505..db32aad 100644 // We pass in the hashtable index so we can calculate it outside of // the SystemDictionary_lock. diff --git a/src/share/vm/classfile/verifier.cpp b/src/share/vm/classfile/verifier.cpp -index 905456a..fe6b80d 100644 --- a/src/share/vm/classfile/verifier.cpp +++ b/src/share/vm/classfile/verifier.cpp -@@ -103,7 +103,7 @@ bool Verifier::relax_verify_for(oop loader) { +@@ -103,7 +103,7 @@ return !need_verify; } @@ -1397,7 +1375,7 @@ index 905456a..fe6b80d 100644 HandleMark hm; ResourceMark rm(THREAD); -@@ -127,17 +127,19 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul +@@ -127,17 +127,19 @@ split_verifier.verify_class(THREAD); exception_name = split_verifier.result(); if (klass->major_version() < NOFAILOVER_MAJOR_VERSION && @@ -1418,7 +1396,7 @@ index 905456a..fe6b80d 100644 exception_name = inference_verify( klass, message_buffer, message_buffer_len, THREAD); } -@@ -152,6 +154,9 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul +@@ -152,6 +154,9 @@ } tty->print_cr("End class verification for: %s", klassName); } @@ -1428,7 +1406,7 @@ index 905456a..fe6b80d 100644 } if (HAS_PENDING_EXCEPTION) { -@@ -203,7 +208,7 @@ bool Verifier::is_eligible_for_verification(instanceKlassHandle klass, bool shou +@@ -203,7 +208,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 || @@ -1437,7 +1415,7 @@ index 905456a..fe6b80d 100644 VerifyReflectionBytecodes) ); } -@@ -272,7 +277,7 @@ bool ClassVerifier::_verify_verbose = false; +@@ -272,7 +277,7 @@ ClassVerifier::ClassVerifier( instanceKlassHandle klass, char* msg, size_t msg_len, TRAPS) : _thread(THREAD), _exception_type(NULL), _message(msg), @@ -1446,7 +1424,7 @@ index 905456a..fe6b80d 100644 _this_type = VerificationType::reference_type(klass->name()); // Create list to hold symbols in reference area. _symbols = new GrowableArray<Symbol*>(100, 0, NULL); -@@ -296,7 +301,7 @@ void ClassVerifier::verify_class(TRAPS) { +@@ -296,7 +301,7 @@ _klass->external_name()); } @@ -1455,7 +1433,7 @@ index 905456a..fe6b80d 100644 int num_methods = methods->length(); for (int index = 0; index < num_methods; index++) { -@@ -2081,7 +2086,10 @@ void ClassVerifier::verify_invoke_instructions( +@@ -2081,7 +2086,10 @@ VerificationType stack_object_type = current_frame->pop_stack(ref_class_type, CHECK_VERIFY(this)); if (current_type() != stack_object_type) { @@ -1468,10 +1446,9 @@ index 905456a..fe6b80d 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 6686858..d16ae52 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. */ @@ -1480,7 +1457,7 @@ index 6686858..d16ae52 100644 // Return false if the class is loaded by the bootstrap loader, // or if defineClass was called requesting skipping verification -@@ -97,7 +97,10 @@ class ClassVerifier : public StackObj { +@@ -97,7 +97,10 @@ size_t _message_buffer_len; GrowableArray<Symbol*>* _symbols; // keep a list of symbols created @@ -1491,7 +1468,7 @@ index 6686858..d16ae52 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); void verify_local_variable_table(u4 code_length, char* code_data, TRAPS); -@@ -168,6 +171,7 @@ class ClassVerifier : public StackObj { +@@ -168,6 +171,7 @@ VerificationType object_type() const; @@ -1500,7 +1477,6 @@ index 6686858..d16ae52 100644 methodHandle _method; // current method being verified VerificationType _this_type; // the verification type of the current class diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp -index d6beb93..53dab58 100644 --- a/src/share/vm/classfile/vmSymbols.hpp +++ b/src/share/vm/classfile/vmSymbols.hpp @@ -131,6 +131,10 @@ @@ -1526,10 +1502,9 @@ index d6beb93..53dab58 100644 template(register_method_name, "register") \ do_alias(register_method_signature, object_void_signature) \ diff --git a/src/share/vm/compiler/compileBroker.cpp b/src/share/vm/compiler/compileBroker.cpp -index 8729e05..162a44e 100644 --- a/src/share/vm/compiler/compileBroker.cpp +++ b/src/share/vm/compiler/compileBroker.cpp -@@ -1166,6 +1166,14 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, +@@ -1166,6 +1166,14 @@ int comp_level, methodHandle hot_method, int hot_count, const char* comment, Thread* THREAD) { @@ -1544,7 +1519,7 @@ index 8729e05..162a44e 100644 // make sure arguments make sense assert(method->method_holder()->klass_part()->oop_is_instance(), "not an instance method"); assert(osr_bci == InvocationEntryBci || (0 <= osr_bci && osr_bci < method->code_size()), "bci out of range"); -@@ -1245,6 +1253,7 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, +@@ -1245,6 +1253,7 @@ } // RedefineClasses() has replaced this method; just return @@ -1552,7 +1527,7 @@ index 8729e05..162a44e 100644 if (method->is_old()) { return NULL; } -@@ -1576,6 +1585,8 @@ void CompileBroker::compiler_thread_loop() { +@@ -1576,6 +1585,8 @@ // Never compile a method if breakpoints are present in it if (method()->number_of_breakpoints() == 0) { @@ -1561,7 +1536,7 @@ index 8729e05..162a44e 100644 // Compile the method. if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) { #ifdef COMPILER1 -@@ -1599,6 +1610,7 @@ void CompileBroker::compiler_thread_loop() { +@@ -1599,6 +1610,7 @@ // After compilation is disabled, remove remaining methods from queue method->clear_queued_for_compilation(); } @@ -1569,7 +1544,7 @@ index 8729e05..162a44e 100644 } } } -@@ -2127,3 +2139,15 @@ void CompileBroker::print_compiler_threads_on(outputStream* st) { +@@ -2127,3 +2139,15 @@ st->cr(); #endif } @@ -1586,10 +1561,9 @@ index 8729e05..162a44e 100644 + } +} diff --git a/src/share/vm/compiler/compileBroker.hpp b/src/share/vm/compiler/compileBroker.hpp -index 1ee2c54..2a20852 100644 --- a/src/share/vm/compiler/compileBroker.hpp +++ b/src/share/vm/compiler/compileBroker.hpp -@@ -407,6 +407,8 @@ class CompileBroker: AllStatic { +@@ -407,6 +407,8 @@ static void print_last_compile(); static void print_compiler_threads_on(outputStream* st); @@ -1599,10 +1573,9 @@ index 1ee2c54..2a20852 100644 #endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp -index 2cb5e2f..74af5d1 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp -@@ -157,6 +157,13 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, +@@ -157,6 +157,13 @@ } } @@ -1617,10 +1590,9 @@ index 2cb5e2f..74af5d1 100644 // update the block offset table. Removed initialize_threshold call because // CFLS does not use a block offset array for contiguous spaces. diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp -index 90d2f5f..14daefa 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); @@ -1629,7 +1601,6 @@ index 90d2f5f..14daefa 100644 // Initialization helpers. diff --git a/src/share/vm/gc_implementation/shared/markSweep.cpp b/src/share/vm/gc_implementation/shared/markSweep.cpp -index 584c24c..121d9f1 100644 --- a/src/share/vm/gc_implementation/shared/markSweep.cpp +++ b/src/share/vm/gc_implementation/shared/markSweep.cpp @@ -30,6 +30,8 @@ @@ -1641,7 +1612,7 @@ index 584c24c..121d9f1 100644 Stack<oop> MarkSweep::_marking_stack; Stack<DataLayout*> MarkSweep::_revisit_mdo_stack; Stack<Klass*> MarkSweep::_revisit_klass_stack; -@@ -350,3 +352,86 @@ void MarkSweep::trace(const char* msg) { +@@ -350,3 +352,86 @@ } #endif @@ -1729,10 +1700,9 @@ index 584c24c..121d9f1 100644 + } +} diff --git a/src/share/vm/gc_implementation/shared/markSweep.hpp b/src/share/vm/gc_implementation/shared/markSweep.hpp -index 19bee0e..850dd42 100644 --- a/src/share/vm/gc_implementation/shared/markSweep.hpp +++ b/src/share/vm/gc_implementation/shared/markSweep.hpp -@@ -115,8 +115,12 @@ class MarkSweep : AllStatic { +@@ -115,8 +115,12 @@ friend class AdjustPointerClosure; friend class KeepAliveClosure; friend class VM_MarkSweep; @@ -1745,7 +1715,7 @@ index 19bee0e..850dd42 100644 // // Vars // -@@ -200,6 +204,8 @@ class MarkSweep : AllStatic { +@@ -200,6 +204,8 @@ template <class T> static inline void mark_and_push(T* p); static inline void push_objarray(oop obj, size_t index); @@ -1755,10 +1725,9 @@ index 19bee0e..850dd42 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 6f5511f..e01eafd 100644 --- a/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/src/share/vm/interpreter/interpreterRuntime.cpp -@@ -403,7 +403,7 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea +@@ -403,7 +403,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 @@ -1767,7 +1736,7 @@ index 6f5511f..e01eafd 100644 if (ExitVMOnVerifyError) vm_exit(-1); ShouldNotReachHere(); } -@@ -674,6 +674,82 @@ IRT_ENTRY(void, InterpreterRuntime::_breakpoint(JavaThread* thread, methodOopDes +@@ -674,6 +674,82 @@ JvmtiExport::post_raw_breakpoint(thread, method, bcp); IRT_END @@ -1850,7 +1819,7 @@ index 6f5511f..e01eafd 100644 IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode)) // extract receiver from the outgoing argument list if necessary Handle receiver(thread, NULL); -@@ -702,6 +778,10 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes +@@ -702,6 +778,10 @@ if (JvmtiExport::can_hotswap_or_post_breakpoint()) { int retry_count = 0; while (info.resolved_method()->is_old()) { @@ -1862,10 +1831,9 @@ index 6f5511f..e01eafd 100644 // in the middle of resolve. If it is looping here more than 100 times // means then there could be a bug here. diff --git a/src/share/vm/interpreter/interpreterRuntime.hpp b/src/share/vm/interpreter/interpreterRuntime.hpp -index 93c1a9e..daf4813 100644 --- a/src/share/vm/interpreter/interpreterRuntime.hpp +++ b/src/share/vm/interpreter/interpreterRuntime.hpp -@@ -137,6 +137,9 @@ class InterpreterRuntime: AllStatic { +@@ -137,6 +137,9 @@ static void post_method_entry(JavaThread *thread); static void post_method_exit (JavaThread *thread); static int interpreter_contains(address pc); @@ -1876,10 +1844,9 @@ index 93c1a9e..daf4813 100644 // Native signature handlers static void prepare_native_call(JavaThread* thread, methodOopDesc* method); diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp -index b7defd7..ea6843f 100644 --- a/src/share/vm/interpreter/linkResolver.cpp +++ b/src/share/vm/interpreter/linkResolver.cpp -@@ -145,8 +145,8 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass +@@ -145,8 +145,8 @@ // Klass resolution void LinkResolver::check_klass_accessability(KlassHandle ref_klass, KlassHandle sel_klass, TRAPS) { @@ -1890,7 +1857,7 @@ index b7defd7..ea6843f 100644 true)) { ResourceMark rm(THREAD); Exceptions::fthrow( -@@ -258,7 +258,7 @@ void LinkResolver::check_method_accessability(KlassHandle ref_klass, +@@ -258,7 +258,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() && @@ -1899,7 +1866,7 @@ index b7defd7..ea6843f 100644 resolved_klass->oop_is_array()) { // We need to change "protected" to "public". assert(flags.is_protected(), "clone not protected?"); -@@ -334,6 +334,149 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method, Klass +@@ -334,6 +334,149 @@ } @@ -2049,7 +2016,7 @@ index b7defd7..ea6843f 100644 void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) { -@@ -346,27 +489,8 @@ void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle res +@@ -346,27 +489,8 @@ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } @@ -2079,7 +2046,7 @@ index b7defd7..ea6843f 100644 // 5. check if method is concrete if (resolved_method->is_abstract() && !resolved_klass->is_abstract()) { -@@ -434,20 +558,7 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method, +@@ -434,20 +558,7 @@ } // lookup method in this interface or its super, java.lang.Object @@ -2101,7 +2068,7 @@ index b7defd7..ea6843f 100644 if (check_access) { HandleMark hm(THREAD); -@@ -534,9 +645,14 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo +@@ -534,9 +645,14 @@ THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string()); } @@ -2117,7 +2084,7 @@ index b7defd7..ea6843f 100644 // check if field exists; i.e., if a klass containing the field def has been selected if (sel_klass.is_null()){ ResourceMark rm(THREAD); -@@ -544,7 +660,6 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo +@@ -544,7 +660,6 @@ } // check access @@ -2125,7 +2092,7 @@ index b7defd7..ea6843f 100644 check_field_accessability(ref_klass, resolved_klass, sel_klass, fd, CHECK); // check for errors -@@ -556,7 +671,7 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo +@@ -556,7 +671,7 @@ } // Final fields can only be accessed from its own class. @@ -2134,7 +2101,7 @@ index b7defd7..ea6843f 100644 THROW(vmSymbols::java_lang_IllegalAccessError()); } -@@ -761,7 +876,7 @@ void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, KlassHand +@@ -761,7 +876,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); @@ -2143,7 +2110,7 @@ index b7defd7..ea6843f 100644 } // throws linktime exceptions -@@ -791,6 +906,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, +@@ -791,6 +906,7 @@ KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, @@ -2151,7 +2118,7 @@ index b7defd7..ea6843f 100644 bool check_null_and_abstract, TRAPS) { -@@ -839,7 +955,40 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, +@@ -839,7 +955,40 @@ // 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(); @@ -2193,10 +2160,9 @@ index b7defd7..ea6843f 100644 } diff --git a/src/share/vm/interpreter/linkResolver.hpp b/src/share/vm/interpreter/linkResolver.hpp -index 3d4c6f4..501f1e4 100644 --- a/src/share/vm/interpreter/linkResolver.hpp +++ b/src/share/vm/interpreter/linkResolver.hpp -@@ -106,7 +106,11 @@ class CallInfo: public LinkInfo { +@@ -106,7 +106,11 @@ // It does all necessary link-time checks & throws exceptions if necessary. class LinkResolver: AllStatic { @@ -2209,7 +2175,7 @@ index 3d4c6f4..501f1e4 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); -@@ -129,7 +133,7 @@ class LinkResolver: AllStatic { +@@ -129,7 +133,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); @@ -2219,10 +2185,9 @@ index 3d4c6f4..501f1e4 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/templateTable.hpp b/src/share/vm/interpreter/templateTable.hpp -index 3b006ad..b27ec97 100644 --- a/src/share/vm/interpreter/templateTable.hpp +++ b/src/share/vm/interpreter/templateTable.hpp -@@ -328,8 +328,8 @@ class TemplateTable: AllStatic { +@@ -328,8 +328,8 @@ static void shouldnotreachhere(); // jvmti support @@ -2234,10 +2199,9 @@ index 3b006ad..b27ec97 100644 // debugging of TemplateGenerator diff --git a/src/share/vm/memory/genMarkSweep.cpp b/src/share/vm/memory/genMarkSweep.cpp -index d5cf4dc..ec88a6c 100644 --- a/src/share/vm/memory/genMarkSweep.cpp +++ b/src/share/vm/memory/genMarkSweep.cpp -@@ -409,6 +409,7 @@ void GenMarkSweep::mark_sweep_phase4() { +@@ -409,6 +409,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. @@ -2245,7 +2209,7 @@ index d5cf4dc..ec88a6c 100644 GenCollectedHeap* gch = GenCollectedHeap::heap(); Generation* pg = gch->perm_gen(); -@@ -421,10 +422,14 @@ void GenMarkSweep::mark_sweep_phase4() { +@@ -421,10 +422,14 @@ VALIDATE_MARK_SWEEP_ONLY(reset_live_oop_tracking(false)); @@ -2261,10 +2225,9 @@ index d5cf4dc..ec88a6c 100644 pg->post_compact(); // Shared spaces verification. } diff --git a/src/share/vm/memory/permGen.cpp b/src/share/vm/memory/permGen.cpp -index 350f583..59faad1 100644 --- a/src/share/vm/memory/permGen.cpp +++ b/src/share/vm/memory/permGen.cpp -@@ -57,7 +57,12 @@ HeapWord* PermGen::mem_allocate_in_gen(size_t size, Generation* gen) { +@@ -57,7 +57,12 @@ for (;;) { { @@ -2279,10 +2242,9 @@ index 350f583..59faad1 100644 return obj; } diff --git a/src/share/vm/memory/space.cpp b/src/share/vm/memory/space.cpp -index 7f3aceb..bb84a5a 100644 --- a/src/share/vm/memory/space.cpp +++ b/src/share/vm/memory/space.cpp -@@ -378,6 +378,31 @@ void CompactibleSpace::clear(bool mangle_space) { +@@ -378,6 +378,31 @@ _compaction_top = bottom(); } @@ -2314,7 +2276,7 @@ index 7f3aceb..bb84a5a 100644 HeapWord* CompactibleSpace::forward(oop q, size_t size, CompactPoint* cp, HeapWord* compact_top) { // q is alive -@@ -401,7 +426,7 @@ HeapWord* CompactibleSpace::forward(oop q, size_t size, +@@ -401,7 +426,7 @@ } // store the forwarding pointer into the mark word @@ -2323,7 +2285,7 @@ index 7f3aceb..bb84a5a 100644 q->forward_to(oop(compact_top)); assert(q->is_gc_marked(), "encoding the pointer should preserve the mark"); } else { -@@ -449,7 +474,208 @@ void CompactibleSpace::prepare_for_compaction(CompactPoint* cp) { +@@ -449,7 +474,208 @@ // Faster object search. void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) { @@ -2533,7 +2495,7 @@ index 7f3aceb..bb84a5a 100644 } void Space::adjust_pointers() { -@@ -490,17 +716,313 @@ void Space::adjust_pointers() { +@@ -490,17 +716,313 @@ assert(q == t, "just checking"); } @@ -2655,11 +2617,10 @@ index 7f3aceb..bb84a5a 100644 if (used() == 0) { return; // Nothing to do. } -- -- SCAN_AND_ADJUST_POINTERS(adjust_obj_size); + /* adjust all the interior pointers to point at the new locations of objects + * Used by MarkSweep::mark_sweep_phase3() */ -+ + +- SCAN_AND_ADJUST_POINTERS(adjust_obj_size); + HeapWord* q = bottom(); + HeapWord* t = _end_of_live; /* Established by "prepare_for_compaction". */ + @@ -2851,10 +2812,9 @@ index 7f3aceb..bb84a5a 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 2d718c2..3f1d74b 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 @@ -2864,7 +2824,7 @@ index 2d718c2..3f1d74b 100644 virtual void adjust_pointers(); // MarkSweep support phase4 virtual void compact(); -@@ -475,6 +478,10 @@ public: +@@ -475,6 +478,10 @@ virtual HeapWord* forward(oop q, size_t size, CompactPoint* cp, HeapWord* compact_top); @@ -2876,7 +2836,6 @@ index 2d718c2..3f1d74b 100644 virtual size_t adjust_object_size_v(size_t size) const { return size; } diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp -index 2651f4d..90d244c 100644 --- a/src/share/vm/memory/universe.cpp +++ b/src/share/vm/memory/universe.cpp @@ -100,6 +100,8 @@ @@ -2888,7 +2847,7 @@ index 2651f4d..90d244c 100644 // Known objects klassOop Universe::_boolArrayKlassObj = NULL; klassOop Universe::_byteArrayKlassObj = NULL; -@@ -203,6 +205,38 @@ void Universe::system_classes_do(void f(klassOop)) { +@@ -203,6 +205,38 @@ f(systemObjArrayKlassObj()); } @@ -2928,10 +2887,9 @@ index 2651f4d..90d244c 100644 f->do_oop((oop*) &_int_mirror); diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp -index e8ebf8f..535c8ca 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; @@ -2940,7 +2898,7 @@ index e8ebf8f..535c8ca 100644 friend class VM_PopulateDumpSharedSpace; friend jint universe_init(); -@@ -257,7 +259,18 @@ class Universe: AllStatic { +@@ -257,7 +259,18 @@ static void compute_verify_oop_data(); @@ -2959,7 +2917,7 @@ index e8ebf8f..535c8ca 100644 // Known classes in the VM static klassOop boolArrayKlassObj() { return _boolArrayKlassObj; } static klassOop byteArrayKlassObj() { return _byteArrayKlassObj; } -@@ -396,6 +409,8 @@ class Universe: AllStatic { +@@ -396,6 +409,8 @@ // Iteration @@ -2968,7 +2926,7 @@ index e8ebf8f..535c8ca 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); -@@ -412,6 +427,7 @@ class Universe: AllStatic { +@@ -412,6 +427,7 @@ // Debugging static bool verify_in_progress() { return _verify_in_progress; } @@ -2977,10 +2935,9 @@ index e8ebf8f..535c8ca 100644 VerifyOption option = VerifyOption_Default ); static int verify_count() { return _verify_count; } diff --git a/src/share/vm/oops/arrayKlass.cpp b/src/share/vm/oops/arrayKlass.cpp -index 4aa1155..2738ea9 100644 --- a/src/share/vm/oops/arrayKlass.cpp +++ b/src/share/vm/oops/arrayKlass.cpp -@@ -129,9 +129,9 @@ objArrayOop arrayKlass::compute_secondary_supers(int num_extra_slots, TRAPS) { +@@ -129,9 +129,9 @@ bool arrayKlass::compute_is_subtype_of(klassOop k) { // An array is a subtype of Serializable, Clonable, and Object @@ -2994,10 +2951,9 @@ index 4aa1155..2738ea9 100644 diff --git a/src/share/vm/oops/constMethodKlass.cpp b/src/share/vm/oops/constMethodKlass.cpp -index 509b411..53d1858 100644 --- a/src/share/vm/oops/constMethodKlass.cpp +++ b/src/share/vm/oops/constMethodKlass.cpp -@@ -101,6 +101,7 @@ void constMethodKlass::oop_follow_contents(oop obj) { +@@ -101,6 +101,7 @@ MarkSweep::mark_and_push(cm->adr_method()); MarkSweep::mark_and_push(cm->adr_stackmap_data()); MarkSweep::mark_and_push(cm->adr_exception_table()); @@ -3005,7 +2961,7 @@ index 509b411..53d1858 100644 // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::constMethodKlassObj never moves. } -@@ -113,6 +114,7 @@ void constMethodKlass::oop_follow_contents(ParCompactionManager* cm, +@@ -113,6 +114,7 @@ PSParallelCompact::mark_and_push(cm, cm_oop->adr_method()); PSParallelCompact::mark_and_push(cm, cm_oop->adr_stackmap_data()); PSParallelCompact::mark_and_push(cm, cm_oop->adr_exception_table()); @@ -3013,7 +2969,7 @@ index 509b411..53d1858 100644 // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::constMethodKlassObj never moves. } -@@ -124,6 +126,7 @@ int constMethodKlass::oop_oop_iterate(oop obj, OopClosure* blk) { +@@ -124,6 +126,7 @@ blk->do_oop(cm->adr_method()); blk->do_oop(cm->adr_stackmap_data()); blk->do_oop(cm->adr_exception_table()); @@ -3021,7 +2977,7 @@ index 509b411..53d1858 100644 // Get size before changing pointers. // Don't call size() or oop_size() since that is a virtual call. int size = cm->object_size(); -@@ -141,6 +144,8 @@ int constMethodKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) +@@ -141,6 +144,8 @@ if (mr.contains(adr)) blk->do_oop(adr); adr = cm->adr_exception_table(); if (mr.contains(adr)) blk->do_oop(adr); @@ -3030,7 +2986,7 @@ index 509b411..53d1858 100644 // Get size before changing pointers. // Don't call size() or oop_size() since that is a virtual call. int size = cm->object_size(); -@@ -156,6 +161,7 @@ int constMethodKlass::oop_adjust_pointers(oop obj) { +@@ -156,6 +161,7 @@ MarkSweep::adjust_pointer(cm->adr_method()); MarkSweep::adjust_pointer(cm->adr_stackmap_data()); MarkSweep::adjust_pointer(cm->adr_exception_table()); @@ -3039,10 +2995,9 @@ index 509b411..53d1858 100644 // Don't call size() or oop_size() since that is a virtual call. int size = cm->object_size(); diff --git a/src/share/vm/oops/constMethodOop.hpp b/src/share/vm/oops/constMethodOop.hpp -index 91f9786..6c6acc9 100644 --- a/src/share/vm/oops/constMethodOop.hpp +++ b/src/share/vm/oops/constMethodOop.hpp -@@ -114,7 +114,7 @@ private: +@@ -114,7 +114,7 @@ public: oop* oop_block_beg() const { return adr_method(); } @@ -3051,7 +3006,7 @@ index 91f9786..6c6acc9 100644 private: // -@@ -132,6 +132,10 @@ private: +@@ -132,6 +132,10 @@ // table is pointing to Universe::the_empty_int_array typeArrayOop _exception_table; @@ -3062,7 +3017,7 @@ index 91f9786..6c6acc9 100644 // // End of the oop block. // -@@ -184,6 +188,28 @@ public: +@@ -184,6 +188,28 @@ void set_exception_table(typeArrayOop e) { oop_store_without_check((oop*) &_exception_table, (oop) e); } bool has_exception_handler() const { return exception_table() != NULL && exception_table()->length() > 0; } @@ -3091,7 +3046,7 @@ index 91f9786..6c6acc9 100644 void init_fingerprint() { const uint64_t initval = CONST64(0x8000000000000000); _fingerprint = initval; -@@ -285,6 +311,7 @@ public: +@@ -285,6 +311,7 @@ oop* adr_method() const { return (oop*)&_method; } oop* adr_stackmap_data() const { return (oop*)&_stackmap_data; } oop* adr_exception_table() const { return (oop*)&_exception_table; } @@ -3100,7 +3055,6 @@ index 91f9786..6c6acc9 100644 void set_is_conc_safe(bool v) { _is_conc_safe = v; } diff --git a/src/share/vm/oops/cpCacheOop.cpp b/src/share/vm/oops/cpCacheOop.cpp -index 678bc13..d34f7c3 100644 --- a/src/share/vm/oops/cpCacheOop.cpp +++ b/src/share/vm/oops/cpCacheOop.cpp @@ -36,9 +36,15 @@ @@ -3119,7 +3073,7 @@ index 678bc13..d34f7c3 100644 assert(constant_pool_index() == index, ""); } -@@ -50,7 +56,7 @@ void ConstantPoolCacheEntry::initialize_secondary_entry(int main_index) { +@@ -50,7 +56,7 @@ int ConstantPoolCacheEntry::as_flags(TosState state, bool is_final, bool is_vfinal, bool is_volatile, @@ -3128,7 +3082,7 @@ index 678bc13..d34f7c3 100644 int f = state; assert( state < number_of_states, "Invalid state in as_flags"); -@@ -65,7 +71,9 @@ int ConstantPoolCacheEntry::as_flags(TosState state, bool is_final, +@@ -65,7 +71,9 @@ if (is_method_interface) f |= 1; f <<= 1; if (is_method) f |= 1; @@ -3139,7 +3093,7 @@ index 678bc13..d34f7c3 100644 // Preserve existing flag bit values #ifdef ASSERT int old_state = ((_flags >> tosBits) & 0x0F); -@@ -137,7 +145,7 @@ void ConstantPoolCacheEntry::set_field(Bytecodes::Code get_code, +@@ -137,7 +145,7 @@ set_f2(field_offset); assert(field_index <= field_index_mask, "field index does not fit in low flag bits"); @@ -3148,7 +3102,7 @@ index 678bc13..d34f7c3 100644 (field_index & field_index_mask)); set_bytecode_1(get_code); set_bytecode_2(put_code); -@@ -153,7 +161,8 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, +@@ -153,7 +161,8 @@ int vtable_index) { assert(!is_secondary_entry(), ""); assert(method->interpreter_entry() != NULL, "should have been set at this point"); @@ -3158,7 +3112,7 @@ index 678bc13..d34f7c3 100644 bool change_to_virtual = (invoke_code == Bytecodes::_invokeinterface); int byte_no = -1; -@@ -167,6 +176,9 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, +@@ -167,6 +176,9 @@ } else { assert(vtable_index >= 0, "valid index"); set_f2(vtable_index); @@ -3168,7 +3122,7 @@ index 678bc13..d34f7c3 100644 } byte_no = 2; break; -@@ -212,7 +224,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, +@@ -212,7 +224,7 @@ needs_vfinal_flag, false, change_to_virtual, @@ -3177,7 +3131,7 @@ index 678bc13..d34f7c3 100644 method()->size_of_parameters()); // Note: byte_no also appears in TemplateTable::resolve. -@@ -252,7 +264,7 @@ void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index) +@@ -252,7 +264,7 @@ assert(instanceKlass::cast(interf)->is_interface(), "must be an interface"); set_f1(interf); set_f2(index); @@ -3186,7 +3140,7 @@ index 678bc13..d34f7c3 100644 set_bytecode_1(Bytecodes::_invokeinterface); } -@@ -282,7 +294,7 @@ void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site, methodHandle sig +@@ -282,7 +294,7 @@ param_size -= 1; // do not count MH.this; it is not stacked for invokedynamic bool is_final = true; assert(signature_invoker->is_final_method(), "is_final"); @@ -3195,7 +3149,7 @@ index 678bc13..d34f7c3 100644 assert(_flags == 0 || _flags == flags, "flags should be the same"); set_flags(flags); // do not do set_bytecode on a secondary CP cache entry -@@ -416,26 +428,13 @@ void ConstantPoolCacheEntry::update_pointers() { +@@ -416,26 +428,13 @@ // If this constantPoolCacheEntry refers to old_method then update it // to refer to new_method. bool ConstantPoolCacheEntry::adjust_method_entry(methodOop old_method, @@ -3203,7 +3157,8 @@ index 678bc13..d34f7c3 100644 + methodOop new_method) { if (is_vfinal()) { -- // virtual and final so f2() contains method ptr instead of vtable index ++ + // virtual and final so f2() contains method ptr instead of vtable index - if (f2() == (intptr_t)old_method) { - // match old_method so need an update - _f2 = (intptr_t)new_method; @@ -3219,14 +3174,13 @@ index 678bc13..d34f7c3 100644 - new_method->name()->as_C_string(), - new_method->signature()->as_C_string())); - } - -+ // virtual and final so f2() contains method ptr instead of vtable index +- + if((methodOop)f2() != NULL && ((methodOop)f2())->method_holder()->klass_part()->new_version()) { + initialize_entry(constant_pool_index()); return true; } -@@ -443,65 +442,28 @@ bool ConstantPoolCacheEntry::adjust_method_entry(methodOop old_method, +@@ -443,65 +442,28 @@ return false; } @@ -3303,7 +3257,7 @@ index 678bc13..d34f7c3 100644 void ConstantPoolCacheEntry::print(outputStream* st, int index) const { // print separator if (index == 0) tty->print_cr(" -------------"); -@@ -542,38 +504,18 @@ void constantPoolCacheOopDesc::initialize(intArray& inverse_index_map) { +@@ -542,38 +504,18 @@ // RedefineClasses() API support: // If any entry of this constantPoolCache points to any of // old_methods, replace it with the corresponding new_method. @@ -3325,7 +3279,8 @@ index 678bc13..d34f7c3 100644 - // skip uninteresting methods - continue; - } -- ++ if (entry_at(i)->is_field_entry()) { + - // The constantPoolCache contains entries for several different - // things, but we only care about methods. In fact, we only care - // about methods in the same class as the one that contains the @@ -3341,8 +3296,6 @@ index 678bc13..d34f7c3 100644 - // break out and get to the next interesting entry if there one - break; - } -+ if (entry_at(i)->is_field_entry()) { -+ + // (tw) TODO: Update only field offsets and modify only constant pool entries that + // point to changed fields + entry_at(i)->initialize_entry(entry_at(i)->constant_pool_index()); @@ -3353,10 +3306,9 @@ index 678bc13..d34f7c3 100644 } } diff --git a/src/share/vm/oops/cpCacheOop.hpp b/src/share/vm/oops/cpCacheOop.hpp -index c3d1847..ab7a095 100644 --- a/src/share/vm/oops/cpCacheOop.hpp +++ b/src/share/vm/oops/cpCacheOop.hpp -@@ -135,19 +135,24 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { +@@ -135,19 +135,24 @@ void set_bytecode_2(Bytecodes::Code code); void set_f1(oop f1) { oop existing_f1 = _f1; // read once @@ -3384,7 +3336,7 @@ index c3d1847..ab7a095 100644 hotSwapBit = 23, methodInterface = 24, volatileField = 25, -@@ -167,6 +172,8 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { +@@ -167,6 +172,8 @@ void initialize_entry(int original_index); // initialize primary entry void initialize_secondary_entry(int main_index); // initialize secondary entry @@ -3393,7 +3345,7 @@ index c3d1847..ab7a095 100644 void set_field( // sets entry to resolved field state Bytecodes::Code get_code, // the bytecode used for reading the field Bytecodes::Code put_code, // the bytecode used for writing the field -@@ -296,9 +303,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { +@@ -296,9 +303,7 @@ // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. @@ -3404,7 +3356,7 @@ index c3d1847..ab7a095 100644 bool is_field_entry() const { return (_flags & (1 << hotSwapBit)) == 0; } bool is_method_entry() const { return (_flags & (1 << hotSwapBit)) != 0; } -@@ -397,14 +402,9 @@ class constantPoolCacheOopDesc: public oopDesc { +@@ -397,14 +402,9 @@ return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index); } @@ -3423,10 +3375,9 @@ index c3d1847..ab7a095 100644 #endif // SHARE_VM_OOPS_CPCACHEOOP_HPP diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp -index eec2e23..cc793e2 100644 --- a/src/share/vm/oops/instanceKlass.cpp +++ b/src/share/vm/oops/instanceKlass.cpp -@@ -248,12 +248,118 @@ void instanceKlass::initialize(TRAPS) { +@@ -248,12 +248,118 @@ } @@ -3546,7 +3497,7 @@ index eec2e23..cc793e2 100644 } -@@ -360,7 +466,13 @@ bool instanceKlass::link_class_impl( +@@ -360,7 +466,13 @@ jt->get_thread_stat()->perf_recursion_counts_addr(), jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_VERIFY); @@ -3561,7 +3512,7 @@ index eec2e23..cc793e2 100644 if (!verify_ok) { return false; } -@@ -398,7 +510,8 @@ bool instanceKlass::link_class_impl( +@@ -398,7 +510,8 @@ } #endif this_oop->set_init_state(linked); @@ -3571,7 +3522,7 @@ index eec2e23..cc793e2 100644 Thread *thread = THREAD; assert(thread->is_Java_thread(), "thread->is_Java_thread()"); JvmtiExport::post_class_prepare((JavaThread *) thread, this_oop()); -@@ -665,6 +778,18 @@ bool instanceKlass::implements_interface(klassOop k) const { +@@ -665,6 +778,18 @@ return false; } @@ -3590,7 +3541,7 @@ index eec2e23..cc793e2 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)) { -@@ -793,7 +918,25 @@ methodOop instanceKlass::class_initializer() { +@@ -793,7 +918,25 @@ } void instanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) { @@ -3616,7 +3567,7 @@ index eec2e23..cc793e2 100644 assert(!this_oop->is_initialized(), "we cannot initialize twice"); if (TraceClassInitialization) { tty->print("%d Initializing ", call_class_initializer_impl_counter++); -@@ -942,6 +1085,137 @@ void instanceKlass::methods_do(void f(methodOop method)) { +@@ -942,6 +1085,137 @@ } } @@ -3754,7 +3705,7 @@ index eec2e23..cc793e2 100644 void instanceKlass::do_local_static_fields(FieldClosure* cl) { for (JavaFieldStream fs(this); !fs.done(); fs.next()) { -@@ -1331,6 +1605,20 @@ jmethodID instanceKlass::jmethod_id_or_null(methodOop method) { +@@ -1331,6 +1605,20 @@ return id; } @@ -3775,7 +3726,7 @@ index eec2e23..cc793e2 100644 // Cache an itable index void instanceKlass::set_cached_itable_index(size_t idnum, int index) { -@@ -1490,6 +1778,13 @@ void instanceKlass::remove_dependent_nmethod(nmethod* nm) { +@@ -1490,6 +1778,13 @@ last = b; b = b->next(); } @@ -3789,7 +3740,7 @@ index eec2e23..cc793e2 100644 #ifdef ASSERT tty->print_cr("### %s can't find dependent nmethod:", this->external_name()); nm->print(); -@@ -2337,6 +2632,9 @@ void instanceKlass::oop_print_on(oop obj, outputStream* st) { +@@ -2337,6 +2632,9 @@ klassOop mirrored_klass = java_lang_Class::as_klassOop(obj); st->print(BULLET"fake entry for mirror: "); mirrored_klass->print_value_on(st); @@ -3800,10 +3751,9 @@ index eec2e23..cc793e2 100644 st->print(BULLET"fake entry resolved_constructor: "); methodOop ctor = java_lang_Class::resolved_constructor(obj); diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp -index e981cde..fb79827 100644 --- a/src/share/vm/oops/instanceKlass.hpp +++ b/src/share/vm/oops/instanceKlass.hpp -@@ -99,6 +99,22 @@ public: +@@ -99,6 +99,22 @@ virtual void do_field(fieldDescriptor* fd) = 0; }; @@ -3826,7 +3776,7 @@ index e981cde..fb79827 100644 #ifndef PRODUCT // Print fields. // If "obj" argument to constructor is NULL, prints static fields, otherwise prints non-static fields. -@@ -264,6 +280,11 @@ class instanceKlass: public Klass { +@@ -264,6 +280,11 @@ // _idnum_allocated_count. u1 _init_state; // state of class @@ -3838,7 +3788,7 @@ index e981cde..fb79827 100644 u1 _reference_type; // reference type // embedded Java vtable follows here -@@ -397,6 +418,7 @@ class instanceKlass: public Klass { +@@ -397,6 +418,7 @@ // initialization (virtuals from Klass) bool should_be_initialized() const; // means that initialize should be called void initialize(TRAPS); @@ -3846,7 +3796,7 @@ index e981cde..fb79827 100644 void link_class(TRAPS); bool link_class_or_fail(TRAPS); // returns false on failure void unlink_class(); -@@ -549,6 +571,7 @@ class instanceKlass: public Klass { +@@ -549,6 +571,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); @@ -3854,7 +3804,7 @@ index e981cde..fb79827 100644 // cached itable index support void set_cached_itable_index(size_t idnum, int index); -@@ -630,6 +653,7 @@ class instanceKlass: public Klass { +@@ -630,6 +653,7 @@ // subclass/subinterface checks bool implements_interface(klassOop k) const; @@ -3862,7 +3812,7 @@ index e981cde..fb79827 100644 // Access to implementors of an interface. We only store the count // of implementors, and in case, there are only a few -@@ -659,6 +683,12 @@ class instanceKlass: public Klass { +@@ -659,6 +683,12 @@ 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); @@ -3876,10 +3826,9 @@ index e981cde..fb79827 100644 void methods_do(void f(methodOop method)); void array_klasses_do(void f(klassOop k)); diff --git a/src/share/vm/oops/instanceKlassKlass.cpp b/src/share/vm/oops/instanceKlassKlass.cpp -index fa13f17..ef1444b 100644 --- a/src/share/vm/oops/instanceKlassKlass.cpp +++ b/src/share/vm/oops/instanceKlassKlass.cpp -@@ -451,6 +451,28 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { +@@ -451,6 +451,28 @@ instanceKlass* ik = instanceKlass::cast(klassOop(obj)); klassKlass::oop_print_on(obj, st); @@ -3908,7 +3857,7 @@ index fa13f17..ef1444b 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(); -@@ -636,7 +658,7 @@ void instanceKlassKlass::oop_verify_on(oop obj, outputStream* st) { +@@ -636,7 +658,7 @@ } guarantee(sib->as_klassOop()->is_klass(), "should be klass"); guarantee(sib->as_klassOop()->is_perm(), "should be in permspace"); @@ -3918,10 +3867,9 @@ index fa13f17..ef1444b 100644 } diff --git a/src/share/vm/oops/instanceRefKlass.cpp b/src/share/vm/oops/instanceRefKlass.cpp -index 71a7a1f..c7644b0 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 @@ -3940,10 +3888,9 @@ index 71a7a1f..c7644b0 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 345d0b2..f49db6c 100644 --- a/src/share/vm/oops/klass.cpp +++ b/src/share/vm/oops/klass.cpp -@@ -54,6 +54,26 @@ bool Klass::is_subclass_of(klassOop k) const { +@@ -54,6 +54,26 @@ return false; } @@ -3970,7 +3917,7 @@ index 345d0b2..f49db6c 100644 bool Klass::search_secondary_supers(klassOop k) const { // Put some extra logic here out-of-line, before the search proper. // This cuts down the size of the inline method. -@@ -160,6 +180,16 @@ klassOop Klass::base_create_klass_oop(KlassHandle& klass, int size, +@@ -160,6 +180,16 @@ kl->set_alloc_size(0); TRACE_SET_KLASS_TRACE_ID(kl, 0); @@ -3987,7 +3934,7 @@ index 345d0b2..f49db6c 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 +262,7 @@ void Klass::initialize_supers(klassOop k, TRAPS) { +@@ -232,7 +262,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"); @@ -3997,10 +3944,9 @@ index 345d0b2..f49db6c 100644 "initialize this only once to a non-trivial value"); set_super(k); diff --git a/src/share/vm/oops/klass.hpp b/src/share/vm/oops/klass.hpp -index 035f44c..3cd26a3 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); }; @@ -4008,7 +3954,7 @@ index 035f44c..3cd26a3 100644 class Klass : public Klass_vtbl { friend class VMStructs; -@@ -222,6 +223,39 @@ class Klass : public Klass_vtbl { +@@ -222,6 +223,39 @@ oop* oop_block_beg() const { return adr_secondary_super_cache(); } oop* oop_block_end() const { return adr_next_sibling() + 1; } @@ -4048,7 +3994,7 @@ index 035f44c..3cd26a3 100644 protected: // // The oop block. All oop fields must be declared here and only oop fields -@@ -241,6 +275,10 @@ class Klass : public Klass_vtbl { +@@ -241,6 +275,10 @@ oop _java_mirror; // Superclass klassOop _super; @@ -4059,7 +4005,7 @@ index 035f44c..3cd26a3 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 +291,19 @@ class Klass : public Klass_vtbl { +@@ -253,6 +291,19 @@ jint _modifier_flags; // Processed access flags, for use by Class.getModifiers. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. @@ -4079,7 +4025,7 @@ index 035f44c..3cd26a3 100644 #ifndef PRODUCT int _verify_count; // to avoid redundant verifies #endif -@@ -301,6 +352,99 @@ class Klass : public Klass_vtbl { +@@ -301,6 +352,99 @@ 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); } @@ -4179,7 +4125,7 @@ index 035f44c..3cd26a3 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 +505,8 @@ class Klass : public Klass_vtbl { +@@ -361,6 +505,8 @@ void set_next_sibling(klassOop s); oop* adr_super() const { return (oop*)&_super; } @@ -4188,7 +4134,7 @@ index 035f44c..3cd26a3 100644 oop* adr_primary_supers() const { return (oop*)&_primary_supers[0]; } oop* adr_secondary_super_cache() const { return (oop*)&_secondary_super_cache; } oop* adr_secondary_supers()const { return (oop*)&_secondary_supers; } -@@ -490,6 +636,7 @@ class Klass : public Klass_vtbl { +@@ -490,6 +636,7 @@ return search_secondary_supers(k); } } @@ -4196,7 +4142,7 @@ index 035f44c..3cd26a3 100644 bool search_secondary_supers(klassOop k) const; // Find LCA in class hierarchy -@@ -818,6 +965,8 @@ class Klass : public Klass_vtbl { +@@ -818,6 +965,8 @@ inline oop klassOopDesc::java_mirror() const { return klass_part()->java_mirror(); } @@ -4206,10 +4152,9 @@ index 035f44c..3cd26a3 100644 #endif // SHARE_VM_OOPS_KLASS_HPP diff --git a/src/share/vm/oops/klassKlass.cpp b/src/share/vm/oops/klassKlass.cpp -index 06809d5..9c08f32 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()); @@ -4218,7 +4163,7 @@ index 06809d5..9c08f32 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()); @@ -4227,7 +4172,7 @@ index 06809d5..9c08f32 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()); @@ -4236,7 +4181,7 @@ index 06809d5..9c08f32 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); @@ -4247,7 +4192,7 @@ index 06809d5..9c08f32 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); -@@ -147,6 +157,8 @@ int klassKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { +@@ -147,6 +157,8 @@ // The following are "weak links" in the perm gen and are // treated specially in a later phase of a perm gen collection. assert(oop(k)->is_perm(), "should be in perm"); @@ -4256,7 +4201,7 @@ index 06809d5..9c08f32 100644 assert(oop(k->adr_subklass())->is_perm(), "should be in perm"); assert(oop(k->adr_next_sibling())->is_perm(), "should be in perm"); if (blk->should_remember_klasses() -@@ -167,6 +179,8 @@ int klassKlass::oop_adjust_pointers(oop obj) { +@@ -167,6 +179,8 @@ Klass* k = Klass::cast(klassOop(obj)); MarkSweep::adjust_pointer(k->adr_super()); @@ -4266,10 +4211,9 @@ index 06809d5..9c08f32 100644 MarkSweep::adjust_pointer(k->adr_primary_supers()+i); MarkSweep::adjust_pointer(k->adr_secondary_super_cache()); diff --git a/src/share/vm/oops/klassOop.hpp b/src/share/vm/oops/klassOop.hpp -index f212fc5..9731a9c 100644 --- a/src/share/vm/oops/klassOop.hpp +++ b/src/share/vm/oops/klassOop.hpp -@@ -41,8 +41,10 @@ class klassOopDesc : public oopDesc { +@@ -41,8 +41,10 @@ // returns the Klass part containing dispatching behavior Klass* klass_part() const { return (Klass*)((address)this + sizeof(klassOopDesc)); } @@ -4282,10 +4226,9 @@ index f212fc5..9731a9c 100644 private: // These have no implementation since klassOop should never be accessed in this fashion diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.cpp -index 8b8bc7d..cefe839 100644 --- a/src/share/vm/oops/klassVtable.cpp +++ b/src/share/vm/oops/klassVtable.cpp -@@ -97,7 +97,8 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length, +@@ -97,7 +97,8 @@ vtable_length = Universe::base_vtable_size(); } @@ -4295,7 +4238,7 @@ index 8b8bc7d..cefe839 100644 vtable_length != Universe::base_vtable_size()) { // Someone is attempting to redefine java.lang.Object incorrectly. The // only way this should happen is from -@@ -107,9 +108,9 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length, +@@ -107,9 +108,9 @@ vtable_length = Universe::base_vtable_size(); } assert(super != NULL || vtable_length == Universe::base_vtable_size(), @@ -4307,7 +4250,7 @@ index 8b8bc7d..cefe839 100644 } int klassVtable::index_of(methodOop m, int len) const { -@@ -1186,6 +1187,7 @@ void klassVtable::verify(outputStream* st, bool forced) { +@@ -1186,6 +1187,7 @@ void klassVtable::verify_against(outputStream* st, klassVtable* vt, int index) { vtableEntry* vte = &vt->table()[index]; @@ -4315,7 +4258,7 @@ index 8b8bc7d..cefe839 100644 if (vte->method()->name() != table()[index].method()->name() || vte->method()->signature() != table()[index].method()->signature()) { fatal("mismatched name/signature of vtable entries"); -@@ -1205,6 +1207,8 @@ void klassVtable::print() { +@@ -1205,6 +1207,8 @@ void vtableEntry::verify(klassVtable* vt, outputStream* st) { NOT_PRODUCT(FlagSetting fs(IgnoreLockingAssertions, true)); @@ -4324,7 +4267,7 @@ index 8b8bc7d..cefe839 100644 assert(method() != NULL, "must have set method"); method()->verify(); // we sub_type, because it could be a miranda method -@@ -1212,7 +1216,13 @@ void vtableEntry::verify(klassVtable* vt, outputStream* st) { +@@ -1212,7 +1216,13 @@ #ifndef PRODUCT print(); #endif @@ -4339,7 +4282,7 @@ index 8b8bc7d..cefe839 100644 } } -@@ -1220,7 +1230,7 @@ void vtableEntry::verify(klassVtable* vt, outputStream* st) { +@@ -1220,7 +1230,7 @@ void vtableEntry::print() { ResourceMark rm; @@ -4348,7 +4291,7 @@ index 8b8bc7d..cefe839 100644 if (Verbose) { tty->print("m %#lx ", (address)method()); } -@@ -1292,7 +1302,7 @@ bool klassVtable::check_no_old_entries() { +@@ -1292,7 +1302,7 @@ for (int i = 0; i < length(); i++) { methodOop m = unchecked_method_at(i); if (m != NULL) { @@ -4358,10 +4301,9 @@ index 8b8bc7d..cefe839 100644 } } diff --git a/src/share/vm/oops/methodKlass.cpp b/src/share/vm/oops/methodKlass.cpp -index b2d6235..1876420 100644 --- a/src/share/vm/oops/methodKlass.cpp +++ b/src/share/vm/oops/methodKlass.cpp -@@ -93,6 +93,10 @@ methodOop methodKlass::allocate(constMethodHandle xconst, +@@ -93,6 +93,10 @@ m->set_adapter_entry(NULL); m->clear_code(); // from_c/from_i get set to c2i/i2i @@ -4372,7 +4314,7 @@ index b2d6235..1876420 100644 if (access_flags.is_native()) { m->clear_native_function(); m->set_signature_handler(NULL); -@@ -127,6 +131,9 @@ void methodKlass::oop_follow_contents(oop obj) { +@@ -127,6 +131,9 @@ // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::methodKlassObj never moves. MarkSweep::mark_and_push(m->adr_constMethod()); @@ -4382,7 +4324,7 @@ index b2d6235..1876420 100644 MarkSweep::mark_and_push(m->adr_constants()); if (m->method_data() != NULL) { MarkSweep::mark_and_push(m->adr_method_data()); -@@ -141,6 +148,9 @@ void methodKlass::oop_follow_contents(ParCompactionManager* cm, +@@ -141,6 +148,9 @@ // 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()); @@ -4392,7 +4334,7 @@ index b2d6235..1876420 100644 PSParallelCompact::mark_and_push(cm, m->adr_constants()); #ifdef COMPILER2 if (m->method_data() != NULL) { -@@ -159,6 +169,9 @@ int methodKlass::oop_oop_iterate(oop obj, OopClosure* blk) { +@@ -159,6 +169,9 @@ // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::methodKlassObj never moves blk->do_oop(m->adr_constMethod()); @@ -4402,7 +4344,7 @@ index b2d6235..1876420 100644 blk->do_oop(m->adr_constants()); if (m->method_data() != NULL) { blk->do_oop(m->adr_method_data()); -@@ -178,6 +191,12 @@ int methodKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { +@@ -178,6 +191,12 @@ oop* adr; adr = m->adr_constMethod(); if (mr.contains(adr)) blk->do_oop(adr); @@ -4415,7 +4357,7 @@ index b2d6235..1876420 100644 adr = m->adr_constants(); if (mr.contains(adr)) blk->do_oop(adr); if (m->method_data() != NULL) { -@@ -197,6 +216,9 @@ int methodKlass::oop_adjust_pointers(oop obj) { +@@ -197,6 +216,9 @@ // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::methodKlassObj never moves. MarkSweep::adjust_pointer(m->adr_constMethod()); @@ -4425,7 +4367,7 @@ index b2d6235..1876420 100644 MarkSweep::adjust_pointer(m->adr_constants()); if (m->method_data() != NULL) { MarkSweep::adjust_pointer(m->adr_method_data()); -@@ -213,6 +235,9 @@ int methodKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { +@@ -213,6 +235,9 @@ assert(obj->is_method(), "should be method"); methodOop m = methodOop(obj); PSParallelCompact::adjust_pointer(m->adr_constMethod()); @@ -4435,7 +4377,7 @@ index b2d6235..1876420 100644 PSParallelCompact::adjust_pointer(m->adr_constants()); #ifdef COMPILER2 if (m->method_data() != NULL) { -@@ -234,7 +259,18 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) { +@@ -234,7 +259,18 @@ methodOop m = methodOop(obj); // get the effect of PrintOopAddress, always, for methods: st->print_cr(" - this oop: "INTPTR_FORMAT, (intptr_t)m); @@ -4456,10 +4398,9 @@ index b2d6235..1876420 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 0a7850f..c62ce28 100644 --- a/src/share/vm/oops/methodOop.cpp +++ b/src/share/vm/oops/methodOop.cpp -@@ -328,6 +328,70 @@ void methodOopDesc::cleanup_inline_caches() { +@@ -328,6 +328,70 @@ } @@ -4530,7 +4471,7 @@ index 0a7850f..c62ce28 100644 int methodOopDesc::extra_stack_words() { // not an inline function, to avoid a header dependency on Interpreter return extra_stack_entries() * Interpreter::stackElementSize; -@@ -1079,6 +1143,9 @@ methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_cod +@@ -1079,6 +1143,9 @@ // Reset correct method/const method, method size, and parameter info newcm->set_method(newm()); newm->set_constMethod(newcm); @@ -4541,10 +4482,9 @@ index 0a7850f..c62ce28 100644 newm->constMethod()->set_code_size(new_code_length); newm->constMethod()->set_constMethod_size(new_const_method_size); diff --git a/src/share/vm/oops/methodOop.hpp b/src/share/vm/oops/methodOop.hpp -index 03f62f6..7f7b05a 100644 --- a/src/share/vm/oops/methodOop.hpp +++ b/src/share/vm/oops/methodOop.hpp -@@ -116,6 +116,11 @@ class methodOopDesc : public oopDesc { +@@ -116,6 +116,11 @@ 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) @@ -4556,7 +4496,7 @@ index 03f62f6..7f7b05a 100644 #ifdef CC_INTERP int _result_index; // C++ interpreter needs for converting results to/from stack #endif -@@ -174,6 +179,32 @@ class methodOopDesc : public oopDesc { +@@ -174,6 +179,32 @@ int name_index() const { return constMethod()->name_index(); } void set_name_index(int index) { constMethod()->set_name_index(index); } @@ -4589,7 +4529,7 @@ index 03f62f6..7f7b05a 100644 // signature Symbol* signature() const { return _constants->symbol_at(signature_index()); } int signature_index() const { return constMethod()->signature_index(); } -@@ -670,6 +701,10 @@ class methodOopDesc : public oopDesc { +@@ -670,6 +701,10 @@ // Inline cache support void cleanup_inline_caches(); @@ -4600,7 +4540,7 @@ index 03f62f6..7f7b05a 100644 // Find if klass for method is loaded bool is_klass_loaded_by_klass_index(int klass_index) const; bool is_klass_loaded(int refinfo_index, bool must_be_resolved = false) const; -@@ -723,6 +758,9 @@ class methodOopDesc : public oopDesc { +@@ -723,6 +758,9 @@ // Garbage collection support oop* adr_constMethod() const { return (oop*)&_constMethod; } @@ -4611,10 +4551,9 @@ index 03f62f6..7f7b05a 100644 oop* adr_method_data() const { return (oop*)&_method_data; } }; diff --git a/src/share/vm/oops/oop.hpp b/src/share/vm/oops/oop.hpp -index 4d2f453..3ea0396 100644 --- a/src/share/vm/oops/oop.hpp +++ b/src/share/vm/oops/oop.hpp -@@ -94,6 +94,7 @@ class oopDesc { +@@ -94,6 +94,7 @@ narrowOop* compressed_klass_addr(); void set_klass(klassOop k); @@ -4622,7 +4561,7 @@ index 4d2f453..3ea0396 100644 // For klass field compression int klass_gap() const; -@@ -134,6 +135,7 @@ class oopDesc { +@@ -134,6 +135,7 @@ bool is_array() const; bool is_objArray() const; bool is_klass() const; @@ -4631,10 +4570,9 @@ index 4d2f453..3ea0396 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 a050f96..09258e1 100644 --- a/src/share/vm/oops/oop.inline.hpp +++ b/src/share/vm/oops/oop.inline.hpp -@@ -115,6 +115,14 @@ inline void oopDesc::set_klass(klassOop k) { +@@ -115,6 +115,14 @@ } } @@ -4649,7 +4587,7 @@ index a050f96..09258e1 100644 inline int oopDesc::klass_gap() const { return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes()); } -@@ -148,6 +156,7 @@ inline bool oopDesc::is_objArray() const { return blueprint()->oop_is_ +@@ -148,6 +156,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(); } @@ -4658,10 +4596,9 @@ index a050f96..09258e1 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 166bbd6..fc1025f 100644 --- a/src/share/vm/prims/jni.cpp +++ b/src/share/vm/prims/jni.cpp -@@ -405,7 +405,7 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR +@@ -405,7 +405,7 @@ } } klassOop k = SystemDictionary::resolve_from_stream(class_name, class_loader, @@ -4671,10 +4608,9 @@ index 166bbd6..fc1025f 100644 if (TraceClassResolution && k != NULL) { diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp -index 4c503fe..9b43779 100644 --- a/src/share/vm/prims/jvm.cpp +++ b/src/share/vm/prims/jvm.cpp -@@ -866,7 +866,7 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, +@@ -866,7 +866,7 @@ Handle protection_domain (THREAD, JNIHandles::resolve(pd)); klassOop k = SystemDictionary::resolve_from_stream(class_name, class_loader, protection_domain, &st, @@ -4684,10 +4620,9 @@ index 4c503fe..9b43779 100644 if (TraceClassResolution && k != NULL) { diff --git a/src/share/vm/prims/jvmtiEnv.cpp b/src/share/vm/prims/jvmtiEnv.cpp -index 46519bb..7fd634a 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); @@ -4699,7 +4634,7 @@ index 46519bb..7fd634a 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) { @@ -4715,10 +4650,9 @@ index 46519bb..7fd634a 100644 } /* end RedefineClasses */ diff --git a/src/share/vm/prims/jvmtiExport.cpp b/src/share/vm/prims/jvmtiExport.cpp -index 5325073..247167a 100644 --- a/src/share/vm/prims/jvmtiExport.cpp +++ b/src/share/vm/prims/jvmtiExport.cpp -@@ -2307,7 +2307,7 @@ JvmtiDynamicCodeEventCollector::JvmtiDynamicCodeEventCollector() : _code_blobs(N +@@ -2307,7 +2307,7 @@ // iterate over any code blob descriptors collected and post a // DYNAMIC_CODE_GENERATED event to the profiler. JvmtiDynamicCodeEventCollector::~JvmtiDynamicCodeEventCollector() { @@ -4728,10 +4662,9 @@ index 5325073..247167a 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 e0d809d..19a4413 100644 --- a/src/share/vm/prims/jvmtiImpl.cpp +++ b/src/share/vm/prims/jvmtiImpl.cpp -@@ -286,6 +286,8 @@ address JvmtiBreakpoint::getBcp() { +@@ -286,6 +286,8 @@ void JvmtiBreakpoint::each_method_version_do(method_action meth_act) { ((methodOopDesc*)_method->*meth_act)(_bci); @@ -4741,17 +4674,16 @@ index e0d809d..19a4413 100644 // are EMCP. Directly or transitively obsolete methods are // not saved in the PreviousVersionInfo. diff --git a/src/share/vm/prims/jvmtiRedefineClasses.cpp b/src/share/vm/prims/jvmtiRedefineClasses.cpp -index 295ed86..fdfc6f4 100644 --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -30,491 +30,637 @@ #include "interpreter/rewriter.hpp" #include "memory/gcLocker.hpp" #include "memory/universe.inline.hpp" --#include "oops/fieldStreams.hpp" +#include "memory/cardTableRS.hpp" - #include "oops/klassVtable.hpp" -+#include "oops/fieldStreams.hpp" ++#include "oops/klassVtable.hpp" + #include "oops/fieldStreams.hpp" +-#include "oops/klassVtable.hpp" #include "prims/jvmtiImpl.hpp" #include "prims/jvmtiRedefineClasses.hpp" +#include "prims/jvmtiClassFileReconstituter.hpp" @@ -4777,12 +4709,13 @@ index 295ed86..fdfc6f4 100644 int VM_RedefineClasses::_added_methods_length = 0; klassOop VM_RedefineClasses::_the_class_oop = NULL; -+// Holds the revision number of the current class redefinition -+int VM_RedefineClasses::_revision_number = -1; - +- -VM_RedefineClasses::VM_RedefineClasses(jint class_count, - const jvmtiClassDefinition *class_defs, - JvmtiClassLoadKind class_load_kind) { ++// Holds the revision number of the current class redefinition ++int VM_RedefineClasses::_revision_number = -1; ++ +VM_RedefineClasses::VM_RedefineClasses(jint class_count, const jvmtiClassDefinition *class_defs, JvmtiClassLoadKind class_load_kind) + : VM_GC_Operation(Universe::heap()->total_full_collections(), GCCause::_jvmti_force_gc) { + RC_TIMER_START(_timer_total); @@ -4794,10 +4727,6 @@ index 295ed86..fdfc6f4 100644 + _result = JVMTI_ERROR_NONE; } --bool VM_RedefineClasses::doit_prologue() { -- if (_class_count == 0) { -- _res = JVMTI_ERROR_NONE; -- return false; +VM_RedefineClasses::~VM_RedefineClasses() { + { + MonitorLockerEx ml(RedefinitionSync_lock); @@ -4819,10 +4748,7 @@ index 295ed86..fdfc6f4 100644 + tty->print_cr("Timing Epilogue: %d", _timer_vm_op_epilogue.milliseconds()); + tty->print_cr("------------------------------------------------------------------"); + tty->print_cr("Total Time: %d", _timer_total.milliseconds()); - } -- if (_class_defs == NULL) { -- _res = JVMTI_ERROR_NULL_POINTER; -- return false; ++ } +} + +// Searches for all affected classes and performs a sorting such that a supertype is always before a subtype. @@ -4835,19 +4761,7 @@ index 295ed86..fdfc6f4 100644 + instanceKlassHandle klass_handle(Thread::current(), java_lang_Class::as_klassOop(mirror)); + klasses_to_redefine.append(klass_handle); + assert(klass_handle->new_version() == NULL, "Must be new class"); - } -- 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; ++ } + + // Find classes not directly redefined, but affected by a redefinition (because one of its supertypes is redefined) + GrowableArray<instanceKlassHandle> affected_classes; @@ -4860,24 +4774,13 @@ index 295ed86..fdfc6f4 100644 + for (int i=0; i<affected_classes.length(); i++) { + RC_TRACE(0x00000001, ("%s", + affected_classes.at(i)->name()->as_C_string())); - } - } - -- // 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); ++ } ++ } ++ + // Add the array of affected classes and the array of redefined classes to get a list of all classes that need a redefinition + all_affected_klasses->appendAll(&klasses_to_redefine); + all_affected_klasses->appendAll(&affected_classes); - -- // We first load new class versions in the prologue, because somewhere down the -- // call chain it is required that the current thread is a Java thread. -- _res = load_new_class_versions(Thread::current()); -- 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; ++ + // Sort the affected klasses such that a supertype is always on a smaller array index than its subtype. + jvmtiError result = do_topological_class_sorting(_class_defs, _class_count, &affected_classes, all_affected_klasses, Thread::current()); + if (RC_TRACE_ENABLED(0x00000001)) { @@ -4886,28 +4789,14 @@ index 295ed86..fdfc6f4 100644 + RC_TRACE(0x00000001, ("%s", + all_affected_klasses->at(i)->name()->as_C_string())); + } - } - -- RC_TIMER_STOP(_timer_vm_op_prologue); -- return true; ++ } ++ + 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 @@ -4917,46 +4806,16 @@ index 295ed86..fdfc6f4 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; - --#ifdef ASSERT -- SystemDictionary::classes_do(check_class, thread); --#endif --} ++ + // 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. - --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 (the_class->get_cached_class_file_bytes() == NULL) { + // not cached, we need to reconstitute the class file from VM representation + constantPoolHandle constants(Thread::current(), the_class->constants()); @@ -4982,16 +4841,15 @@ index 295ed86..fdfc6f4 100644 + // Redefine with bytecodes at index j + *class_bytes = _class_defs[j].class_bytes; + *class_byte_count = _class_defs[j].class_byte_count; - } ++ } + + return JVMTI_ERROR_NONE; - } - --bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) { -- // classes for primitives cannot be redefined -- if (java_lang_Class::is_primitive(klass_mirror)) { ++} ++ +// Prologue of the VM operation, called on the Java thread in parallel to normal program execution -+bool VM_RedefineClasses::doit_prologue() { + bool VM_RedefineClasses::doit_prologue() { +- if (_class_count == 0) { +- _res = JVMTI_ERROR_NONE; + + _revision_number++; + RC_TRACE(0x00000001, ("Redefinition with revision number %d started!", _revision_number)); @@ -5003,9 +4861,8 @@ index 295ed86..fdfc6f4 100644 + 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()) { +- if (_class_defs == NULL) { +- _res = JVMTI_ERROR_NULL_POINTER; + + // 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. @@ -5025,132 +4882,26 @@ index 295ed86..fdfc6f4 100644 + VM_GC_Operation::doit_prologue(); + RC_TIMER_STOP(_timer_prologue); + RC_TRACE(0x00000001, ("doit_prologue finished!")); - 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); ++ return true; ++} ++ +// Checks basic properties of the arguments of the redefinition command. +bool VM_RedefineClasses::check_arguments() { - -- 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; ++ + if (_class_count == 0) RC_ABORT(JVMTI_ERROR_NONE); + if (_class_defs == NULL) RC_ABORT(JVMTI_ERROR_NULL_POINTER); -+ for (int i = 0; i < _class_count; i++) { + 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].klass == NULL) RC_ABORT(JVMTI_ERROR_INVALID_CLASS); + if (_class_defs[i].class_byte_count == 0) RC_ABORT(JVMTI_ERROR_INVALID_CLASS_FORMAT); + if (_class_defs[i].class_bytes == NULL) RC_ABORT(JVMTI_ERROR_NULL_POINTER); + } - -- // 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 ++ + return true; +} - -- 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; ++ +jvmtiError VM_RedefineClasses::check_exception() const { + Thread* THREAD = Thread::current(); + if (HAS_PENDING_EXCEPTION) { @@ -5161,7 +4912,14 @@ index 295ed86..fdfc6f4 100644 + if (TraceRedefineClasses >= 1) { + java_lang_Throwable::print(PENDING_EXCEPTION, tty); + tty->print_cr(""); -+ } + } +- 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; + CLEAR_PENDING_EXCEPTION; + + if (ex_name == vmSymbols::java_lang_UnsupportedClassVersionError()) { @@ -5178,9 +4936,21 @@ index 295ed86..fdfc6f4 100644 + } else { + // Just in case more exceptions can be thrown.. + return JVMTI_ERROR_FAILS_VERIFICATION; -+ } -+ } -+ + } + } + +- // 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; + return JVMTI_ERROR_NONE; +} + @@ -5200,8 +4970,25 @@ index 295ed86..fdfc6f4 100644 + RC_TRACE(0x00000001, ("Error finding sorted affected classes: %d", + (int)err)); + return err; -+ } -+ + } + +- 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; + + JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current()); + @@ -5299,40 +5086,13 @@ index 295ed86..fdfc6f4 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 (RC_TRACE_ENABLED(0x00000001)) { @@ -5341,18 +5101,9 @@ index 295ed86..fdfc6f4 100644 + 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); @@ -5373,13 +5124,7 @@ index 295ed86..fdfc6f4 100644 + RC_TRACE(0x00000001, ("Error redefinition not allowed!")); + result = allowed; + 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)); ++ } + redefinition_flags = Klass::ModifyClass; + } + @@ -5408,93 +5153,23 @@ index 295ed86..fdfc6f4 100644 + fd_new.initialize(new_class(), fs.index()); + fd_old.initialize(new_class->old_version(), fs.index()); + transfer_special_access_flags(&fd_old, &fd_new); - } ++ } + } - -- (*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 (RC_TRACE_ENABLED(0x00000008)) { + if (new_class->super() != NULL) { + RC_TRACE(0x00000008, ("Super class is %s", + new_class->super()->klass_part()->name()->as_C_string())); - } -- (*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 ++ +#ifdef ASSERT + assert(new_class->super() == NULL || new_class->super()->klass_part()->new_version() == NULL, "Super klass must be newest version!"); - -- 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; -- } -- } ++ + the_class->vtable()->verify(tty); + new_class->vtable()->verify(tty); +#endif - -- 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; ++ + RC_TRACE(0x00000002, ("Verification done!")); + + if (i == all_affected_klasses.length() - 1) { @@ -5529,118 +5204,60 @@ index 295ed86..fdfc6f4 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 = all_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; ++ + unlock_threads(); + RC_TRACE(0x00000001, ("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)); -- } +- for (int i = 0; i < _class_count; i++) { +- redefine_single_class(_class_defs[i].klass, _scratch_classes[i], thread); + 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; + } +- // 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(); ++ + 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<all_affected_klasses.length(); i++) { + instanceKlassHandle the_class = all_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 ++ + RC_TRACE(0x00000002, ("Linking class %d/%d %s", + i, + all_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 ++ + RC_TRACE(0x00000002, ("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 + #ifdef ASSERT +- SystemDictionary::classes_do(check_class, thread); + for (int i=0; i<all_affected_klasses.length(); i++) { + instanceKlassHandle the_class = all_affected_klasses.at(i); + assert(the_class->new_version() != NULL, "Must have been redefined"); @@ -5656,12 +5273,30 @@ index 295ed86..fdfc6f4 100644 + + SystemDictionary::classes_do(check_class, THREAD); + -+#endif + #endif + + RC_TRACE(0x00000001, ("Finished verification!")); + 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())); +void VM_RedefineClasses::lock_threads() { + + RC_TIMER_START(_timer_wait_for_locks); @@ -5674,8 +5309,8 @@ index 295ed86..fdfc6f4 100644 + compilerThread->set_should_bailout(true); + } + javaThread = javaThread->next(); -+ } - + } ++ + int cnt = 0; + javaThread = Threads::first(); + while (javaThread != NULL) { @@ -5700,12 +5335,14 @@ index 295ed86..fdfc6f4 100644 + + + RC_TRACE(0x00000002, ("Locked %d threads", cnt)); - --void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class) { -- typeArrayOop save; -+ RC_TIMER_STOP(_timer_wait_for_locks); -+} + ++ RC_TIMER_STOP(_timer_wait_for_locks); + } + +-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::unlock_threads() { + + int cnt = 0; @@ -5720,16 +5357,14 @@ index 295ed86..fdfc6f4 100644 + } + } + javaThread = javaThread->next(); -+ } - -- 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); + } +- 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; ++ + RC_TRACE(0x00000002, ("Unlocked %d compiler threads", cnt)); - -- 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); ++ + cnt = 0; + javaThread = Threads::first(); + while (javaThread != NULL) { @@ -5739,14 +5374,349 @@ index 295ed86..fdfc6f4 100644 + } + } + javaThread = javaThread->next(); -+ } + } +- return true; ++ ++ RC_TRACE(0x00000002, ("Unlocked %d threads", cnt)); + } +-// 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; +- +- 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); -+ RC_TRACE(0x00000002, ("Unlocked %d threads", cnt)); - } - +-} +- +- +-jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( +- instanceKlassHandle the_class, +- instanceKlassHandle scratch_class) { +jvmtiError VM_RedefineClasses::check_redefinition_allowed(instanceKlassHandle scratch_class) { + + @@ -5756,10 +5726,7 @@ index 295ed86..fdfc6f4 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 @@ -5777,7 +5744,7 @@ index 295ed86..fdfc6f4 100644 } // Check if the number, names and order of directly implemented interfaces are the same. -@@ -532,8 +678,8 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( +@@ -532,8 +678,8 @@ } for (i = 0; i < n_intfs; i++) { if (Klass::cast((klassOop) k_interfaces->obj_at(i))->name() != @@ -5788,7 +5755,7 @@ index 295ed86..fdfc6f4 100644 } } -@@ -682,12 +828,8 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( +@@ -682,12 +828,8 @@ idnum_owner->set_method_idnum(new_num); } k_new_method->set_method_idnum(old_num); @@ -5801,7 +5768,7 @@ index 295ed86..fdfc6f4 100644 // advance to next pair of methods ++oi; ++ni; -@@ -696,11 +838,11 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( +@@ -696,11 +838,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 @@ -5818,7 +5785,7 @@ index 295ed86..fdfc6f4 100644 } { u2 num = the_class->next_method_idnum(); -@@ -715,24 +857,19 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( +@@ -715,24 +857,19 @@ idnum_owner->set_method_idnum(new_num); } k_new_method->set_method_idnum(num); @@ -5848,12 +5815,11 @@ index 295ed86..fdfc6f4 100644 ++oi; // advance to next old method break; default: -@@ -743,2217 +880,1789 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( +@@ -743,2084 +880,2272 @@ 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. @@ -5861,20 +5827,11 @@ index 295ed86..fdfc6f4 100644 - if (_index_map_count == 0) { - // map is empty so nothing can be found - return 0; -- } ++int VM_RedefineClasses::calculate_redefinition_flags(instanceKlassHandle new_class) { ++ + int result = Klass::NoRedefinition; - -- 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; ++ ++ + + RC_TRACE(0x00000002, ("Comparing different class versions of class %s", + new_class->name()->as_C_string())); @@ -5888,10 +5845,13 @@ index 295ed86..fdfc6f4 100644 + //result = Klass::union_redefinition_level(result, Klass::Invalid); } -- return value; --} // end find_new_index() +- 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; - ++ + ////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Check superclasses + assert(new_class->super() == NULL || new_class->super()->klass_part()->is_newest_version(), ""); @@ -5911,17 +5871,10 @@ index 295ed86..fdfc6f4 100644 + cur_klass->klass_part()->set_subtype_changed(true); + } + } - --// 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) { ++ + cur_klass = cur_klass->klass_part()->super(); + } - -- 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 ++ + cur_klass = new_class->super(); + while (cur_klass != NULL) { + if (!the_class->is_subclass_of(cur_klass->klass_part()->old_version())) { @@ -5931,8 +5884,149 @@ index 295ed86..fdfc6f4 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; +- } +- +- 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 +- } +- +- return true; // made it through the gauntlet; this is our special case +-} // end is_unresolved_class_mismatch() +- +- +-// Returns true if the current mismatch is due to a resolved/unresolved +-// string pair. Otherwise, returns false. +-bool VM_RedefineClasses::is_unresolved_string_mismatch(constantPoolHandle cp1, +- int index1, constantPoolHandle cp2, int index2) { +- +- jbyte t1 = cp1->tag_at(index1).value(); +- if (t1 != JVM_CONSTANT_String && t1 != JVM_CONSTANT_UnresolvedString) { +- return false; // wrong entry type; not our special case +- } +- +- jbyte t2 = cp2->tag_at(index2).value(); +- if (t2 != JVM_CONSTANT_String && t2 != JVM_CONSTANT_UnresolvedString) { +- return false; // wrong entry type; not our special case +- } +- +- if (t1 == t2) { +- return false; // not a mismatch; not our special case +- } +- +- char *s1 = cp1->string_at_noresolve(index1); +- char *s2 = cp2->string_at_noresolve(index2); +- if (strcmp(s1, s2) != 0) { +- return false; // strings don't match; not our special case +- } +- +- return true; // made it through the gauntlet; this is our special case +-} // end is_unresolved_string_mismatch() +- +- +-jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) { +- // For consistency allocate memory using os::malloc wrapper. +- _scratch_classes = (instanceKlassHandle *) +- os::malloc(sizeof(instanceKlassHandle) * _class_count); +- if (_scratch_classes == NULL) { +- return JVMTI_ERROR_OUT_OF_MEMORY; +- } +- +- ResourceMark rm(THREAD); +- +- JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current()); +- // state can only be NULL if the current thread is exiting which +- // should not happen since we're trying to do a RedefineClasses +- guarantee(state != NULL, "exiting thread calling load_new_class_versions"); +- for (int i = 0; i < _class_count; i++) { +- oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass); +- // classes for primitives cannot be redefined +- if (!is_modifiable_class(mirror)) { +- return JVMTI_ERROR_UNMODIFIABLE_CLASS; +- } +- klassOop the_class_oop = java_lang_Class::as_klassOop(mirror); +- instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop); +- Symbol* the_class_sym = the_class->name(); +- +- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark +- RC_TRACE_WITH_THREAD(0x00000001, THREAD, +- ("loading name=%s kind=%d (avail_mem=" UINT64_FORMAT "K)", +- the_class->external_name(), _class_load_kind, +- os::available_memory() >> 10)); +- +- ClassFileStream st((u1*) _class_defs[i].class_bytes, +- _class_defs[i].class_byte_count, (char *)"__VM_RedefineClasses__"); +- +- // Parse the stream. +- Handle the_class_loader(THREAD, the_class->class_loader()); +- Handle protection_domain(THREAD, the_class->protection_domain()); +- // Set redefined class handle in JvmtiThreadState class. +- // This redefined class is sent to agent event handler for class file +- // load hook event. +- state->set_class_being_redefined(&the_class, _class_load_kind); +- +- klassOop k = SystemDictionary::parse_stream(the_class_sym, +- the_class_loader, +- protection_domain, +- &st, +- THREAD); +- // Clear class_being_redefined just to be sure. +- state->clear_class_being_redefined(); +- +- // TODO: if this is retransform, and nothing changed we can skip it +- +- instanceKlassHandle scratch_class (THREAD, k); +- +- if (HAS_PENDING_EXCEPTION) { +- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); +- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark +- RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("parse_stream exception: '%s'", +- ex_name->as_C_string())); +- CLEAR_PENDING_EXCEPTION; +- +- if (ex_name == vmSymbols::java_lang_UnsupportedClassVersionError()) { +- return JVMTI_ERROR_UNSUPPORTED_VERSION; +- } else if (ex_name == vmSymbols::java_lang_ClassFormatError()) { +- return JVMTI_ERROR_INVALID_CLASS_FORMAT; +- } else if (ex_name == vmSymbols::java_lang_ClassCircularityError()) { +- return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; +- } else if (ex_name == vmSymbols::java_lang_NoClassDefFoundError()) { +- // The message will be "XXX (wrong name: YYY)" +- return JVMTI_ERROR_NAMES_DONT_MATCH; +- } else if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { +- return JVMTI_ERROR_OUT_OF_MEMORY; +- } else { // Just in case more exceptions can be thrown.. +- return JVMTI_ERROR_FAILS_VERIFICATION; + ////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Check interfaces + @@ -5949,13 +6043,22 @@ index 295ed86..fdfc6f4 100644 + RC_TRACE(0x00000002, ("Subtype changed of interface %s", + old_interface->name()->as_C_string())); + old_interface->set_subtype_changed(true); -+ } -+ } - } - -- 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 + } + } +- +- // Ensure class is linked before redefine +- if (!the_class->is_linked()) { +- the_class->link_class(THREAD); +- if (HAS_PENDING_EXCEPTION) { +- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); +- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark +- RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("link_class exception: '%s'", +- ex_name->as_C_string())); +- CLEAR_PENDING_EXCEPTION; +- if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { +- return JVMTI_ERROR_OUT_OF_MEMORY; ++ } ++ + // Interfaces added? + objArrayOop new_interfaces = new_class->transitive_interfaces(); + for (i = 0; i<new_interfaces->length(); i++) { @@ -5964,25 +6067,16 @@ index 295ed86..fdfc6f4 100644 + RC_TRACE(0x00000002, ("Added interface %s", + ((klassOop)new_interfaces->obj_at(i))->klass_part()->name()->as_C_string())); + } - } - -- 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 ++ } ++ ++ + // Check whether class modifiers are the same. + jushort old_flags = (jushort) the_class->access_flags().get_flags(); + jushort new_flags = (jushort) new_class->access_flags().get_flags(); + if (old_flags != new_flags) { + // TODO (tw): Can this have any effects? - } - -- return true; // made it through the gauntlet; this is our special case --} // end is_unresolved_class_mismatch() ++ } ++ + // Check if the number, names, types and order of fields declared in these classes + // are the same. + JavaFieldStream old_fs(the_class); @@ -6007,15 +6101,11 @@ index 295ed86..fdfc6f4 100644 + result = result | Klass::ModifyInstances; + } + } - ++ + if (!old_fs.done() || !new_fs.done()) { + result = result | Klass::ModifyInstances; + } - --// Returns true if the current mismatch is due to a resolved/unresolved --// string pair. Otherwise, returns false. --bool VM_RedefineClasses::is_unresolved_string_mismatch(constantPoolHandle cp1, -- int index1, constantPoolHandle cp2, int index2) { ++ + // 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 @@ -6037,22 +6127,14 @@ index 295ed86..fdfc6f4 100644 + objArrayHandle k_new_methods(new_class->methods()); + int n_old_methods = k_old_methods->length(); + int n_new_methods = k_new_methods->length(); - -- jbyte t1 = cp1->tag_at(index1).value(); -- if (t1 != JVM_CONSTANT_String && t1 != JVM_CONSTANT_UnresolvedString) { -- return false; // wrong entry type; not our special case -- } ++ + int ni = 0; + int oi = 0; + while (true) { + methodOop k_old_method; + methodOop k_new_method; + enum { matched, added, deleted, undetermined } method_was = undetermined; - -- jbyte t2 = cp2->tag_at(index2).value(); -- if (t2 != JVM_CONSTANT_String && t2 != JVM_CONSTANT_UnresolvedString) { -- return false; // wrong entry type; not our special case -- } ++ + if (oi >= n_old_methods) { + if (ni >= n_new_methods) { + break; // we've looked at everything, done @@ -6073,7 +6155,8 @@ index 295ed86..fdfc6f4 100644 + // or deleted + if (k_old_method->name()->fast_compare(k_new_method->name()) > 0) { + method_was = added; -+ } else { + } else { +- return JVMTI_ERROR_INTERNAL; + method_was = deleted; + } + } else if (k_old_method->signature() == k_new_method->signature()) { @@ -6099,21 +6182,23 @@ index 295ed86..fdfc6f4 100644 + break; + } + } - -- if (t1 == t2) { -- return false; // not a mismatch; not our special case -- } ++ + if (nj >= n_new_methods) { + // reached the end without a match; so method was deleted + method_was = deleted; -+ } -+ } -+ } + } + } + } -- char *s1 = cp1->string_at_noresolve(index1); -- char *s2 = cp2->string_at_noresolve(index2); -- if (strcmp(s1, s2) != 0) { -- return false; // strings don't match; not our special case +- // 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 +- // the_class to scratch_class. In particular, we don't have to +- // modify JNI GetSuperclass() and thus won't change its performance. +- jvmtiError res = compare_and_normalize_class_versions(the_class, +- scratch_class); +- if (res != JVMTI_ERROR_NONE) { +- return res; + switch (method_was) { + case matched: + // methods match, be sure modifiers do too @@ -6122,8 +6207,32 @@ index 295ed86..fdfc6f4 100644 + if ((old_flags ^ new_flags) & ~(JVM_ACC_NATIVE)) { + // (tw) Can this have any effects? Probably yes on vtables? + result = result | Klass::ModifyClass; -+ } -+ { + } +- +- // 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 +- // the_class to scratch_class in the JVM_* functions called by the +- // verifier. Please, refer to jvmtiThreadState.hpp for the detailed +- // description. +- RedefineVerifyMark rvm(&the_class, &scratch_class, state); +- Verifier::verify( +- scratch_class, Verifier::ThrowException, true, THREAD); +- } +- +- if (HAS_PENDING_EXCEPTION) { +- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); +- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark +- RC_TRACE_WITH_THREAD(0x00000002, THREAD, +- ("verify_byte_codes exception: '%s'", ex_name->as_C_string())); +- CLEAR_PENDING_EXCEPTION; +- if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { +- return JVMTI_ERROR_OUT_OF_MEMORY; +- } else { +- // tell the caller the bytecodes are bad +- return JVMTI_ERROR_FAILS_VERIFICATION; + u2 new_num = k_new_method->method_idnum(); + u2 old_num = k_old_method->method_idnum(); + if (new_num != old_num) { @@ -6137,8 +6246,12 @@ index 295ed86..fdfc6f4 100644 + new_num, + old_num)); + // swap_all_method_annotations(old_num, new_num, new_class); -+ } -+ } + } + } +- +- res = merge_cp_and_rewrite(the_class, scratch_class, THREAD); +- if (res != JVMTI_ERROR_NONE) { +- return res; + 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)); @@ -6155,13 +6268,32 @@ index 295ed86..fdfc6f4 100644 + ) { + // new methods must be private + result = result | Klass::ModifyClass; -+ } + } +- +- 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); + { + u2 num = the_class->next_method_idnum(); + if (num == constMethodOopDesc::UNSET_IDNUM) { + // cannot add any more methods + result = result | Klass::ModifyClass; -+ } + } +- +- if (HAS_PENDING_EXCEPTION) { +- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); +- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark +- RC_TRACE_WITH_THREAD(0x00000002, THREAD, +- ("verify_byte_codes post merge-CP exception: '%s'", +- ex_name->as_C_string())); +- CLEAR_PENDING_EXCEPTION; +- if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { +- return JVMTI_ERROR_OUT_OF_MEMORY; +- } else { +- // tell the caller that constant pool merging screwed up +- return JVMTI_ERROR_INTERNAL; + u2 new_num = k_new_method->method_idnum(); + methodOop idnum_owner = new_class->method_with_idnum(num); + if (idnum_owner != NULL) { @@ -6192,294 +6324,118 @@ index 295ed86..fdfc6f4 100644 + default: + ShouldNotReachHere(); + } - } - -- return true; // made it through the gauntlet; this is our special case --} // end is_unresolved_string_mismatch() ++ } ++ + 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; + } - --jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) { -- // For consistency allocate memory using os::malloc wrapper. -- _scratch_classes = (instanceKlassHandle *) -- os::malloc(sizeof(instanceKlassHandle) * _class_count); -- if (_scratch_classes == NULL) { -- return JVMTI_ERROR_OUT_OF_MEMORY; ++ + methodHandle instanceTransformerMethod(new_class->find_method(vmSymbols::transformer_name(), vmSymbols::void_method_signature())); + if (!instanceTransformerMethod.is_null() && !instanceTransformerMethod->is_static()) { + result |= Klass::HasInstanceTransformer; - } - -- ResourceMark rm(THREAD); ++ } ++ + // (tw) Check method bodies to be able to return NoChange? + return result; +} - -- JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current()); -- // state can only be NULL if the current thread is exiting which -- // should not happen since we're trying to do a RedefineClasses -- guarantee(state != NULL, "exiting thread calling load_new_class_versions"); -- for (int i = 0; i < _class_count; i++) { -- oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass); -- // classes for primitives cannot be redefined -- if (!is_modifiable_class(mirror)) { -- return JVMTI_ERROR_UNMODIFIABLE_CLASS; -- } -- klassOop the_class_oop = java_lang_Class::as_klassOop(mirror); -- instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop); -- Symbol* the_class_sym = the_class->name(); ++ +void VM_RedefineClasses::calculate_instance_update_information(klassOop new_version) { - -- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark -- RC_TRACE_WITH_THREAD(0x00000001, THREAD, -- ("loading name=%s kind=%d (avail_mem=" UINT64_FORMAT "K)", -- the_class->external_name(), _class_load_kind, -- os::available_memory() >> 10)); ++ + class UpdateFieldsEvolutionClosure : public FieldEvolutionClosure { - -- ClassFileStream st((u1*) _class_defs[i].class_bytes, -- _class_defs[i].class_byte_count, (char *)"__VM_RedefineClasses__"); ++ + private: - -- // Parse the stream. -- Handle the_class_loader(THREAD, the_class->class_loader()); -- Handle protection_domain(THREAD, the_class->protection_domain()); -- // Set redefined class handle in JvmtiThreadState class. -- // This redefined class is sent to agent event handler for class file -- // load hook event. -- state->set_class_being_redefined(&the_class, _class_load_kind); ++ + GrowableArray<int> info; + int curPosition; + bool copy_backwards; - -- klassOop k = SystemDictionary::parse_stream(the_class_sym, -- the_class_loader, -- protection_domain, -- &st, -- THREAD); -- // Clear class_being_redefined just to be sure. -- state->clear_class_being_redefined(); ++ + public: - -- // TODO: if this is retransform, and nothing changed we can skip it -- -- instanceKlassHandle scratch_class (THREAD, k); -- -- if (HAS_PENDING_EXCEPTION) { -- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); -- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark -- RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("parse_stream exception: '%s'", -- ex_name->as_C_string())); -- CLEAR_PENDING_EXCEPTION; -- -- if (ex_name == vmSymbols::java_lang_UnsupportedClassVersionError()) { -- return JVMTI_ERROR_UNSUPPORTED_VERSION; -- } else if (ex_name == vmSymbols::java_lang_ClassFormatError()) { -- return JVMTI_ERROR_INVALID_CLASS_FORMAT; -- } else if (ex_name == vmSymbols::java_lang_ClassCircularityError()) { -- return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; -- } else if (ex_name == vmSymbols::java_lang_NoClassDefFoundError()) { -- // The message will be "XXX (wrong name: YYY)" -- return JVMTI_ERROR_NAMES_DONT_MATCH; -- } else if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { -- return JVMTI_ERROR_OUT_OF_MEMORY; -- } else { // Just in case more exceptions can be thrown.. -- return JVMTI_ERROR_FAILS_VERIFICATION; -- } -- } -- -- // Ensure class is linked before redefine -- if (!the_class->is_linked()) { -- the_class->link_class(THREAD); -- if (HAS_PENDING_EXCEPTION) { -- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); -- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark -- RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("link_class exception: '%s'", -- ex_name->as_C_string())); -- CLEAR_PENDING_EXCEPTION; -- if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { -- return JVMTI_ERROR_OUT_OF_MEMORY; -- } else { -- return JVMTI_ERROR_INTERNAL; -- } -- } ++ + bool does_copy_backwards() { + return copy_backwards; - } - -- // 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 -- // the_class to scratch_class. In particular, we don't have to -- // modify JNI GetSuperclass() and thus won't change its performance. -- jvmtiError res = compare_and_normalize_class_versions(the_class, -- scratch_class); -- if (res != JVMTI_ERROR_NONE) { -- return res; -- } ++ } ++ + UpdateFieldsEvolutionClosure(klassOop klass) { - -- // 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 -- // the_class to scratch_class in the JVM_* functions called by the -- // verifier. Please, refer to jvmtiThreadState.hpp for the detailed -- // description. -- RedefineVerifyMark rvm(&the_class, &scratch_class, state); -- Verifier::verify( -- scratch_class, Verifier::ThrowException, true, THREAD); -- } -- -- if (HAS_PENDING_EXCEPTION) { -- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); -- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark -- RC_TRACE_WITH_THREAD(0x00000002, THREAD, -- ("verify_byte_codes exception: '%s'", ex_name->as_C_string())); -- CLEAR_PENDING_EXCEPTION; -- if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { -- return JVMTI_ERROR_OUT_OF_MEMORY; -- } else { -- // tell the caller the bytecodes are bad -- return JVMTI_ERROR_FAILS_VERIFICATION; ++ + int base_offset = instanceOopDesc::base_offset_in_bytes(); + + if (klass->klass_part()->newest_version() == SystemDictionary::Reference_klass()->klass_part()->newest_version()) { + base_offset += java_lang_ref_Reference::number_of_fake_oop_fields*size_of_type(T_OBJECT); - } ++ } + + info.append(base_offset); + info.append(0); + curPosition = base_offset; + copy_backwards = false; - } - -- res = merge_cp_and_rewrite(the_class, scratch_class, THREAD); -- if (res != JVMTI_ERROR_NONE) { -- return res; ++ } ++ + GrowableArray<int> &finish() { + info.append(0); + return info; - } - -- 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); ++ } ++ + virtual void do_new_field(fieldDescriptor* fd){ + int alignment = fd->offset() - curPosition; + if (alignment > 0) { + // This field was aligned, so we need to make sure that we fill the gap + fill(alignment); - } - -- if (HAS_PENDING_EXCEPTION) { -- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); -- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark -- RC_TRACE_WITH_THREAD(0x00000002, THREAD, -- ("verify_byte_codes post merge-CP exception: '%s'", -- ex_name->as_C_string())); -- CLEAR_PENDING_EXCEPTION; -- if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { -- return JVMTI_ERROR_OUT_OF_MEMORY; -- } else { -- // tell the caller that constant pool merging screwed up -- return JVMTI_ERROR_INTERNAL; -- } -- } ++ } ++ + int size = size_of_type(fd->field_type()); + fill(size); - } - -- Rewriter::rewrite(scratch_class, THREAD); -- if (!HAS_PENDING_EXCEPTION) { -- Rewriter::relocate_and_link(scratch_class, THREAD); -- } -- if (HAS_PENDING_EXCEPTION) { -- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); -- CLEAR_PENDING_EXCEPTION; -- if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { -- return JVMTI_ERROR_OUT_OF_MEMORY; ++ } ++ + private: + + void fill(int size) { + if (info.length() > 0 && info.at(info.length() - 1) < 0) { + (*info.adr_at(info.length() - 1)) -= size; - } else { -- return JVMTI_ERROR_INTERNAL; ++ } else { + info.append(-size); - } ++ } + + curPosition += size; - } - -- _scratch_classes[i] = scratch_class; ++ } ++ + int size_of_type(BasicType type) { + int size = 0; + switch(type) { + case T_BOOLEAN: + size = sizeof(jboolean); + break; - -- // 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)); -- } ++ + case T_CHAR: + size = (sizeof(jchar)); + break; - -- return JVMTI_ERROR_NONE; --} ++ + case T_FLOAT: + size = (sizeof(jfloat)); + break; - ++ + case T_DOUBLE: + size = (sizeof(jdouble)); + break; - --// 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, -- int old_index, int new_index) { -- if (find_new_index(old_index) != 0) { -- // old_index is already mapped -- return; -- } ++ + case T_BYTE: + size = (sizeof(jbyte)); + break; - -- if (old_index == new_index) { -- // no mapping is needed -- return; -- } ++ + case T_SHORT: + size = (sizeof(jshort)); + break; - -- _index_map_p->at_put(old_index, new_index); -- _index_map_count++; ++ + case T_INT: + size = (sizeof(jint)); + break; - -- 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() ++ + case T_LONG: + size = (sizeof(jlong)); + break; - ++ + case T_OBJECT: + case T_ARRAY: + if (UseCompressedOops) { @@ -6488,7 +6444,257 @@ index 295ed86..fdfc6f4 100644 + size = (sizeof(oop)); + } + break; ++ ++ default: ++ ShouldNotReachHere(); ++ } ++ ++ assert(size > 0, ""); ++ return size; ++ ++ } ++ ++ public: ++ ++ virtual void do_old_field(fieldDescriptor* fd){} ++ ++ virtual void do_changed_field(fieldDescriptor* old_fd, fieldDescriptor *new_fd){ ++ ++ int alignment = new_fd->offset() - curPosition; ++ if (alignment > 0) { ++ // This field was aligned, so we need to make sure that we fill the gap ++ fill(alignment); ++ } ++ ++ assert(old_fd->field_type() == new_fd->field_type(), ""); ++ assert(curPosition == new_fd->offset(), "must be correct offset!"); ++ ++ int offset = old_fd->offset(); ++ int size = size_of_type(old_fd->field_type()); ++ ++ int prevEnd = -1; ++ if (info.length() > 0 && info.at(info.length() - 1) > 0) { ++ prevEnd = info.at(info.length() - 2) + info.at(info.length() - 1); ++ } ++ ++ if (prevEnd == offset) { ++ info.at_put(info.length() - 2, info.at(info.length() - 2) + size); ++ } else { ++ info.append(size); ++ info.append(offset); ++ } ++ ++ if (old_fd->offset() < new_fd->offset()) { ++ copy_backwards = true; ++ } ++ ++ transfer_special_access_flags(old_fd, new_fd); ++ ++ curPosition += size; ++ } ++ }; ++ ++ UpdateFieldsEvolutionClosure cl(new_version); ++ ((instanceKlass*)new_version->klass_part())->do_fields_evolution(&cl); ++ ++ GrowableArray<int> result = cl.finish(); ++ ((instanceKlass*)new_version->klass_part())->store_update_information(result); ++ ((instanceKlass*)new_version->klass_part())->set_copying_backwards(cl.does_copy_backwards()); ++ ++ if (RC_TRACE_ENABLED(0x00000002)) { ++ RC_TRACE(0x00000002, ("Instance update information for %s:", ++ new_version->klass_part()->name()->as_C_string())); ++ if (cl.does_copy_backwards()) { ++ RC_TRACE(0x00000002, ("\tDoes copy backwards!")); ++ } ++ for (int i=0; i<result.length(); i++) { ++ int curNum = result.at(i); ++ if (curNum < 0) { ++ RC_TRACE(0x00000002, ("\t%d CLEAN", curNum)); ++ } else if (curNum > 0) { ++ RC_TRACE(0x00000002, ("\t%d COPY from %d", curNum, result.at(i + 1))); ++ i++; ++ } else { ++ RC_TRACE(0x00000002, ("\tEND")); ++ } ++ } ++ } ++} ++ ++Symbol* VM_RedefineClasses::signature_to_class_name(Symbol* signature) { ++ assert(FieldType::is_obj(signature), ""); ++ return SymbolTable::new_symbol(signature->as_C_string() + 1, signature->utf8_length() - 2, Thread::current()); ++} ++ ++void VM_RedefineClasses::calculate_type_check_information(klassOop klass) { ++ if (klass->klass_part()->is_redefining()) { ++ klass = klass->klass_part()->old_version(); ++ } ++ ++ // We found an instance klass! ++ instanceKlass *cur_instance_klass = instanceKlass::cast(klass); ++ GrowableArray< Pair<int, klassOop> > type_check_information; ++ ++ class MyFieldClosure : public FieldClosure { ++ ++ public: ++ ++ GrowableArray< Pair<int, klassOop> > *_arr; ++ ++ MyFieldClosure(GrowableArray< Pair<int, klassOop> > *arr) { ++ _arr = arr; ++ } ++ ++ virtual void do_field(fieldDescriptor* fd) { ++ if (fd->field_type() == T_OBJECT) { ++ Symbol* signature = fd->signature(); ++ if (FieldType::is_obj(signature)) { ++ Symbol* name = signature_to_class_name(signature); ++ klassOop field_klass; ++ if (is_field_dangerous(name, fd, field_klass)) { ++ RC_TRACE(0x00000002, ("Found dangerous field %s in klass %s of type %s", ++ fd->name()->as_C_string(), ++ fd->field_holder()->klass_part()->name()->as_C_string(), ++ name->as_C_string())); ++ _arr->append(Pair<int, klassOop>(fd->offset(), field_klass->klass_part()->newest_version())); ++ } ++ } ++ ++ // Array fields can never be a problem! ++ } ++ } ++ ++ bool is_field_dangerous(Symbol* klass_name, fieldDescriptor *fd, klassOop &field_klass) { ++ field_klass = SystemDictionary::find(klass_name, fd->field_holder()->klass_part()->class_loader(), ++ fd->field_holder()->klass_part()->protection_domain(), Thread::current()); ++ if(field_klass != NULL) { ++ if (field_klass->klass_part()->is_redefining()) { ++ field_klass = field_klass->klass_part()->old_version(); ++ } ++ if (field_klass->klass_part()->has_subtype_changed()) { ++ return true; ++ } ++ } ++ return false; ++ } ++ }; ++ ++ MyFieldClosure fieldClosure(&type_check_information); ++ cur_instance_klass->do_nonstatic_fields(&fieldClosure); ++ ++ if (type_check_information.length() > 0) { ++ type_check_information.append(Pair<int, klassOop>(-1, NULL)); ++ cur_instance_klass->store_type_check_information(type_check_information); ++ } ++} ++ ++bool VM_RedefineClasses::check_field_value_types() { ++ ++ Thread *THREAD = Thread::current(); ++ class CheckFieldTypesClosure : public ObjectClosure { ++ ++ private: ++ ++ bool _result; ++ ++ public: ++ ++ CheckFieldTypesClosure() { ++ _result = true; ++ } ++ ++ bool result() { return _result; } ++ ++ virtual void do_object(oop obj) { ++ ++ if (!_result) { ++ return; ++ } ++ ++ if (obj->is_objArray()) { ++ ++ objArrayOop array = objArrayOop(obj); ++ ++ klassOop element_klass = objArrayKlass::cast(array->klass())->element_klass(); ++ ++ if (element_klass->klass_part()->has_subtype_changed()) { ++ int length = array->length(); ++ for (int i=0; i<length; i++) { ++ oop element = array->obj_at(i); ++ if (element != NULL && element->blueprint()->newest_version()->klass_part()->is_redefining()) { ++ // Check subtype relationship to static type of array ++ if (!element->blueprint()->newest_version()->klass_part()->is_subtype_of(element_klass->klass_part()->newest_version())) { ++ RC_TRACE(0x00000001, ("Array value is INVALID - abort redefinition (static_type=%s, index=%d, dynamic_type=%s)", ++ element_klass->klass_part()->name()->as_C_string(), ++ i, ++ element->blueprint()->name()->as_C_string())); ++ _result = false; ++ break; ++ } ++ } ++ } ++ } ++ ++ } else { ++ Pair<int, klassOop> *cur = obj->klass()->klass_part()->type_check_information(); ++ if (cur != NULL) { ++ // Type check information exists for this oop ++ while ((*cur).left() != -1) { ++ check_field(obj, (*cur).left(), (*cur).right()); ++ cur++; ++ } + } + } + } +- Rewriter::rewrite(scratch_class, THREAD); +- if (!HAS_PENDING_EXCEPTION) { +- Rewriter::relocate_and_link(scratch_class, THREAD); +- } +- if (HAS_PENDING_EXCEPTION) { +- Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); +- CLEAR_PENDING_EXCEPTION; +- if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { +- return JVMTI_ERROR_OUT_OF_MEMORY; +- } else { +- return JVMTI_ERROR_INTERNAL; +- } +- } +- +- _scratch_classes[i] = scratch_class; +- +- // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark +- RC_TRACE_WITH_THREAD(0x00000001, THREAD, +- ("loaded name=%s (avail_mem=" UINT64_FORMAT "K)", +- the_class->external_name(), os::available_memory() >> 10)); +- } +- +- return JVMTI_ERROR_NONE; +-} +- +- +-// 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, +- int old_index, int new_index) { +- if (find_new_index(old_index) != 0) { +- // old_index is already mapped +- return; +- } +- +- if (old_index == new_index) { +- // no mapping is needed +- return; +- } +- +- _index_map_p->at_put(old_index, new_index); +- _index_map_count++; +- +- 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() +- +- -// 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 -// merge_cp_length_p. The entries in old_cp occupy the same locations @@ -6499,10 +6705,7 @@ index 295ed86..fdfc6f4 100644 -bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp, - constantPoolHandle scratch_cp, constantPoolHandle *merge_cp_p, - int *merge_cp_length_p, TRAPS) { -+ default: -+ ShouldNotReachHere(); -+ } - +- - if (merge_cp_p == NULL) { - assert(false, "caller must provide scatch constantPool"); - return false; // robustness @@ -6518,16 +6721,11 @@ index 295ed86..fdfc6f4 100644 - assert(false, "merge area too small"); - return false; // robustness - } -+ assert(size > 0, ""); -+ return size; - +- - RC_TRACE_WITH_THREAD(0x00010000, THREAD, - ("old_cp_len=%d, scratch_cp_len=%d", old_cp->length(), - scratch_cp->length())); -+ } -+ -+ public: - +- - { - // Pass 0: - // The old_cp is copied to *merge_cp_p; this means that any code @@ -6552,8 +6750,7 @@ index 295ed86..fdfc6f4 100644 - (*merge_cp_p)->unresolved_klass_at_put(old_i, - old_cp->klass_name_at(old_i)); - break; -+ virtual void do_old_field(fieldDescriptor* fd){} - +- - case JVM_CONSTANT_Double: - case JVM_CONSTANT_Long: - // just copy the entry to *merge_cp_p, but double and long take @@ -6561,33 +6758,24 @@ index 295ed86..fdfc6f4 100644 - constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0); - old_i++; - break; -+ virtual void do_changed_field(fieldDescriptor* old_fd, fieldDescriptor *new_fd){ - +- - default: - // just copy the entry to *merge_cp_p - constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0); - break; -+ int alignment = new_fd->offset() - curPosition; -+ if (alignment > 0) { -+ // This field was aligned, so we need to make sure that we fill the gap -+ fill(alignment); - } +- } - } // end for each old_cp entry - +- - // We don't need to sanity check that *merge_cp_length_p is within - // *merge_cp_p bounds since we have the minimum on-entry check above. - (*merge_cp_length_p) = old_i; - } -+ assert(old_fd->field_type() == new_fd->field_type(), ""); -+ assert(curPosition == new_fd->offset(), "must be correct offset!"); - +- - // merge_cp_len should be the same as old_cp->length() at this point - // so this trace message is really a "warm-and-breathing" message. - RC_TRACE_WITH_THREAD(0x00020000, THREAD, - ("after pass 0: merge_cp_len=%d", *merge_cp_length_p)); -+ int offset = old_fd->offset(); -+ int size = size_of_type(old_fd->field_type()); - +- - int scratch_i; // index into scratch_cp - { - // Pass 1a: @@ -6608,11 +6796,8 @@ index 295ed86..fdfc6f4 100644 - default: - increment = 1; - break; -+ int prevEnd = -1; -+ if (info.length() > 0 && info.at(info.length() - 1) > 0) { -+ prevEnd = info.at(info.length() - 2) + info.at(info.length() - 1); - } - +- } +- - bool match = scratch_cp->compare_entry_to(scratch_i, *merge_cp_p, - scratch_i, CHECK_0); - if (match) { @@ -6682,13 +6867,8 @@ index 295ed86..fdfc6f4 100644 - default: - increment = 1; - break; -+ if (prevEnd == offset) { -+ info.at_put(info.length() - 2, info.at(info.length() - 2) + size); -+ } else { -+ info.append(size); -+ info.append(offset); - } - +- } +- - int found_i = - scratch_cp->find_matching_entry(scratch_i, *merge_cp_p, CHECK_0); - if (found_i != 0) { @@ -6696,50 +6876,19 @@ index 295ed86..fdfc6f4 100644 - // just need a mapping entry. - map_index(scratch_cp, scratch_i, found_i); - continue; -+ if (old_fd->offset() < new_fd->offset()) { -+ copy_backwards = true; - } - +- } +- - // No match found so we have to append this entry and any unique - // referenced entries to *merge_cp_p. - append_entry(scratch_cp, scratch_i, merge_cp_p, merge_cp_length_p, - CHECK_0); -+ transfer_special_access_flags(old_fd, new_fd); -+ -+ curPosition += size; - } -+ }; -+ -+ UpdateFieldsEvolutionClosure cl(new_version); -+ ((instanceKlass*)new_version->klass_part())->do_fields_evolution(&cl); -+ -+ GrowableArray<int> result = cl.finish(); -+ ((instanceKlass*)new_version->klass_part())->store_update_information(result); -+ ((instanceKlass*)new_version->klass_part())->set_copying_backwards(cl.does_copy_backwards()); - +- } +- - RC_TRACE_WITH_THREAD(0x00020000, THREAD, - ("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d", - *merge_cp_length_p, scratch_i, _index_map_count)); -+ if (RC_TRACE_ENABLED(0x00000002)) { -+ RC_TRACE(0x00000002, ("Instance update information for %s:", -+ new_version->klass_part()->name()->as_C_string())); -+ if (cl.does_copy_backwards()) { -+ RC_TRACE(0x00000002, ("\tDoes copy backwards!")); -+ } -+ for (int i=0; i<result.length(); i++) { -+ int curNum = result.at(i); -+ if (curNum < 0) { -+ RC_TRACE(0x00000002, ("\t%d CLEAN", curNum)); -+ } else if (curNum > 0) { -+ RC_TRACE(0x00000002, ("\t%d COPY from %d", curNum, result.at(i + 1))); -+ i++; -+ } else { -+ RC_TRACE(0x00000002, ("\tEND")); -+ } -+ } - } -+} - +- } +- - return true; -} // end merge_constant_pools() - @@ -6780,23 +6929,12 @@ index 295ed86..fdfc6f4 100644 - // RedefineClasses() calls so just copy the orig_length() - // value. - merge_cp->set_orig_length(old_cp->orig_length()); -+Symbol* VM_RedefineClasses::signature_to_class_name(Symbol* signature) { -+ assert(FieldType::is_obj(signature), ""); -+ return SymbolTable::new_symbol(signature->as_C_string() + 1, signature->utf8_length() - 2, Thread::current()); -+} -+ -+void VM_RedefineClasses::calculate_type_check_information(klassOop klass) { -+ if (klass->klass_part()->is_redefining()) { -+ klass = klass->klass_part()->old_version(); - } - +- } +- - ResourceMark rm(THREAD); - _index_map_count = 0; - _index_map_p = new intArray(scratch_cp->length(), -1); -+ // We found an instance klass! -+ instanceKlass *cur_instance_klass = instanceKlass::cast(klass); -+ GrowableArray< Pair<int, klassOop> > type_check_information; - +- - bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp, - &merge_cp_length, THREAD); - if (!result) { @@ -6846,15 +6984,7 @@ index 295ed86..fdfc6f4 100644 - // drop local ref to the merged constant pool - merge_cp()->set_is_conc_safe(true); - merge_cp = constantPoolHandle(); -+ class MyFieldClosure : public FieldClosure { -+ -+ public: -+ -+ GrowableArray< Pair<int, klassOop> > *_arr; -+ -+ MyFieldClosure(GrowableArray< Pair<int, klassOop> > *arr) { -+ _arr = arr; - } +- } - } else { - if (RC_TRACE_ENABLED(0x00040000)) { - // don't want to loop unless we are tracing @@ -6866,152 +6996,6 @@ index 295ed86..fdfc6f4 100644 - RC_TRACE_WITH_THREAD(0x00040000, THREAD, - ("index_map[%d]: old=%d new=%d", count, i, value)); - count++; -+ -+ virtual void do_field(fieldDescriptor* fd) { -+ if (fd->field_type() == T_OBJECT) { -+ Symbol* signature = fd->signature(); -+ if (FieldType::is_obj(signature)) { -+ Symbol* name = signature_to_class_name(signature); -+ klassOop field_klass; -+ if (is_field_dangerous(name, fd, field_klass)) { -+ RC_TRACE(0x00000002, ("Found dangerous field %s in klass %s of type %s", -+ fd->name()->as_C_string(), -+ fd->field_holder()->klass_part()->name()->as_C_string(), -+ name->as_C_string())); -+ _arr->append(Pair<int, klassOop>(fd->offset(), field_klass->klass_part()->newest_version())); -+ } - } -+ -+ // Array fields can never be a problem! - } - } - -- // 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)) { -- return JVMTI_ERROR_INTERNAL; -+ bool is_field_dangerous(Symbol* klass_name, fieldDescriptor *fd, klassOop &field_klass) { -+ field_klass = SystemDictionary::find(klass_name, fd->field_holder()->klass_part()->class_loader(), -+ fd->field_holder()->klass_part()->protection_domain(), Thread::current()); -+ if(field_klass != NULL) { -+ if (field_klass->klass_part()->is_redefining()) { -+ field_klass = field_klass->klass_part()->old_version(); -+ } -+ if (field_klass->klass_part()->has_subtype_changed()) { -+ return true; -+ } -+ } -+ return false; - } -+ }; -+ -+ MyFieldClosure fieldClosure(&type_check_information); -+ cur_instance_klass->do_nonstatic_fields(&fieldClosure); - -- // Replace the new constant pool with a shrunken copy of the -- // merged constant pool so now the rewritten bytecodes have -- // valid references; the previous new constant pool will get -- // GCed. -- set_new_constant_pool(scratch_class, merge_cp, merge_cp_length, true, -- THREAD); -- merge_cp()->set_is_conc_safe(true); -+ if (type_check_information.length() > 0) { -+ type_check_information.append(Pair<int, klassOop>(-1, NULL)); -+ cur_instance_klass->store_type_check_information(type_check_information); - } -- assert(old_cp()->is_conc_safe(), "Just checking"); -- assert(scratch_cp()->is_conc_safe(), "Just checking"); -+} - -- return JVMTI_ERROR_NONE; --} // end merge_cp_and_rewrite() -+bool VM_RedefineClasses::check_field_value_types() { - -+ Thread *THREAD = Thread::current(); -+ class CheckFieldTypesClosure : public ObjectClosure { - --// Rewrite constant pool references in klass scratch_class. --bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class, -- TRAPS) { -+ private: - -- // rewrite constant pool references in the methods: -- if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) { -- // propagate failure back to caller -- return false; -- } -+ bool _result; - -- // rewrite constant pool references in the class_annotations: -- if (!rewrite_cp_refs_in_class_annotations(scratch_class, THREAD)) { -- // propagate failure back to caller -- return false; -- } -+ public: - -- // rewrite constant pool references in the fields_annotations: -- if (!rewrite_cp_refs_in_fields_annotations(scratch_class, THREAD)) { -- // propagate failure back to caller -- return false; -- } -+ CheckFieldTypesClosure() { -+ _result = true; -+ } - -- // rewrite constant pool references in the methods_annotations: -- if (!rewrite_cp_refs_in_methods_annotations(scratch_class, THREAD)) { -- // propagate failure back to caller -- return false; -- } -+ bool result() { return _result; } - -- // rewrite constant pool references in the methods_parameter_annotations: -- if (!rewrite_cp_refs_in_methods_parameter_annotations(scratch_class, -- THREAD)) { -- // propagate failure back to caller -- return false; -+ virtual void do_object(oop obj) { -+ -+ if (!_result) { -+ return; -+ } -+ -+ if (obj->is_objArray()) { -+ -+ objArrayOop array = objArrayOop(obj); -+ -+ klassOop element_klass = objArrayKlass::cast(array->klass())->element_klass(); -+ -+ if (element_klass->klass_part()->has_subtype_changed()) { -+ int length = array->length(); -+ for (int i=0; i<length; i++) { -+ oop element = array->obj_at(i); -+ if (element != NULL && element->blueprint()->newest_version()->klass_part()->is_redefining()) { -+ // Check subtype relationship to static type of array -+ if (!element->blueprint()->newest_version()->klass_part()->is_subtype_of(element_klass->klass_part()->newest_version())) { -+ RC_TRACE(0x00000001, ("Array value is INVALID - abort redefinition (static_type=%s, index=%d, dynamic_type=%s)", -+ element_klass->klass_part()->name()->as_C_string(), -+ i, -+ element->blueprint()->name()->as_C_string())); -+ _result = false; -+ break; -+ } -+ } -+ } -+ } -+ -+ } else { -+ Pair<int, klassOop> *cur = obj->klass()->klass_part()->type_check_information(); -+ if (cur != NULL) { -+ // Type check information exists for this oop -+ while ((*cur).left() != -1) { -+ check_field(obj, (*cur).left(), (*cur).right()); -+ cur++; -+ } -+ } -+ } -+ } -+ + void check_field(oop obj, int offset, klassOop static_type) { + oop field_value = obj->obj_field(offset); + if (field_value != NULL) { @@ -7031,9 +7015,14 @@ index 295ed86..fdfc6f4 100644 + offset, + field_value->klass()->klass_part()->name()->as_C_string())); + _result = false; -+ } -+ } -+ } + } + } + } +- +- // 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)) { +- return JVMTI_ERROR_INTERNAL; + }; + + CheckFieldTypesClosure myObjectClosure; @@ -7053,23 +7042,16 @@ index 295ed86..fdfc6f4 100644 + CompactingPermGenGen* gen = (CompactingPermGenGen*)gch->perm_gen(); + gen->ro_space()->object_iterate(&myObjectClosure); + gen->rw_space()->object_iterate(&myObjectClosure); - } - -- // rewrite constant pool references in the methods_default_annotations: -- if (!rewrite_cp_refs_in_methods_default_annotations(scratch_class, -- THREAD)) { -- // propagate failure back to caller -- return false; ++ } ++ + return myObjectClosure.result(); +} + +void VM_RedefineClasses::clear_type_check_information(klassOop k) { + if (k->klass_part()->is_redefining()) { + k = k->klass_part()->old_version(); - } - -- return true; --} // end rewrite_cp_refs() ++ } ++ + // We found an instance klass! + instanceKlass *cur_instance_klass = instanceKlass::cast(k); + cur_instance_klass->clear_type_check_information(); @@ -7145,23 +7127,40 @@ index 295ed86..fdfc6f4 100644 + iframe->set_method(jvf->method()->new_version(), bci); + RC_TRACE(0x00000002, ("Updated method to newer version")); + assert(jvf->method()->new_version() == NULL, "must be latest version"); - ++ + } + } + } + vf = vf->sender(); + } -+ } + } --// Rewrite constant pool references in the methods. --bool VM_RedefineClasses::rewrite_cp_refs_in_methods( -- instanceKlassHandle scratch_class, TRAPS) { +- // Replace the new constant pool with a shrunken copy of the +- // merged constant pool so now the rewritten bytecodes have +- // valid references; the previous new constant pool will get +- // GCed. +- set_new_constant_pool(scratch_class, merge_cp, merge_cp_length, true, +- THREAD); +- merge_cp()->set_is_conc_safe(true); + // Advance to next thread + java_thread = java_thread->next(); -+ } + } +- assert(old_cp()->is_conc_safe(), "Just checking"); +- assert(scratch_cp()->is_conc_safe(), "Just checking"); +- +- return JVMTI_ERROR_NONE; +-} // end merge_cp_and_rewrite() +- +- +-// Rewrite constant pool references in klass scratch_class. +-bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class, +- TRAPS) { +- +- // rewrite constant pool references in the methods: +- if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) { +- // propagate failure back to caller +} - -- objArrayHandle methods(THREAD, scratch_class->methods()); ++ +void VM_RedefineClasses::method_forwarding() { + + int forwarding_count = 0; @@ -7244,22 +7243,11 @@ index 295ed86..fdfc6f4 100644 + vf = vf->sender(); + } + } - -- if (methods.is_null() || methods->length() == 0) { -- // no methods so nothing to do -- return true; ++ + // Advance to next thread + java_thread = java_thread->next(); - } - -- // rewrite constant pool references in the methods: -- for (int i = methods->length() - 1; i >= 0; i--) { -- methodHandle method(THREAD, (methodOop)methods->obj_at(i)); -- methodHandle new_method; -- rewrite_cp_refs_in_method(method, &new_method, CHECK_false); -- if (!new_method.is_null()) { -- // the method has been replaced so save the new method version -- methods->obj_at_put(i, new_method()); ++ } ++ + RC_TRACE(0x00000001, ("Method forwarding applied to %d methods", + forwarding_count)); +} @@ -7392,112 +7380,45 @@ index 295ed86..fdfc6f4 100644 + } + vf = vf->sender(); + } - } ++ } + + // Advance to next thread + java_thread = java_thread->next(); - } - - return true; - } - ++ } ++ ++ return true; ++} ++ +bool VM_RedefineClasses::check_method(methodOop method) { - --// Rewrite constant pool references in the specific method. This code --// was adapted from Rewriter::rewrite_method(). --void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method, -- methodHandle *new_method_p, TRAPS) { - -- *new_method_p = methodHandle(); // default is no new method ++ ++ + return true; +} - -- // We cache a pointer to the bytecodes here in code_base. If GC -- // moves the methodOop, then the bytecodes will also move which -- // will likely cause a crash. We create a No_Safepoint_Verifier -- // object to detect whether we pass a possible safepoint in this -- // code block. -- No_Safepoint_Verifier nsv; ++ +// Warning: destroys redefinition level values of klasses. +bool VM_RedefineClasses::check_loaded_methods() { - -- // Bytecodes and their length -- address code_base = method->code_base(); -- int code_length = method->code_size(); ++ + class CheckLoadedMethodsClosure : public ObjectClosure { - -- int bc_length; -- for (int bci = 0; bci < code_length; bci += bc_length) { -- address bcp = code_base + bci; -- Bytecodes::Code c = (Bytecodes::Code)(*bcp); ++ + private: + + bool _result; + GrowableArray<klassOop> *_dangerous_klasses; - -- bc_length = Bytecodes::length_for(c); -- if (bc_length == 0) { -- // More complicated bytecodes report a length of zero so -- // we have to try again a slightly different way. -- bc_length = Bytecodes::length_at(method(), bcp); ++ + public: + CheckLoadedMethodsClosure(GrowableArray<klassOop> *dangerous_klasses) { + _result = true; + _dangerous_klasses = dangerous_klasses; - } - -- assert(bc_length != 0, "impossible bytecode length"); ++ } ++ + bool result() { + return _result; + } - -- switch (c) { -- case Bytecodes::_ldc: -- { -- int cp_index = *(bcp + 1); -- int new_index = find_new_index(cp_index); ++ + bool is_class_dangerous(klassOop k) { + return k->klass_part()->newest_version()->klass_part()->check_redefinition_flag(Klass::RemoveSuperType); + } - -- if (StressLdcRewrite && new_index == 0) { -- // If we are stressing ldc -> ldc_w rewriting, then we -- // always need a new_index value. -- new_index = cp_index; -- } -- if (new_index != 0) { -- // the original index is mapped so we have more work to do -- if (!StressLdcRewrite && new_index <= max_jubyte) { -- // The new value can still use ldc instead of ldc_w -- // unless we are trying to stress ldc -> ldc_w rewriting -- RC_TRACE_WITH_THREAD(0x00080000, THREAD, -- ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c), -- bcp, cp_index, new_index)); -- *(bcp + 1) = new_index; -- } else { -- RC_TRACE_WITH_THREAD(0x00080000, THREAD, -- ("%s->ldc_w@" INTPTR_FORMAT " old=%d, new=%d", -- Bytecodes::name(c), bcp, cp_index, new_index)); -- // the new value needs ldc_w instead of ldc -- u_char inst_buffer[4]; // max instruction size is 4 bytes -- bcp = (address)inst_buffer; -- // construct new instruction sequence -- *bcp = Bytecodes::_ldc_w; -- bcp++; -- // Rewriter::rewrite_method() does not rewrite ldc -> ldc_w. -- // See comment below for difference between put_Java_u2() -- // and put_native_u2(). -- Bytes::put_Java_u2(bcp, new_index); -- -- Relocator rc(method, NULL /* no RelocatorListener needed */); -- methodHandle m; -- { -- Pause_No_Safepoint_Verifier pnsv(&nsv); -- -- // ldc is 2 bytes and ldc_w is 3 bytes -- m = rc.insert_space_at(bci, 3, inst_buffer, THREAD); -- if (m.is_null() || HAS_PENDING_EXCEPTION) { -- guarantee(false, "insert_space_at() failed"); ++ + bool can_be_affected(instanceKlass *klass) { + + constantPoolOop cp = klass->constants(); @@ -7564,60 +7485,13 @@ index 295ed86..fdfc6f4 100644 + } + + signatureStream.next(); - } ++ } + + } else if (is_type_signature_dangerous(symbol)) { + return true; - } ++ } + break; - -- // return the new method so that the caller can update -- // the containing class -- *new_method_p = method = m; -- // switch our bytecode processing loop from the old method -- // to the new method -- code_base = method->code_base(); -- code_length = method->code_size(); -- bcp = code_base + bci; -- c = (Bytecodes::Code)(*bcp); -- bc_length = Bytecodes::length_for(c); -- assert(bc_length != 0, "sanity check"); -- } // end we need ldc_w instead of ldc -- } // end if there is a mapped index -- } break; -- -- // these bytecodes have a two-byte constant pool index -- case Bytecodes::_anewarray : // fall through -- case Bytecodes::_checkcast : // fall through -- case Bytecodes::_getfield : // fall through -- case Bytecodes::_getstatic : // fall through -- case Bytecodes::_instanceof : // fall through -- case Bytecodes::_invokeinterface: // fall through -- case Bytecodes::_invokespecial : // fall through -- case Bytecodes::_invokestatic : // fall through -- case Bytecodes::_invokevirtual : // fall through -- case Bytecodes::_ldc_w : // fall through -- case Bytecodes::_ldc2_w : // fall through -- case Bytecodes::_multianewarray : // fall through -- case Bytecodes::_new : // fall through -- case Bytecodes::_putfield : // fall through -- case Bytecodes::_putstatic : -- { -- address p = bcp + 1; -- int cp_index = Bytes::get_Java_u2(p); -- int new_index = find_new_index(cp_index); -- if (new_index != 0) { -- // the original index is mapped so update w/ new value -- RC_TRACE_WITH_THREAD(0x00080000, THREAD, -- ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c), -- bcp, cp_index, new_index)); -- // Rewriter::rewrite_method() uses put_native_u2() in this -- // situation because it is reusing the constant pool index -- // location for a native index into the constantPoolCache. -- // Since we are updating the constant pool index prior to -- // verification and constantPoolCache initialization, we -- // need to keep the new index in Java byte order. -- Bytes::put_Java_u2(p, new_index); ++ + case JVM_CONSTANT_UnresolvedClass: + symbol = cp->unresolved_klass_at(i); + if (is_symbol_dangerous(symbol)) { @@ -7627,15 +7501,12 @@ index 295ed86..fdfc6f4 100644 + + default: + ShouldNotReachHere(); - } -- } break; ++ } + } + + return false; - } -- } // end for each bytecode --} // end rewrite_cp_refs_in_method() - ++ } ++ + bool is_type_signature_dangerous(Symbol* signature) { + // This must be a field type + if (FieldType::is_obj(signature)) { @@ -7712,39 +7583,26 @@ index 295ed86..fdfc6f4 100644 + }*/ + } + }; - --// Rewrite constant pool references in the class_annotations field. --bool VM_RedefineClasses::rewrite_cp_refs_in_class_annotations( -- instanceKlassHandle scratch_class, TRAPS) { ++ + // TODO: Check bytecodes in case of interface => class or class => interface etc.. - -- 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; ++ + GrowableArray<klassOop> dangerous_klasses; + for (int i=0; i<_new_classes->length(); i++) { + instanceKlassHandle handle = _new_classes->at(i); + if (handle->check_redefinition_flag(Klass::RemoveSuperType)) { + dangerous_klasses.append(handle()); + } - } - -- RC_TRACE_WITH_THREAD(0x02000000, THREAD, -- ("class_annotations length=%d", class_annotations->length())); ++ } ++ + CheckLoadedMethodsClosure checkLoadedMethodsClosure(&dangerous_klasses); + Thread::current()->set_pretend_new_universe(true); + SystemDictionary::classes_do(&checkLoadedMethodsClosure); + Thread::current()->set_pretend_new_universe(false); + - -- int byte_i = 0; // byte index into class_annotations -- return rewrite_cp_refs_in_annotations_typeArray(class_annotations, byte_i, -- THREAD); ++ + return checkLoadedMethodsClosure.result(); - } - ++} ++ +bool VM_RedefineClasses::check_type_consistency() { + + Universe::set_verify_in_progress(true); @@ -7755,75 +7613,55 @@ index 295ed86..fdfc6f4 100644 + if (!result) { + RC_TRACE(0x00000001, ("Aborting redefinition because of wrong field or array element value!")); + Universe::set_verify_in_progress(false); -+ return false; -+ } -+ + return false; + } + +- // rewrite constant pool references in the class_annotations: +- if (!rewrite_cp_refs_in_class_annotations(scratch_class, THREAD)) { +- // propagate failure back to caller + result = check_method_stacks(); + if (!result) { + RC_TRACE(0x00000001, ("Aborting redefinition because of wrong value on the stack")); + Universe::set_verify_in_progress(false); -+ return false; -+ } -+ + return false; + } + +- // rewrite constant pool references in the fields_annotations: +- if (!rewrite_cp_refs_in_fields_annotations(scratch_class, THREAD)) { +- // propagate failure back to caller + result = check_loaded_methods(); + if (!result) { + RC_TRACE(0x00000001, ("Aborting redefinition because of wrong loaded method")); + Universe::set_verify_in_progress(false); -+ return false; -+ } -+ + return false; + } + +- // rewrite constant pool references in the methods_annotations: +- if (!rewrite_cp_refs_in_methods_annotations(scratch_class, THREAD)) { +- // propagate failure back to caller + RC_TRACE(0x00000001, ("Verification passed => hierarchy change is valid!")); + Universe::set_verify_in_progress(false); + return true; +} - --// 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: --// --// annotations_typeArray { --// u2 num_annotations; --// annotation annotations[num_annotations]; --// } --// --bool VM_RedefineClasses::rewrite_cp_refs_in_annotations_typeArray( -- typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) { ++ +void VM_RedefineClasses::rollback() { + RC_TRACE(0x00000001, ("Rolling back redefinition!")); + SystemDictionary::rollback_redefinition(); - -- if ((byte_i_ref + 2) > annotations_typeArray->length()) { -- // not enough room for num_annotations field -- RC_TRACE_WITH_THREAD(0x02000000, THREAD, -- ("length() is too small for num_annotations field")); -- return false; ++ + RC_TRACE(0x00000001, ("After rolling back system dictionary!")); + for (int i=0; i<_new_classes->length(); i++) { + SystemDictionary::remove_from_hierarchy(_new_classes->at(i)); - } - -- u2 num_annotations = Bytes::get_Java_u2((address) -- annotations_typeArray->byte_at_addr(byte_i_ref)); -- byte_i_ref += 2; ++ } ++ + 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); + } - -- RC_TRACE_WITH_THREAD(0x02000000, THREAD, -- ("num_annotations=%d", num_annotations)); ++ +} - -- int calc_num_annotations = 0; -- for (; calc_num_annotations < num_annotations; calc_num_annotations++) { -- if (!rewrite_cp_refs_in_annotation_struct(annotations_typeArray, -- byte_i_ref, THREAD)) { -- RC_TRACE_WITH_THREAD(0x02000000, THREAD, -- ("bad annotation_struct at %d", calc_num_annotations)); -- // propagate failure back to caller -- return false; ++ +template <class T> void VM_RedefineClasses::do_oop_work(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { @@ -7862,23 +7700,649 @@ index 295ed86..fdfc6f4 100644 + } + } + } - } - } -- assert(num_annotations == calc_num_annotations, "sanity check"); ++ } ++ } +} - -- return true; --} // end rewrite_cp_refs_in_annotations_typeArray() ++ +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); +} - ++ +void VM_RedefineClasses::doit() { + Thread *thread = Thread::current(); ++ ++ RC_TRACE(0x00000001, ("Entering doit!")); ++ ++ ++ if ((_max_redefinition_flags & Klass::RemoveSuperType) != 0) { ++ ++ RC_TIMER_START(_timer_check_type); ++ ++ if (!check_type_consistency()) { ++ // (tw) TODO: Rollback the class redefinition ++ rollback(); ++ RC_TRACE(0x00000001, ("Detected type inconsistency!")); ++ _result = JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; ++ RC_TIMER_STOP(_timer_check_type); ++ return; ++ } ++ ++ RC_TIMER_STOP(_timer_check_type); ++ ++ } else { ++ RC_TRACE(0x00000001, ("No type narrowing => skipping check for type inconsistency")); ++ } ++ ++ if (UseMethodForwardPoints) { ++ RC_TRACE(0x00000001, ("Check stack for forwarding methods to new version")); ++ method_forwarding(); ++ } ++ ++ 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(0x00000001, ("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_redefinition); ++ ++ class ChangePointersOopClosure : public OopClosure { ++ virtual void do_oop(oop* o) { ++ do_oop_work(o); ++ } ++ ++ virtual void do_oop(narrowOop* o) { ++ do_oop_work(o); ++ } ++ }; ++ ++ class ChangePointersObjectClosure : public ObjectClosure { ++ ++ private: ++ ++ OopClosure *_closure; ++ bool _needs_instance_update; ++ GrowableArray<oop> *_updated_oops; ++ ++ public: ++ ChangePointersObjectClosure(OopClosure *closure) : _closure(closure), _needs_instance_update(false), _updated_oops(NULL) {} ++ ++ bool needs_instance_update() { ++ return _needs_instance_update; ++ } ++ ++ GrowableArray<oop> *updated_oops() { return _updated_oops; } ++ ++ virtual void do_object(oop obj) { ++ if (!obj->is_instanceKlass()) { ++ obj->oop_iterate(_closure); ++ ++ if (obj->blueprint()->is_redefining()) { ++ ++ if (obj->blueprint()->check_redefinition_flag(Klass::HasInstanceTransformer)) { ++ if (_updated_oops == NULL) { ++ _updated_oops = new (ResourceObj::C_HEAP) GrowableArray<oop>(100, true); ++ } ++ _updated_oops->append(obj); ++ } ++ ++ if(obj->blueprint()->update_information() != NULL || obj->is_perm()) { ++ ++ assert(obj->blueprint()->old_version() != NULL, "must have old version"); ++ obj->set_klass_no_check(obj->blueprint()->old_version()); ++ ++ if (obj->size() != obj->size_given_klass(obj->blueprint()->new_version()->klass_part()) || obj->is_perm()) { ++ // We need an instance update => set back to old klass ++ _needs_instance_update = true; ++ ++ } else { ++ MarkSweep::update_fields(obj, obj); ++ assert(obj->blueprint()->is_redefining(), "update fields resets the klass"); ++ } ++ } ++ } ++ ++ } else { ++ instanceKlass *klass = instanceKlass::cast((klassOop)obj); ++ if (klass->is_redefining()) { ++ // DCEVM: We need to restorte constants pool owner which was updated by do_oop_work ++ instanceKlass* old_klass = instanceKlass::cast(klass->old_version()); ++ old_klass->constants()->set_pool_holder(klass->old_version()); ++ ++ // 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. ++ klass->initialize_redefined_class(); ++ } ++ // idubrov: FIXME: we probably don't need that since oop's will be visited in a regular way... ++ // idubrov: need to check if there is a test to verify that fields referencing class being updated ++ // idubrov: will get new version of that class ++ //klass->iterate_static_fields(_closure); ++ } ++ } ++ }; ++ ++ ChangePointersOopClosure oopClosure; ++ ChangePointersObjectClosure objectClosure(&oopClosure); ++ ++ { ++ SharedHeap::heap()->gc_prologue(true); ++ Universe::root_oops_do(&oopClosure); ++ Universe::heap()->object_iterate(&objectClosure); ++ SharedHeap::heap()->gc_epilogue(false); ++ } ++ ++ // Swap marks to have same hashcodes ++ for (int i=0; i<_new_classes->length(); i++) { ++ swap_marks(_new_classes->at(i)(), _new_classes->at(i)->old_version()); ++ swap_marks(_new_classes->at(i)->java_mirror(), _new_classes->at(i)->old_version()->java_mirror()); ++ } ++ ++ _updated_oops = objectClosure.updated_oops(); ++ ++ if (objectClosure.needs_instance_update()){ ++ ++ // Do a full garbage collection to update the instance sizes accordingly ++ RC_TRACE(0x00000001, ("Before performing full GC!")); ++ Universe::set_redefining_gc_run(true); ++ JvmtiGCMarker jgcm; ++ notify_gc_begin(true); ++ Universe::heap()->collect_as_vm_thread(GCCause::_heap_inspection); ++ notify_gc_end(); ++ Universe::set_redefining_gc_run(false); ++ RC_TRACE(0x00000001, ("GC done!")); ++ } ++ ++ ++ if (RC_TRACE_ENABLED(0x00000001)) { ++ if (_updated_oops != NULL) { ++ RC_TRACE(0x00000001, ("%d object(s) updated!", _updated_oops->length())); ++ } else { ++ RC_TRACE(0x00000001, ("No objects updated!")); ++ } ++ } ++ ++ // Unmark klassOops as "redefining" ++ for (int i=0; i<_new_classes->length(); i++) { ++ klassOop cur = _new_classes->at(i)(); ++ _new_classes->at(i)->set_redefining(false); ++ _new_classes->at(i)->clear_update_information(); ++ _new_classes->at(i)->update_supers_to_newest_version(); ++ ++ if (((instanceKlass *)cur->klass_part()->old_version()->klass_part())->array_klasses() != NULL) { ++ update_array_classes_to_newest_version(((instanceKlass *)cur->klass_part()->old_version()->klass_part())->array_klasses()); ++ ++ // Transfer the array classes, otherwise we might get cast exceptions when casting array types. ++ ((instanceKlass*)cur->klass_part())->set_array_klasses(((instanceKlass*)cur->klass_part()->old_version()->klass_part())->array_klasses()); ++ ++ oop new_mirror = _new_classes->at(i)->java_mirror(); ++ oop old_mirror = _new_classes->at(i)->old_version()->java_mirror(); ++ java_lang_Class::set_array_klass(new_mirror, java_lang_Class::array_klass(old_mirror)); ++ ++ // Transfer init state ++ instanceKlass::ClassState state = instanceKlass::cast(cur->old_version())->init_state(); ++ if (state > instanceKlass::linked) { ++ instanceKlass::cast(cur)->call_class_initializer(thread); ++ } ++ } ++ } ++ ++ for (int i=T_BOOLEAN; i<=T_LONG; i++) { ++ update_array_classes_to_newest_version(Universe::typeArrayKlassObj((BasicType)i)); ++ } ++ ++ // 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 ++ CompileBroker::cleanup_after_redefinition(); ++ ++#ifdef ASSERT ++ ++ // Universe::verify(); ++ // JNIHandles::verify(); ++ ++ SystemDictionary::classes_do(check_class, thread); ++#endif ++ ++ update_active_methods(); ++ RC_TIMER_STOP(_timer_redefinition); ++ ++} ++ ++void VM_RedefineClasses::update_array_classes_to_newest_version(klassOop smallest_dimension) { ++ ++ arrayKlass *curArrayKlass = arrayKlass::cast(smallest_dimension); ++ assert(curArrayKlass->lower_dimension() == NULL, "argument must be smallest dimension"); ++ ++ ++ while (curArrayKlass != NULL) { ++ klassOop higher_dimension = curArrayKlass->higher_dimension(); ++ klassOop lower_dimension = curArrayKlass->lower_dimension(); ++ curArrayKlass->update_supers_to_newest_version(); ++ ++ curArrayKlass = NULL; ++ if (higher_dimension != NULL) { ++ curArrayKlass = arrayKlass::cast(higher_dimension); ++ } ++ } ++ ++} ++ ++void VM_RedefineClasses::doit_epilogue() { ++ ++ RC_TIMER_START(_timer_vm_op_epilogue); ++ ++ unlock_threads(); ++ ++ ResourceMark mark; ++ ++ VM_GC_Operation::doit_epilogue(); ++ RC_TRACE(0x00000001, ("GC Operation epilogue finished! ")); ++ ++ GrowableArray<methodHandle> instanceTransformerMethods; ++ ++ // Call static transformers ++ for (int i=0; i<_new_classes->length(); i++) { ++ ++ instanceKlassHandle klass = _new_classes->at(i); ++ ++ // Find instance transformer method ++ ++ if (klass->check_redefinition_flag(Klass::HasInstanceTransformer)) { ++ ++ RC_TRACE(0x00008000, ("Call instance transformer of %s instance", klass->name()->as_C_string())); ++ klassOop cur_klass = klass(); ++ while (cur_klass != NULL) { ++ methodOop method = ((instanceKlass*)cur_klass->klass_part())->find_method(vmSymbols::transformer_name(), vmSymbols::void_method_signature()); ++ if (method != NULL) { ++ methodHandle instanceTransformerMethod(method); ++ instanceTransformerMethods.append(instanceTransformerMethod); ++ break; ++ } else { ++ cur_klass = cur_klass->klass_part()->super(); ++ } ++ } ++ assert(cur_klass != NULL, "must have instance transformer method"); ++ } else { ++ instanceTransformerMethods.append(methodHandle(Thread::current(), NULL)); ++ } ++ } ++ ++ ++ // Call instance transformers ++ if (_updated_oops != NULL) { ++ ++ for (int i=0; i<_updated_oops->length(); i++) { ++ assert(_updated_oops->at(i) != NULL, "must not be null!"); ++ Handle cur(_updated_oops->at(i)); ++ instanceKlassHandle klass(cur->klass()); ++ ++ if (klass->check_redefinition_flag(Klass::HasInstanceTransformer)) { ++ ++ methodHandle method = instanceTransformerMethods.at(klass->redefinition_index()); ++ ++ RC_TRACE(0x00008000, ("executing transformer method")); ++ ++ Thread *__the_thread__ = Thread::current(); ++ JavaValue result(T_VOID); ++ JavaCallArguments args(cur); ++ JavaCalls::call(&result, ++ method, ++ &args, ++ THREAD); ++ ++ // TODO: What to do with an exception here? ++ if (HAS_PENDING_EXCEPTION) { ++ Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); ++ RC_TRACE(0x00000002, ("exception when executing transformer: '%s'", ++ ex_name->as_C_string())); ++ CLEAR_PENDING_EXCEPTION; ++ } ++ } ++ } ++ ++ delete _updated_oops; ++ _updated_oops = NULL; ++ } ++ ++ // Free the array of scratch classes ++ delete _new_classes; ++ _new_classes = NULL; ++ RC_TRACE(0x00000001, ("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; + } +- +- // rewrite constant pool references in the methods_parameter_annotations: +- if (!rewrite_cp_refs_in_methods_parameter_annotations(scratch_class, +- THREAD)) { +- // propagate failure back to caller ++ 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; + } +- +- // rewrite constant pool references in the methods_default_annotations: +- if (!rewrite_cp_refs_in_methods_default_annotations(scratch_class, +- THREAD)) { +- // propagate failure back to caller +- return false; ++ return true; ++} ++ ++#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 true; +-} // end rewrite_cp_refs() +- +- +-// Rewrite constant pool references in the methods. +-bool VM_RedefineClasses::rewrite_cp_refs_in_methods( +- instanceKlassHandle scratch_class, TRAPS) { +- +- objArrayHandle methods(THREAD, scratch_class->methods()); +- +- if (methods.is_null() || methods->length() == 0) { +- // no methods so nothing to do +- return true; +- } +- +- // rewrite constant pool references in the methods: +- for (int i = methods->length() - 1; i >= 0; i--) { +- methodHandle method(THREAD, (methodOop)methods->obj_at(i)); +- methodHandle new_method; +- rewrite_cp_refs_in_method(method, &new_method, CHECK_false); +- if (!new_method.is_null()) { +- // the method has been replaced so save the new method version +- methods->obj_at_put(i, new_method()); ++} ++ ++#endif ++ ++// 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. ++static void 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; ++ } ++ } ++ ++ // 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(). +-void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method, +- methodHandle *new_method_p, TRAPS) { +- +- *new_method_p = methodHandle(); // default is no new method +- +- // We cache a pointer to the bytecodes here in code_base. If GC +- // moves the methodOop, then the bytecodes will also move which +- // will likely cause a crash. We create a No_Safepoint_Verifier +- // object to detect whether we pass a possible safepoint in this +- // code block. +- No_Safepoint_Verifier nsv; +- +- // Bytecodes and their length +- address code_base = method->code_base(); +- int code_length = method->code_size(); +- +- int bc_length; +- for (int bci = 0; bci < code_length; bci += bc_length) { +- address bcp = code_base + bci; +- Bytecodes::Code c = (Bytecodes::Code)(*bcp); +- +- bc_length = Bytecodes::length_for(c); +- if (bc_length == 0) { +- // More complicated bytecodes report a length of zero so +- // we have to try again a slightly different way. +- bc_length = Bytecodes::length_at(method(), bcp); +- } +- +- assert(bc_length != 0, "impossible bytecode length"); +- +- switch (c) { +- case Bytecodes::_ldc: +- { +- int cp_index = *(bcp + 1); +- int new_index = find_new_index(cp_index); +- +- if (StressLdcRewrite && new_index == 0) { +- // If we are stressing ldc -> ldc_w rewriting, then we +- // always need a new_index value. +- new_index = cp_index; +- } +- if (new_index != 0) { +- // the original index is mapped so we have more work to do +- if (!StressLdcRewrite && new_index <= max_jubyte) { +- // The new value can still use ldc instead of ldc_w +- // unless we are trying to stress ldc -> ldc_w rewriting +- RC_TRACE_WITH_THREAD(0x00080000, THREAD, +- ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c), +- bcp, cp_index, new_index)); +- *(bcp + 1) = new_index; +- } else { +- RC_TRACE_WITH_THREAD(0x00080000, THREAD, +- ("%s->ldc_w@" INTPTR_FORMAT " old=%d, new=%d", +- Bytecodes::name(c), bcp, cp_index, new_index)); +- // the new value needs ldc_w instead of ldc +- u_char inst_buffer[4]; // max instruction size is 4 bytes +- bcp = (address)inst_buffer; +- // construct new instruction sequence +- *bcp = Bytecodes::_ldc_w; +- bcp++; +- // Rewriter::rewrite_method() does not rewrite ldc -> ldc_w. +- // See comment below for difference between put_Java_u2() +- // and put_native_u2(). +- Bytes::put_Java_u2(bcp, new_index); +- +- Relocator rc(method, NULL /* no RelocatorListener needed */); +- methodHandle m; +- { +- Pause_No_Safepoint_Verifier pnsv(&nsv); +- +- // ldc is 2 bytes and ldc_w is 3 bytes +- m = rc.insert_space_at(bci, 3, inst_buffer, THREAD); +- if (m.is_null() || HAS_PENDING_EXCEPTION) { +- guarantee(false, "insert_space_at() failed"); +- } +- } +- +- // return the new method so that the caller can update +- // the containing class +- *new_method_p = method = m; +- // switch our bytecode processing loop from the old method +- // to the new method +- code_base = method->code_base(); +- code_length = method->code_size(); +- bcp = code_base + bci; +- c = (Bytecodes::Code)(*bcp); +- bc_length = Bytecodes::length_for(c); +- assert(bc_length != 0, "sanity check"); +- } // end we need ldc_w instead of ldc +- } // end if there is a mapped index +- } break; +- +- // these bytecodes have a two-byte constant pool index +- case Bytecodes::_anewarray : // fall through +- case Bytecodes::_checkcast : // fall through +- case Bytecodes::_getfield : // fall through +- case Bytecodes::_getstatic : // fall through +- case Bytecodes::_instanceof : // fall through +- case Bytecodes::_invokeinterface: // fall through +- case Bytecodes::_invokespecial : // fall through +- case Bytecodes::_invokestatic : // fall through +- case Bytecodes::_invokevirtual : // fall through +- case Bytecodes::_ldc_w : // fall through +- case Bytecodes::_ldc2_w : // fall through +- case Bytecodes::_multianewarray : // fall through +- case Bytecodes::_new : // fall through +- case Bytecodes::_putfield : // fall through +- case Bytecodes::_putstatic : +- { +- address p = bcp + 1; +- int cp_index = Bytes::get_Java_u2(p); +- int new_index = find_new_index(cp_index); +- if (new_index != 0) { +- // the original index is mapped so update w/ new value +- RC_TRACE_WITH_THREAD(0x00080000, THREAD, +- ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c), +- bcp, cp_index, new_index)); +- // Rewriter::rewrite_method() uses put_native_u2() in this +- // situation because it is reusing the constant pool index +- // location for a native index into the constantPoolCache. +- // Since we are updating the constant pool index prior to +- // verification and constantPoolCache initialization, we +- // need to keep the new index in Java byte order. +- Bytes::put_Java_u2(p, new_index); +- } +- } break; +- } +- } // end for each bytecode +-} // end rewrite_cp_refs_in_method() +- +- +-// Rewrite constant pool references in the class_annotations field. +-bool VM_RedefineClasses::rewrite_cp_refs_in_class_annotations( +- instanceKlassHandle scratch_class, TRAPS) { +- +- typeArrayHandle class_annotations(THREAD, +- scratch_class->class_annotations()); +- if (class_annotations.is_null() || class_annotations->length() == 0) { +- // no class_annotations so nothing to do +- return true; +- } +- +- RC_TRACE_WITH_THREAD(0x02000000, THREAD, +- ("class_annotations length=%d", class_annotations->length())); +- +- int byte_i = 0; // byte index into class_annotations +- return rewrite_cp_refs_in_annotations_typeArray(class_annotations, byte_i, +- THREAD); +-} +- +- +-// 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: +-// +-// annotations_typeArray { +-// u2 num_annotations; +-// annotation annotations[num_annotations]; +-// } +-// +-bool VM_RedefineClasses::rewrite_cp_refs_in_annotations_typeArray( +- typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) { +- +- if ((byte_i_ref + 2) > annotations_typeArray->length()) { +- // not enough room for num_annotations field +- RC_TRACE_WITH_THREAD(0x02000000, THREAD, +- ("length() is too small for num_annotations field")); +- return false; +- } +- +- u2 num_annotations = Bytes::get_Java_u2((address) +- annotations_typeArray->byte_at_addr(byte_i_ref)); +- byte_i_ref += 2; +- +- RC_TRACE_WITH_THREAD(0x02000000, THREAD, +- ("num_annotations=%d", num_annotations)); +- +- int calc_num_annotations = 0; +- for (; calc_num_annotations < num_annotations; calc_num_annotations++) { +- if (!rewrite_cp_refs_in_annotation_struct(annotations_typeArray, +- byte_i_ref, THREAD)) { +- RC_TRACE_WITH_THREAD(0x02000000, THREAD, +- ("bad annotation_struct at %d", calc_num_annotations)); +- // propagate failure back to caller +- return false; +- } +- } +- assert(num_annotations == calc_num_annotations, "sanity check"); +- +- return true; +-} // end rewrite_cp_refs_in_annotations_typeArray() +- +- -// 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: @@ -7900,22 +8364,19 @@ index 295ed86..fdfc6f4 100644 - ("length() is too small for annotation_struct")); - return false; - } -+ RC_TRACE(0x00000001, ("Entering doit!")); - +- - u2 type_index = rewrite_cp_ref_in_annotation_data(annotations_typeArray, - byte_i_ref, "mapped old type_index=%d", THREAD); - +- - u2 num_element_value_pairs = Bytes::get_Java_u2((address) - annotations_typeArray->byte_at_addr( - byte_i_ref)); - byte_i_ref += 2; -+ if ((_max_redefinition_flags & Klass::RemoveSuperType) != 0) { - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("type_index=%d num_element_value_pairs=%d", type_index, - num_element_value_pairs)); -+ RC_TIMER_START(_timer_check_type); - +- - int calc_num_element_value_pairs = 0; - for (; calc_num_element_value_pairs < num_element_value_pairs; - calc_num_element_value_pairs++) { @@ -7925,52 +8386,26 @@ index 295ed86..fdfc6f4 100644 - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("length() is too small for element_name_index")); - return false; -+ if (!check_type_consistency()) { -+ // (tw) TODO: Rollback the class redefinition -+ rollback(); -+ RC_TRACE(0x00000001, ("Detected type inconsistency!")); -+ _result = JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; -+ RC_TIMER_STOP(_timer_check_type); -+ return; - } - +- } +- - u2 element_name_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old element_name_index=%d", THREAD); -+ RC_TIMER_STOP(_timer_check_type); -+ -+ } else { -+ RC_TRACE(0x00000001, ("No type narrowing => skipping check for type inconsistency")); -+ } - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("element_name_index=%d", element_name_index)); -+ if (UseMethodForwardPoints) { -+ RC_TRACE(0x00000001, ("Check stack for forwarding methods to new version")); -+ method_forwarding(); -+ } - +- - if (!rewrite_cp_refs_in_element_value(annotations_typeArray, - byte_i_ref, THREAD)) { - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("bad element_value at %d", calc_num_element_value_pairs)); - // 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()) { -+ RC_TRACE(0x00000001, ("failed to remap shared readonly space to readwrite, private")); -+ _result = JVMTI_ERROR_INTERNAL; -+ return; - } +- } - } // end for each component - assert(num_element_value_pairs == calc_num_element_value_pairs, - "sanity check"); -+ } - +- - return true; -} // end rewrite_cp_refs_in_annotation_struct() - @@ -7995,14 +8430,8 @@ index 295ed86..fdfc6f4 100644 - byte_i_ref += 2; - return old_cp_index; -} -+ 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()); - +- +- -// Rewrite constant pool references in the element_value portion of an -// annotations_typeArray. This "structure" is from section 4.8.15.1 of -// the 2nd-edition of the VM spec: @@ -8026,19 +8455,14 @@ index 295ed86..fdfc6f4 100644 -// -bool VM_RedefineClasses::rewrite_cp_refs_in_element_value( - typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) { -+ // Adjust constantpool caches and vtables for all classes -+ // that reference methods of the evolved class. -+ SystemDictionary::classes_do(adjust_cpool_cache, Thread::current()); - +- - 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; - } -+ RC_TIMER_STOP(_timer_prepare_redefinition); -+ RC_TIMER_START(_timer_redefinition); - +- - u1 tag = annotations_typeArray->byte_at(byte_i_ref); - byte_i_ref++; - RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("tag='%c'", tag)); @@ -8060,100 +8484,65 @@ index 295ed86..fdfc6f4 100644 - { - // For the above tag values (including the BaseType values), - // value.const_value_index is right union field. -+ class ChangePointersOopClosure : public OopClosure { -+ virtual void do_oop(oop* o) { -+ do_oop_work(o); -+ } - +- - if ((byte_i_ref + 2) > annotations_typeArray->length()) { - // not enough room for a const_value_index - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("length() is too small for a const_value_index")); - return false; -+ virtual void do_oop(narrowOop* o) { -+ do_oop_work(o); - } -+ }; - +- } +- - u2 const_value_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old const_value_index=%d", THREAD); -+ class ChangePointersObjectClosure : public ObjectClosure { - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("const_value_index=%d", const_value_index)); - } break; -+ private: - +- - case 'e': - { - // for the above tag value, value.enum_const_value is right union field -+ OopClosure *_closure; -+ bool _needs_instance_update; -+ GrowableArray<oop> *_updated_oops; - +- - 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; - } -+ public: -+ ChangePointersObjectClosure(OopClosure *closure) : _closure(closure), _needs_instance_update(false), _updated_oops(NULL) {} - +- - u2 type_name_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old type_name_index=%d", THREAD); -+ bool needs_instance_update() { -+ return _needs_instance_update; -+ } - +- - u2 const_name_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old const_name_index=%d", THREAD); -+ GrowableArray<oop> *updated_oops() { return _updated_oops; } - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("type_name_index=%d const_name_index=%d", type_name_index, - const_name_index)); - } break; -+ virtual void do_object(oop obj) { -+ if (!obj->is_instanceKlass()) { -+ obj->oop_iterate(_closure); -+ -+ if (obj->blueprint()->is_redefining()) { - +- - case 'c': - { - // for the above tag value, value.class_info_index is right union field -+ if (obj->blueprint()->check_redefinition_flag(Klass::HasInstanceTransformer)) { -+ if (_updated_oops == NULL) { -+ _updated_oops = new (ResourceObj::C_HEAP) GrowableArray<oop>(100, true); -+ } -+ _updated_oops->append(obj); -+ } - +- - 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; - } -+ if(obj->blueprint()->update_information() != NULL || obj->is_perm()) { - +- - u2 class_info_index = rewrite_cp_ref_in_annotation_data( - annotations_typeArray, byte_i_ref, - "mapped old class_info_index=%d", THREAD); -+ assert(obj->blueprint()->old_version() != NULL, "must have old version"); -+ obj->set_klass_no_check(obj->blueprint()->old_version()); - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("class_info_index=%d", class_info_index)); - } break; -+ if (obj->size() != obj->size_given_klass(obj->blueprint()->new_version()->klass_part()) || obj->is_perm()) { -+ // We need an instance update => set back to old klass -+ _needs_instance_update = true; - +- - case '@': - // For the above tag value, value.attr_value is the right union - // field. This is a nested annotation. @@ -8163,13 +8552,7 @@ index 295ed86..fdfc6f4 100644 - return false; - } - break; -+ } else { -+ MarkSweep::update_fields(obj, obj); -+ assert(obj->blueprint()->is_redefining(), "update fields resets the klass"); -+ } -+ } -+ } - +- - case '[': - { - if ((byte_i_ref + 2) > annotations_typeArray->length()) { @@ -8194,76 +8577,35 @@ index 295ed86..fdfc6f4 100644 - ("bad nested element_value at %d", calc_num_values)); - // propagate failure back to caller - return false; -+ } else { -+ instanceKlass *klass = instanceKlass::cast((klassOop)obj); -+ if (klass->is_redefining()) { -+ // DCEVM: We need to restorte constants pool owner which was updated by do_oop_work -+ instanceKlass* old_klass = instanceKlass::cast(klass->old_version()); -+ old_klass->constants()->set_pool_holder(klass->old_version()); -+ -+ // 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. -+ klass->initialize_redefined_class(); -+ } -+ // idubrov: FIXME: we probably don't need that since oop's will be visited in a regular way... -+ // idubrov: need to check if there is a test to verify that fields referencing class being updated -+ // idubrov: will get new version of that class -+ //klass->iterate_static_fields(_closure); - } - } +- } +- } - assert(num_values == calc_num_values, "sanity check"); - } break; -+ }; - +- - default: - RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("bad tag=0x%x", tag)); - return false; - } // end decode tag field -+ ChangePointersOopClosure oopClosure; -+ ChangePointersObjectClosure objectClosure(&oopClosure); - +- - return true; -} // end rewrite_cp_refs_in_element_value() -+ { -+ SharedHeap::heap()->gc_prologue(true); -+ Universe::root_oops_do(&oopClosure); -+ Universe::heap()->object_iterate(&objectClosure); -+ SharedHeap::heap()->gc_epilogue(false); -+ } - -+ // Swap marks to have same hashcodes -+ for (int i=0; i<_new_classes->length(); i++) { -+ swap_marks(_new_classes->at(i)(), _new_classes->at(i)->old_version()); -+ swap_marks(_new_classes->at(i)->java_mirror(), _new_classes->at(i)->old_version()->java_mirror()); -+ } - +- +- -// Rewrite constant pool references in a fields_annotations field. -bool VM_RedefineClasses::rewrite_cp_refs_in_fields_annotations( - instanceKlassHandle scratch_class, TRAPS) { -+ _updated_oops = objectClosure.updated_oops(); - +- - objArrayHandle fields_annotations(THREAD, - scratch_class->fields_annotations()); -+ if (objectClosure.needs_instance_update()){ - +- - if (fields_annotations.is_null() || fields_annotations->length() == 0) { - // no fields_annotations so nothing to do - return true; -+ // Do a full garbage collection to update the instance sizes accordingly -+ RC_TRACE(0x00000001, ("Before performing full GC!")); -+ Universe::set_redefining_gc_run(true); -+ JvmtiGCMarker jgcm; -+ notify_gc_begin(true); -+ Universe::heap()->collect_as_vm_thread(GCCause::_heap_inspection); -+ notify_gc_end(); -+ Universe::set_redefining_gc_run(false); -+ RC_TRACE(0x00000001, ("GC done!")); - } - +- } +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("fields_annotations length=%d", fields_annotations->length())); - +- - for (int i = 0; i < fields_annotations->length(); i++) { - typeArrayHandle field_annotations(THREAD, - (typeArrayOop)fields_annotations->obj_at(i)); @@ -8279,30 +8621,17 @@ index 295ed86..fdfc6f4 100644 - ("bad field_annotations at %d", i)); - // propagate failure back to caller - return false; -+ if (RC_TRACE_ENABLED(0x00000001)) { -+ if (_updated_oops != NULL) { -+ RC_TRACE(0x00000001, ("%d object(s) updated!", _updated_oops->length())); -+ } else { -+ RC_TRACE(0x00000001, ("No objects updated!")); - } - } - +- } +- } +- - return true; -} // end rewrite_cp_refs_in_fields_annotations() - -+ // Unmark klassOops as "redefining" -+ for (int i=0; i<_new_classes->length(); i++) { -+ klassOop cur = _new_classes->at(i)(); -+ _new_classes->at(i)->set_redefining(false); -+ _new_classes->at(i)->clear_update_information(); -+ _new_classes->at(i)->update_supers_to_newest_version(); - +- -// Rewrite constant pool references in a methods_annotations field. -bool VM_RedefineClasses::rewrite_cp_refs_in_methods_annotations( - instanceKlassHandle scratch_class, TRAPS) { -+ if (((instanceKlass *)cur->klass_part()->old_version()->klass_part())->array_klasses() != NULL) { -+ update_array_classes_to_newest_version(((instanceKlass *)cur->klass_part()->old_version()->klass_part())->array_klasses()); - +- - objArrayHandle methods_annotations(THREAD, - scratch_class->methods_annotations()); - @@ -8310,29 +8639,18 @@ index 295ed86..fdfc6f4 100644 - // no methods_annotations so nothing to do - return true; - } -+ // Transfer the array classes, otherwise we might get cast exceptions when casting array types. -+ ((instanceKlass*)cur->klass_part())->set_array_klasses(((instanceKlass*)cur->klass_part()->old_version()->klass_part())->array_klasses()); - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_annotations length=%d", methods_annotations->length())); -+ oop new_mirror = _new_classes->at(i)->java_mirror(); -+ oop old_mirror = _new_classes->at(i)->old_version()->java_mirror(); -+ java_lang_Class::set_array_klass(new_mirror, java_lang_Class::array_klass(old_mirror)); - +- - for (int i = 0; i < methods_annotations->length(); i++) { - typeArrayHandle method_annotations(THREAD, - (typeArrayOop)methods_annotations->obj_at(i)); - if (method_annotations.is_null() || method_annotations->length() == 0) { - // this method does not have any annotations so skip it - continue; -+ // Transfer init state -+ instanceKlass::ClassState state = instanceKlass::cast(cur->old_version())->init_state(); -+ if (state > instanceKlass::linked) { -+ instanceKlass::cast(cur)->call_class_initializer(thread); -+ } - } -+ } - +- } +- - int byte_i = 0; // byte index into method_annotations - if (!rewrite_cp_refs_in_annotations_typeArray(method_annotations, byte_i, - THREAD)) { @@ -8341,19 +8659,12 @@ index 295ed86..fdfc6f4 100644 - // propagate failure back to caller - return false; - } -+ for (int i=T_BOOLEAN; i<=T_LONG; i++) { -+ update_array_classes_to_newest_version(Universe::typeArrayKlassObj((BasicType)i)); - } - +- } +- - return true; -} // end rewrite_cp_refs_in_methods_annotations() -+ // 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(); - +- +- -// Rewrite constant pool references in a methods_parameter_annotations -// field. This "structure" is adapted from the -// RuntimeVisibleParameterAnnotations_attribute described in section @@ -8369,27 +8680,20 @@ index 295ed86..fdfc6f4 100644 -// -bool VM_RedefineClasses::rewrite_cp_refs_in_methods_parameter_annotations( - instanceKlassHandle scratch_class, TRAPS) { -+ // Clean up caches in the compiler interface and compiler threads -+ CompileBroker::cleanup_after_redefinition(); - +- - objArrayHandle methods_parameter_annotations(THREAD, - scratch_class->methods_parameter_annotations()); -+#ifdef ASSERT - +- - if (methods_parameter_annotations.is_null() - || methods_parameter_annotations->length() == 0) { - // no methods_parameter_annotations so nothing to do - return true; - } -+ // Universe::verify(); -+ // JNIHandles::verify(); - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_parameter_annotations length=%d", - methods_parameter_annotations->length())); -+ SystemDictionary::classes_do(check_class, thread); -+#endif - +- - for (int i = 0; i < methods_parameter_annotations->length(); i++) { - typeArrayHandle method_parameter_annotations(THREAD, - (typeArrayOop)methods_parameter_annotations->obj_at(i)); @@ -8398,28 +8702,22 @@ index 295ed86..fdfc6f4 100644 - // this method does not have any parameter annotations so skip it - continue; - } -+ update_active_methods(); -+ RC_TIMER_STOP(_timer_redefinition); - +- - 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; - } -+} - +- - int byte_i = 0; // byte index into method_parameter_annotations -+void VM_RedefineClasses::update_array_classes_to_newest_version(klassOop smallest_dimension) { - +- - u1 num_parameters = method_parameter_annotations->byte_at(byte_i); - byte_i++; -+ arrayKlass *curArrayKlass = arrayKlass::cast(smallest_dimension); -+ assert(curArrayKlass->lower_dimension() == NULL, "argument must be smallest dimension"); - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("num_parameters=%d", num_parameters)); - +- - int calc_num_parameters = 0; - for (; calc_num_parameters < num_parameters; calc_num_parameters++) { - if (!rewrite_cp_refs_in_annotations_typeArray( @@ -8429,24 +8727,14 @@ index 295ed86..fdfc6f4 100644 - // propagate failure back to caller - return false; - } -+ while (curArrayKlass != NULL) { -+ klassOop higher_dimension = curArrayKlass->higher_dimension(); -+ klassOop lower_dimension = curArrayKlass->lower_dimension(); -+ curArrayKlass->update_supers_to_newest_version(); -+ -+ curArrayKlass = NULL; -+ if (higher_dimension != NULL) { -+ curArrayKlass = arrayKlass::cast(higher_dimension); - } +- } - assert(num_parameters == calc_num_parameters, "sanity check"); - } - +- } +- - return true; -} // end rewrite_cp_refs_in_methods_parameter_annotations() -+} - -+void VM_RedefineClasses::doit_epilogue() { - +- +- -// 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: @@ -8457,25 +8745,20 @@ index 295ed86..fdfc6f4 100644 -// -bool VM_RedefineClasses::rewrite_cp_refs_in_methods_default_annotations( - instanceKlassHandle scratch_class, TRAPS) { -+ RC_TIMER_START(_timer_vm_op_epilogue); - +- - objArrayHandle methods_default_annotations(THREAD, - scratch_class->methods_default_annotations()); -+ unlock_threads(); - +- - if (methods_default_annotations.is_null() - || methods_default_annotations->length() == 0) { - // no methods_default_annotations so nothing to do - return true; - } -+ ResourceMark mark; - +- - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_default_annotations length=%d", - methods_default_annotations->length())); -+ VM_GC_Operation::doit_epilogue(); -+ RC_TRACE(0x00000001, ("GC Operation epilogue finished! ")); - +- - for (int i = 0; i < methods_default_annotations->length(); i++) { - typeArrayHandle method_default_annotations(THREAD, - (typeArrayOop)methods_default_annotations->obj_at(i)); @@ -8484,48 +8767,22 @@ index 295ed86..fdfc6f4 100644 - // this method does not have any default annotations so skip it - continue; - } -+ GrowableArray<methodHandle> instanceTransformerMethods; - +- - int byte_i = 0; // byte index into method_default_annotations -+ // Call static transformers -+ for (int i=0; i<_new_classes->length(); i++) { -+ -+ instanceKlassHandle klass = _new_classes->at(i); -+ -+ // Find instance transformer method - +- - if (!rewrite_cp_refs_in_element_value( - method_default_annotations, byte_i, THREAD)) { - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("bad default element_value at %d", i)); - // propagate failure back to caller - return false; -+ if (klass->check_redefinition_flag(Klass::HasInstanceTransformer)) { -+ -+ RC_TRACE(0x00008000, ("Call instance transformer of %s instance", klass->name()->as_C_string())); -+ klassOop cur_klass = klass(); -+ while (cur_klass != NULL) { -+ methodOop method = ((instanceKlass*)cur_klass->klass_part())->find_method(vmSymbols::transformer_name(), vmSymbols::void_method_signature()); -+ if (method != NULL) { -+ methodHandle instanceTransformerMethod(method); -+ instanceTransformerMethods.append(instanceTransformerMethod); -+ break; -+ } else { -+ cur_klass = cur_klass->klass_part()->super(); -+ } -+ } -+ assert(cur_klass != NULL, "must have instance transformer method"); -+ } else { -+ instanceTransformerMethods.append(methodHandle(Thread::current(), NULL)); - } - } - +- } +- } +- - return true; -} // end rewrite_cp_refs_in_methods_default_annotations() - -+ // Call instance transformers -+ if (_updated_oops != NULL) { - +- +- -// 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 @@ -8747,11 +9004,7 @@ index 295ed86..fdfc6f4 100644 - case ITEM_UninitializedThis: - // nothing more to do for the above tag types - break; -+ for (int i=0; i<_updated_oops->length(); i++) { -+ assert(_updated_oops->at(i) != NULL, "must not be null!"); -+ Handle cur(_updated_oops->at(i)); -+ instanceKlassHandle klass(cur->klass()); - +- - // Object_variable_info { - // u1 tag = ITEM_Object; /* 7 */ - // u2 cpool_index; @@ -8782,8 +9035,7 @@ index 295ed86..fdfc6f4 100644 - assert(stackmap_p_ref + 2 <= stackmap_end, "no room for offset"); - stackmap_p_ref += 2; - break; -+ if (klass->check_redefinition_flag(Klass::HasInstanceTransformer)) { - +- - default: - RC_TRACE_WITH_THREAD(0x04000000, THREAD, - ("frame_i=%u, frame_type=%u, bad tag=0x%x", frame_i, frame_type, tag)); @@ -9005,54 +9257,422 @@ index 295ed86..fdfc6f4 100644 - } - } // end for each local variable table entry - } // end if there are local variable table entries -+ methodHandle method = instanceTransformerMethods.at(klass->redefinition_index()); -+ -+ RC_TRACE(0x00008000, ("executing transformer method")); -+ -+ Thread *__the_thread__ = Thread::current(); -+ JavaValue result(T_VOID); -+ JavaCallArguments args(cur); -+ JavaCalls::call(&result, -+ method, -+ &args, -+ THREAD); - +- - 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() -+ // TODO: What to do with an exception here? -+ if (HAS_PENDING_EXCEPTION) { -+ Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name(); -+ RC_TRACE(0x00000002, ("exception when executing transformer: '%s'", -+ ex_name->as_C_string())); -+ CLEAR_PENDING_EXCEPTION; -+ } -+ } -+ } - -+ delete _updated_oops; -+ _updated_oops = NULL; -+ } - +- +- -// 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; -+ RC_TRACE(0x00000001, ("Redefinition finished!")); - ++void VM_RedefineClasses::adjust_cpool_cache(klassOop k_oop_latest, oop initiating_loader, TRAPS) { ++ klassOop k_oop = k_oop_latest; ++ while (k_oop != NULL) { ++ //tty->print_cr("name=%s", k_oop->klass_part()->name()->as_C_string()); ++/* ++ methodOop *matching_old_methods = NEW_RESOURCE_ARRAY(methodOop, _old_methods->length()); ++ methodOop *matching_new_methods = NEW_RESOURCE_ARRAY(methodOop, _old_methods->length()); ++ ++ for (int i=0; i<_matching_methods_length; i++) { ++ matching_old_methods[i] = (methodOop)_old_methods->obj_at(_matching_old_methods[i]); ++ matching_new_methods[i] = (methodOop)_new_methods->obj_at(_matching_new_methods[i]); ++ }*/ ++ ++ Klass *k = k_oop->klass_part(); ++ if (k->oop_is_instance()) { ++ HandleMark hm(THREAD); ++ instanceKlass *ik = (instanceKlass *) k; ++ ++ constantPoolHandle other_cp; ++ constantPoolCacheOop cp_cache; ++ ++ other_cp = constantPoolHandle(ik->constants()); ++ ++ 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) { ++ ++ // (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!"); ++ } ++ } ++ ++ cp_cache = other_cp->cache(); ++ ++ if (cp_cache != NULL) { ++ cp_cache->adjust_entries(NULL, ++ NULL, ++ 0); ++ } ++ ++ // If bytecode rewriting is enabled, we also need to unpatch bytecode to force resolution of zeroied entries ++ if (RewriteBytecodes) { ++ ik->methods_do(unpatch_bytecode); ++ } ++ } ++ k_oop = k_oop->klass_part()->old_version(); ++ } ++} ++ ++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]); ++ RC_TRACE(0x00008000, ("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); ++ //RC_TRACE(0x00008000, ("Changed jmethodID for old method assigned to %d / result=%d", new_jmethod_id, result); ++ //RC_TRACE(0x00008000, ("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); ++ //RC_TRACE(0x00008000, ("Changed jmethodID for new method assigned to %d / result=%d", jmid, result); ++ ++ } ++ JNIHandles::change_method_associated_with_jmethod_id(jmid, new_method_h); ++ //RC_TRACE(0x00008000, ("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!"); ++ ++ //RC_TRACE(0x00008000, ("jmethodID new method: %d jmethodID old method: %d", new_method_h->jmethod_id(), old_method->jmethod_id()); ++ } ++ } ++} ++ ++ ++// 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"); ++ RC_TRACE(0x00008000, ("Matching methods = %d / deleted methods = %d / added methods = %d", ++ _matching_methods_length, _deleted_methods_length, _added_methods_length)); ++} ++ ++ ++ ++// 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(); ++ _the_class_oop = the_old_class(); ++ 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(); ++ ++ // keep track of previous versions of this class ++ the_new_class->add_previous_version(the_old_class, &emcp_methods, ++ emcp_method_count); ++ ++ // 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) { ++ RC_TRACE(0x00008000, ("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); ++ ++ RC_TRACE(0x00008000, ("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()) { ++ RC_TRACE(0x00000002, ("Checking breakpoint")); ++ RC_TRACE(0x00000002, ("%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"); ++ RC_TRACE(0x00000002, ("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. ++ RC_TRACE(0x00008000, ("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; ++ // 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(0x00008000, ("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"); ++ RC_TRACE(0x00008000, ("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); ++ RC_TRACE(0x00008000, ("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; +- - // HotSpot specific optimization! HotSpot does not currently - // support delegation from the bootstrap class loader to a - // user-defined class loader. This means that if the bootstrap @@ -9070,9 +9690,7 @@ index 295ed86..fdfc6f4 100644 - if (is_user_defined && ik->class_loader() == NULL) { - return; - } -+ RC_TIMER_STOP(_timer_vm_op_epilogue); -+} - +- - // This is a very busy routine. We don't want too much tracing - // printed out. - bool trace_name_printed = false; @@ -9091,7 +9709,10 @@ index 295ed86..fdfc6f4 100644 - // holds the methodOops for virtual (but not final) methods. - if (ik->vtable_length() > 0 && ik->is_subtype_of(_the_class_oop)) { - // ik->vtable() creates a wrapper object; rm cleans it up -- ResourceMark rm(THREAD); ++ assert(ik->is_newest_version(), "must be latest version in system dictionary"); ++ ++ if (ik->vtable_length() > 0) { + ResourceMark rm(THREAD); - ik->vtable()->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, @@ -9139,7 +9760,13 @@ index 295ed86..fdfc6f4 100644 - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); -- } ++ if (!ik->vtable()->check_no_old_entries()) { ++ RC_TRACE(0x00000001, ("size of class: %d\n", ++ k_oop->size())); ++ RC_TRACE(0x00000001, ("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ++ ik->signature_name())); ++ assert(false, "OLD method found"); + } - } - { - ResourceMark rm(THREAD); @@ -9163,19 +9790,9 @@ index 295ed86..fdfc6f4 100644 - } - } // pvw is cleaned up - } // rm is cleaned up -+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; - } - +- } +-} +- -void VM_RedefineClasses::update_jmethod_ids() { - for (int j = 0; j < _matching_methods_length; ++j) { - methodOop old_method = _matching_old_methods[j]; @@ -9186,16 +9803,9 @@ index 295ed86..fdfc6f4 100644 - JNIHandles::change_method_associated_with_jmethod_id(jmid, new_method_h); - assert(JNIHandles::resolve_jmethod_id(jmid) == _matching_new_methods[j], - "should be replaced"); -- } -+#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(); ++ ik->vtable()->verify(tty, true); + } } } @@ -9214,7 +9824,29 @@ index 295ed86..fdfc6f4 100644 - while ((old_array_method = (methodOop) _old_methods->obj_at(old_index)) - != old_method) { - ++old_index; -- } ++#endif ++ ++VM_RedefineClasses::FindAffectedKlassesClosure::FindAffectedKlassesClosure( GrowableArray<instanceKlassHandle> *original_klasses, GrowableArray<instanceKlassHandle> *result ) ++{ ++ assert(original_klasses != NULL && result != NULL, ""); ++ this->_original_klasses = original_klasses; ++ this->_result = result; ++ SystemDictionary::classes_do(this); ++} ++ ++void VM_RedefineClasses::FindAffectedKlassesClosure::do_object( oop obj ) ++{ ++ klassOop klass = (klassOop)obj; ++ assert(!_result->contains(klass), "must not occur more than once!"); ++ assert(klass->klass_part()->new_version() == NULL, "Only last version is valid entry in system dictionary"); ++ ++ for(int i=0; i<_original_klasses->length(); i++) { ++ instanceKlassHandle cur = _original_klasses->at(i); ++ if (cur() != klass && klass->klass_part()->is_subtype_of(cur()) && !_original_klasses->contains(klass)) { ++ RC_TRACE(0x00008000, ("Found affected class: %s", klass->klass_part()->name()->as_C_string())); ++ _result->append(klass); ++ break; + } - - if (MethodComparator::methods_EMCP(old_method, new_method)) { - // The EMCP definition from JSR-163 requires the bytecodes to be @@ -9292,35 +9924,50 @@ index 295ed86..fdfc6f4 100644 - // mark obsolete methods as such - old_method->set_is_obsolete(); - obsolete_count++; -+#endif - +- - // obsolete methods need a unique idnum - u2 num = instanceKlass::cast(_the_class_oop)->next_method_idnum(); - if (num != constMethodOopDesc::UNSET_IDNUM) { -// u2 old_num = old_method->method_idnum(); - old_method->set_method_idnum(num); -// TO DO: attach obsolete annotations to obsolete method's new idnum -+// 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. -+static void 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); ++jvmtiError VM_RedefineClasses::do_topological_class_sorting( const jvmtiClassDefinition *class_defs, int class_count, GrowableArray<instanceKlassHandle> *affected, GrowableArray<instanceKlassHandle> *arr, TRAPS) ++{ ++ GrowableArray< Pair<klassOop, klassOop> > *links = new GrowableArray< Pair<klassOop, klassOop> >(); ++ ++ for (int i=0; i<class_count; i++) { ++ ++ oop mirror = JNIHandles::resolve_non_null(class_defs[i].klass); ++ klassOop the_class_oop = java_lang_Class::as_klassOop(mirror); ++ instanceKlassHandle the_class(THREAD, the_class_oop); ++ 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; ++ RC_TRACE(0x00000002, ("Before find super symbols of class %s", ++ the_class->name()->as_C_string())); ++ cfp.findSuperSymbols(the_class->name(), the_class_loader, protection_domain, the_class, symbolArr, THREAD); ++ ++ for (int j=0; j<symbolArr.length(); j++) { ++ Symbol* sym = symbolArr.at(j); ++ ++ RC_TRACE(0x00008000, ("Before adding link to super class %s", sym->as_C_string())); ++ ++ for (int k=0; k<arr->length(); k++) { ++ klassOop curOop = arr->at(k)(); ++ // (tw) TODO: Check if we get aliasing problems with different class loaders? ++ if (curOop->klass_part()->name() == sym /*&& curOop->klass_part()->class_loader() == the_class_loader()*/) { ++ RC_TRACE(0x00000002, ("Found class to link")); ++ links->append(Pair<klassOop, klassOop>(curOop, the_class())); ++ break; ++ } } - // With tracing we try not to "yack" too much. The position of - // this trace assumes there are fewer obsolete methods than @@ -9328,26 +9975,9 @@ index 295ed86..fdfc6f4 100644 - RC_TRACE(0x00000100, ("mark %s(%s) as obsolete", - old_method->name()->as_C_string(), - old_method->signature()->as_C_string())); -+ } 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; -+ } -+ } -+ -+ // 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); } - old_method->set_is_old(); -- } + } - for (int i = 0; i < _deleted_methods_length; ++i) { - methodOop old_method = _deleted_methods[i]; - @@ -9364,62 +9994,124 @@ index 295ed86..fdfc6f4 100644 - RC_TRACE(0x00000100, ("mark deleted %s(%s) as obsolete", - old_method->name()->as_C_string(), - old_method->signature()->as_C_string())); -- } ++ ++ ++ RC_TRACE(0x00000001, ("Identified links between classes! ")); ++ ++ for (int i=0; i<affected->length(); i++) { ++ ++ instanceKlassHandle klass = affected->at(i); ++ ++ klassOop superKlass = klass->super(); ++ if (affected->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 (arr->contains(interfaceKlass)) { ++ links->append(Pair<klassOop, klassOop>(interfaceKlass, klass())); ++ } ++ } + } - 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)); ++ ++ if (RC_TRACE_ENABLED(0x00000002)) { ++ RC_TRACE(0x00000002, ("Identified links: ")); ++ for (int i=0; i<links->length(); i++) { ++ RC_TRACE(0x00000002, ("%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<arr->length(); i++) { ++ ++ int j; ++ for (j=i; j<arr->length(); j++) { ++ ++ int k; ++ for (k=0; k<links->length(); k++) { ++ ++ klassOop k1 = links->adr_at(k)->right(); ++ klassOop k2 = arr->at(j)(); ++ if (k1 == k2) { ++ break; ++ } ++ } ++ ++ if (k == links->length()) { ++ break; ++ } ++ } ++ ++ if (j == arr->length()) { ++ // circle detected ++ return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; ++ } ++ ++ for (int k=0; k<links->length(); k++) { ++ if (links->adr_at(k)->left() == arr->at(j)()) { ++ links->at_put(k, links->at(links->length() - 1)); ++ links->remove_at(links->length() - 1); ++ k--; ++ } ++ } ++ ++ instanceKlassHandle tmp = arr->at(j); ++ arr->at_put(j, arr->at(i)); ++ arr->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 -+// 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. ++void VM_RedefineClasses::oops_do(OopClosure *closure) { ++ ++ if (_updated_oops != NULL) { ++ for (int i=0; i<_updated_oops->length(); i++) { ++ closure->do_oop(_updated_oops->adr_at(i)); ++ } ++ } ++} ++ ++void VM_RedefineClasses::transfer_special_access_flags(fieldDescriptor *from, fieldDescriptor *to) { ++ to->set_is_field_modification_watched(from->is_field_modification_watched()); ++ to->set_is_field_access_watched(from->is_field_access_watched()); ++ if (from->is_field_modification_watched() || from->is_field_access_watched()) { ++ RC_TRACE(0x00000002, ("Transfered watch for field %s", ++ from->name()->as_C_string())); ++ } ++ update_klass_field_access_flag(to); ++} ++ ++void VM_RedefineClasses::update_klass_field_access_flag(fieldDescriptor *fd) { ++ instanceKlass* ik = instanceKlass::cast(fd->field_holder()); ++ FieldInfo* fi = FieldInfo::from_field_array(ik->fields(), fd->index()); ++ fi->set_access_flags(fd->access_flags().as_short()); ++} ++ ++ + // 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 +@@ -2842,7 +3167,7 @@ + // Same, caused by prefix removal only 3_2_1_m -> 3_2_m // --class TransferNativeFunctionRegistration { + class TransferNativeFunctionRegistration { - private: -- instanceKlassHandle the_class; -- int prefix_count; -- char** prefixes; -+// 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) { -+ //tty->print_cr("name=%s", k_oop->klass_part()->name()->as_C_string()); -+/* -+ methodOop *matching_old_methods = NEW_RESOURCE_ARRAY(methodOop, _old_methods->length()); -+ methodOop *matching_new_methods = NEW_RESOURCE_ARRAY(methodOop, _old_methods->length()); - -- // 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; +@@ -2855,42 +3180,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) { @@ -9435,12 +10127,17 @@ index 295ed86..fdfc6f4 100644 - method = search_prefix_name_space(depth+1, name_str, name_len, signature); - if (method != NULL) { - return method; // found -- } -+ for (int i=0; i<_matching_methods_length; i++) { -+ matching_old_methods[i] = (methodOop)_old_methods->obj_at(_matching_old_methods[i]); -+ matching_new_methods[i] = (methodOop)_new_methods->obj_at(_matching_new_methods[i]); -+ }*/ - ++ 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; + } +- - // Try adding this prefix to the method name and see if it matches - // another method name. - char* prefix = prefixes[depth]; @@ -9455,229 +10152,196 @@ index 295ed86..fdfc6f4 100644 - // If found along this branch, it was prefixed, mark as such - method->set_is_prefixed_native(); - return method; // found -- } -- } -- } ++ 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 -- } -+ Klass *k = k_oop->klass_part(); -+ if (k->oop_is_instance()) { -+ HandleMark hm(THREAD); -+ instanceKlass *ik = (instanceKlass *) k; - -- // 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(); -+ constantPoolHandle other_cp; -+ constantPoolCacheOop cp_cache; - -- // 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; -- } -+ other_cp = constantPoolHandle(ik->constants()); ++ return NULL; // This whole branch bore nothing + } -- // 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. +@@ -2915,10 +3240,10 @@ + ResourceMark rm; + char* name_str = method_name_without_prefixes(method); + return search_prefix_name_space(0, name_str, strlen(name_str), - method->signature()); -- } -+ 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) { -+ -+ // (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!"); -+ } -+ } ++ method->signature()); + } - public: -+ cp_cache = other_cp->cache(); - -- // Construct a native method transfer processor for this class. -- TransferNativeFunctionRegistration(instanceKlassHandle _the_class) { -- assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); -+ if (cp_cache != NULL) { -+ cp_cache->adjust_entries(NULL, -+ NULL, -+ 0); -+ } ++public: -- the_class = _the_class; -- prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count); -+ // If bytecode rewriting is enabled, we also need to unpatch bytecode to force resolution of zeroied entries -+ if (RewriteBytecodes) { -+ ik->methods_do(unpatch_bytecode); -+ } -+ } -+ k_oop = k_oop->klass_part()->old_version(); + // Construct a native method transfer processor for this class. + TransferNativeFunctionRegistration(instanceKlassHandle _the_class) { +@@ -2929,9 +3254,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]; -+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]); -+ RC_TRACE(0x00008000, ("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); -+ //RC_TRACE(0x00008000, ("Changed jmethodID for old method assigned to %d / result=%d", new_jmethod_id, result); -+ //RC_TRACE(0x00008000, ("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); -+ //RC_TRACE(0x00008000, ("Changed jmethodID for new method assigned to %d / result=%d", jmid, result); ++ 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); +@@ -2940,7 +3265,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); -- } - } -+ JNIHandles::change_method_associated_with_jmethod_id(jmid, new_method_h); -+ //RC_TRACE(0x00008000, ("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!"); ++ !methodOopDesc::native_bind_event_is_interesting); + -+ //RC_TRACE(0x00008000, ("jmethodID new method: %d jmethodID old method: %d", new_method_h->jmethod_id(), old_method->jmethod_id()); ++ RC_TRACE(0x00008000, ("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. +@@ -2948,494 +3275,8 @@ + }; + + // 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::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 -@@ -2974,7 +2683,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(); -@@ -2997,10 +2709,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; -@@ -3015,36 +2727,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; - } - } -@@ -3052,6 +2764,8 @@ 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"); -+ RC_TRACE(0x00008000, ("Matching methods = %d / deleted methods = %d / added methods = %d", -+ _matching_methods_length, _deleted_methods_length, _added_methods_length)); - } - - -@@ -3059,287 +2773,184 @@ 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 @@ -9685,47 +10349,35 @@ index 295ed86..fdfc6f4 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(); +- +-#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_class_oop); -+ jvmti_breakpoints.clearall_in_class_at_safepoint(the_old_class()); - #endif // !JVMTI_KERNEL - +-#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(); -+ _the_class_oop = the_old_class(); - compute_added_deleted_matching_methods(); +- compute_added_deleted_matching_methods(); - update_jmethod_ids(); - - // Attach new constant pool to the original klass. The original @@ -9821,17 +10473,12 @@ index 295ed86..fdfc6f4 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 @@ -9852,16 +10499,12 @@ index 295ed86..fdfc6f4 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); -+ // keep track of previous versions of this class -+ the_new_class->add_previous_version(the_old_class, &emcp_methods, -+ emcp_method_count); - +- - // Initialize the vtable and interface table after - // methods have been rewritten - { @@ -9875,26 +10518,20 @@ index 295ed86..fdfc6f4 100644 - the_class->itable()->initialize_itable(false, THREAD); - assert(!HAS_PENDING_EXCEPTION || (THREAD->pending_exception()->is_a(SystemDictionary::ThreadDeath_klass())), "redefine exception"); - } -+ // TODO: -+ transfer_old_native_function_registrations(the_old_class); - +- - // Leave arrays of jmethodIDs and itable index cache unchanged - +- - // Copy the "source file name" attribute from new class version - the_class->set_source_file_name(scratch_class->source_file_name()); -+#ifdef ASSERT - +- - // Copy the "source debug extension" attribute from new class version - the_class->set_source_debug_extension( - scratch_class->source_debug_extension()); -+// 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!"); - +- - // Use of javac -g could be different in the old and the new - if (scratch_class->access_flags().has_localvariable_table() != - the_class->access_flags().has_localvariable_table()) { -+ //JNIHandles::verify(); - +- - AccessFlags flags = the_class->access_flags(); - if (scratch_class->access_flags().has_localvariable_table()) { - flags.set_has_localvariable_table(); @@ -9950,157 +10587,46 @@ index 295ed86..fdfc6f4 100644 - scratch_class->enclosing_method_class_index(), - scratch_class->enclosing_method_method_index()); - scratch_class->set_enclosing_method_indices(old_class_idx, old_method_idx); -+// klassOop systemLookup = SystemDictionary::resolve_or_null(the_old_class->name(), the_old_class->class_loader(), the_old_class->protection_domain(), THREAD); - +- - // keep track of previous versions of this class - the_class->add_previous_version(scratch_class, &emcp_methods, - emcp_method_count); -+// 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"); - +- - RC_TIMER_STOP(_timer_rsc_phase1); - RC_TIMER_START(_timer_rsc_phase2); -+ 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!"); -+ } - +- - // Adjust constantpool caches and vtables for all classes - // that reference methods of the evolved class. - SystemDictionary::classes_do(adjust_cpool_cache_and_vtable, THREAD); -+ _old_methods->verify(); -+ _new_methods->verify(); - +- - 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(); - } -+ 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) { -+ RC_TRACE(0x00008000, ("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); -+ -+ RC_TRACE(0x00008000, ("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()) { -+ RC_TRACE(0x00000002, ("Checking breakpoint")); -+ RC_TRACE(0x00000002, ("%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"); -+ RC_TRACE(0x00000002, ("Found a breakpoint in an old EMCP method")); -+ new_method->set_breakpoint(bp->bci()); -+ } -+ } -+ -+ - +- - // 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)); -+ } 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. -+ RC_TRACE(0x00008000, ("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. -+ RC_TRACE(0x00008000, ("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"); -+ RC_TRACE(0x00008000, ("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. -@@ -3348,94 +2959,324 @@ 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() @@ -10117,37 +10643,28 @@ index 295ed86..fdfc6f4 100644 - increment_class_counter(subik, THREAD); - } - } -+ RC_TRACE(0x00008000, ("updated count for class=%s to %d", ik->external_name(), new_count)); - } - - #ifndef PRODUCT +-} +- +-#ifndef PRODUCT -void VM_RedefineClasses::check_class(klassOop k_oop, - oop initiating_loader, TRAPS) { -+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_entries()) { +- Klass *k = k_oop->klass_part(); +- if (k->oop_is_instance()) { +- HandleMark hm(THREAD); +- instanceKlass *ik = (instanceKlass *) k; +- +- if (ik->vtable_length() > 0) { +- ResourceMark rm(THREAD); +- if (!ik->vtable()->check_no_old_entries()) { - tty->print_cr("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); - ik->vtable()->dump_vtable(); - dump_methods(); -+ RC_TRACE(0x00000001, ("size of class: %d\n", -+ k_oop->size())); -+ RC_TRACE(0x00000001, ("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", -+ ik->signature_name())); - assert(false, "OLD method found"); - } -+ -+ ik->vtable()->verify(tty, true); - } - } - } - +- assert(false, "OLD method found"); +- } +- } +- } +-} +- -void VM_RedefineClasses::dump_methods() { - int j; - tty->print_cr("_old_methods --"); @@ -10167,66 +10684,7 @@ index 295ed86..fdfc6f4 100644 - tty->print(" -- "); - m->print_name(tty); - tty->cr(); -+#endif -+ -+VM_RedefineClasses::FindAffectedKlassesClosure::FindAffectedKlassesClosure( GrowableArray<instanceKlassHandle> *original_klasses, GrowableArray<instanceKlassHandle> *result ) -+{ -+ assert(original_klasses != NULL && result != NULL, ""); -+ this->_original_klasses = original_klasses; -+ this->_result = result; -+ SystemDictionary::classes_do(this); -+} -+ -+void VM_RedefineClasses::FindAffectedKlassesClosure::do_object( oop obj ) -+{ -+ klassOop klass = (klassOop)obj; -+ assert(!_result->contains(klass), "must not occur more than once!"); -+ assert(klass->klass_part()->new_version() == NULL, "Only last version is valid entry in system dictionary"); -+ -+ for(int i=0; i<_original_klasses->length(); i++) { -+ instanceKlassHandle cur = _original_klasses->at(i); -+ if (cur() != klass && klass->klass_part()->is_subtype_of(cur()) && !_original_klasses->contains(klass)) { -+ RC_TRACE(0x00008000, ("Found affected class: %s", klass->klass_part()->name()->as_C_string())); -+ _result->append(klass); -+ break; -+ } -+ } -+} -+ -+jvmtiError VM_RedefineClasses::do_topological_class_sorting( const jvmtiClassDefinition *class_defs, int class_count, GrowableArray<instanceKlassHandle> *affected, GrowableArray<instanceKlassHandle> *arr, TRAPS) -+{ -+ GrowableArray< Pair<klassOop, klassOop> > *links = new GrowableArray< Pair<klassOop, klassOop> >(); -+ -+ for (int i=0; i<class_count; i++) { -+ -+ oop mirror = JNIHandles::resolve_non_null(class_defs[i].klass); -+ klassOop the_class_oop = java_lang_Class::as_klassOop(mirror); -+ instanceKlassHandle the_class(THREAD, the_class_oop); -+ 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; -+ RC_TRACE(0x00000002, ("Before find super symbols of class %s", -+ the_class->name()->as_C_string())); -+ cfp.findSuperSymbols(the_class->name(), the_class_loader, protection_domain, the_class, symbolArr, THREAD); -+ -+ for (int j=0; j<symbolArr.length(); j++) { -+ Symbol* sym = symbolArr.at(j); -+ -+ RC_TRACE(0x00008000, ("Before adding link to super class %s", sym->as_C_string())); -+ -+ for (int k=0; k<arr->length(); k++) { -+ klassOop curOop = arr->at(k)(); -+ // (tw) TODO: Check if we get aliasing problems with different class loaders? -+ if (curOop->klass_part()->name() == sym /*&& curOop->klass_part()->class_loader() == the_class_loader()*/) { -+ RC_TRACE(0x00000002, ("Found class to link")); -+ links->append(Pair<klassOop, klassOop>(curOop, the_class())); -+ break; - } +- } - tty->print_cr("_matching_(old/new)_methods --"); - for (j = 0; j < _matching_methods_length; ++j) { - methodOop m = _matching_old_methods[j]; @@ -10239,53 +10697,7 @@ index 295ed86..fdfc6f4 100644 - tty->print(" (%5d) ", m->vtable_index()); - m->access_flags().print_on(tty); - tty->cr(); -+ } -+ } -+ } -+ -+ -+ RC_TRACE(0x00000001, ("Identified links between classes! ")); -+ -+ for (int i=0; i<affected->length(); i++) { -+ -+ instanceKlassHandle klass = affected->at(i); -+ -+ klassOop superKlass = klass->super(); -+ if (affected->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 (arr->contains(interfaceKlass)) { -+ links->append(Pair<klassOop, klassOop>(interfaceKlass, klass())); -+ } -+ } -+ } -+ -+ if (RC_TRACE_ENABLED(0x00000002)) { -+ RC_TRACE(0x00000002, ("Identified links: ")); -+ for (int i=0; i<links->length(); i++) { -+ RC_TRACE(0x00000002, ("%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<arr->length(); i++) { -+ -+ int j; -+ for (j=i; j<arr->length(); j++) { -+ -+ int k; -+ for (k=0; k<links->length(); k++) { -+ -+ klassOop k1 = links->adr_at(k)->right(); -+ klassOop k2 = arr->at(j)(); -+ if (k1 == k2) { -+ break; - } +- } - tty->print_cr("_deleted_methods --"); - for (j = 0; j < _deleted_methods_length; ++j) { - methodOop m = _deleted_methods[j]; @@ -10294,128 +10706,7 @@ index 295ed86..fdfc6f4 100644 - tty->print(" -- "); - m->print_name(tty); - tty->cr(); -+ } -+ -+ if (k == links->length()) { -+ break; -+ } -+ } -+ -+ if (j == arr->length()) { -+ // circle detected -+ return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; -+ } -+ -+ for (int k=0; k<links->length(); k++) { -+ if (links->adr_at(k)->left() == arr->at(j)()) { -+ links->at_put(k, links->at(links->length() - 1)); -+ links->remove_at(links->length() - 1); -+ k--; -+ } -+ } -+ -+ instanceKlassHandle tmp = arr->at(j); -+ arr->at_put(j, arr->at(i)); -+ arr->at_put(i, tmp); -+ } -+ -+ return JVMTI_ERROR_NONE; -+} -+ -+void VM_RedefineClasses::oops_do(OopClosure *closure) { -+ -+ if (_updated_oops != NULL) { -+ for (int i=0; i<_updated_oops->length(); i++) { -+ closure->do_oop(_updated_oops->adr_at(i)); -+ } -+ } -+} -+ -+void VM_RedefineClasses::transfer_special_access_flags(fieldDescriptor *from, fieldDescriptor *to) { -+ to->set_is_field_modification_watched(from->is_field_modification_watched()); -+ to->set_is_field_access_watched(from->is_field_access_watched()); -+ if (from->is_field_modification_watched() || from->is_field_access_watched()) { -+ RC_TRACE(0x00000002, ("Transfered watch for field %s", -+ from->name()->as_C_string())); -+ } -+ update_klass_field_access_flag(to); -+} -+ -+void VM_RedefineClasses::update_klass_field_access_flag(fieldDescriptor *fd) { -+ instanceKlass* ik = instanceKlass::cast(fd->field_holder()); -+ FieldInfo* fi = FieldInfo::from_field_array(ik->fields(), fd->index()); -+ fi->set_access_flags(fd->access_flags().as_short()); -+} -+ -+ -+// 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 -+ } -+ } - } +- } - tty->print_cr("_added_methods --"); - for (j = 0; j < _added_methods_length; ++j) { - methodOop m = _added_methods[j]; @@ -10424,75 +10715,10 @@ index 295ed86..fdfc6f4 100644 - tty->print(" -- "); - m->print_name(tty); - tty->cr(); -+ } -+ 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); -+ -+ RC_TRACE(0x00008000, ("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); - } +- } +-} -#endif diff --git a/src/share/vm/prims/jvmtiRedefineClasses.hpp b/src/share/vm/prims/jvmtiRedefineClasses.hpp -index c5f4bdd..88fdbac 100644 --- a/src/share/vm/prims/jvmtiRedefineClasses.hpp +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp @@ -1,26 +1,29 @@ @@ -10861,10 +11087,9 @@ index c5f4bdd..88fdbac 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 { +#define RC_ABORT(error) { _result = error; return false; } -+ + +-class VM_RedefineClasses: public VM_Operation { +class VM_RedefineClasses: public VM_GC_Operation { private: + @@ -10890,7 +11115,7 @@ index c5f4bdd..88fdbac 100644 // The instance fields are used to pass information from // doit_prologue() to doit() and doit_epilogue(). jint _class_count; -@@ -370,36 +70,29 @@ class VM_RedefineClasses: public VM_Operation { +@@ -370,36 +70,29 @@ // _index_map_p contains any entries. int _index_map_count; intArray * _index_map_p; @@ -10908,13 +11133,6 @@ index c5f4bdd..88fdbac 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; @@ -10924,7 +11142,13 @@ index c5f4bdd..88fdbac 100644 + elapsedTimer _timer_wait_for_locks; + 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(GrowableArray<instanceKlassHandle> *all_affected_klasses); + jvmtiError find_class_bytes(instanceKlassHandle the_class, const unsigned char **class_bytes, jint *class_byte_count, jboolean *not_changed); @@ -10944,7 +11168,7 @@ index c5f4bdd..88fdbac 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,96 +100,100 @@ class VM_RedefineClasses: public VM_Operation { +@@ -407,96 +100,100 @@ // Change jmethodIDs to point to the new methods void update_jmethod_ids(); @@ -10958,7 +11182,12 @@ index c5f4bdd..88fdbac 100644 - int * emcp_method_count_p); - void transfer_old_native_function_registrations(instanceKlassHandle the_class); + class FindAffectedKlassesClosure : public ObjectClosure { -+ + +- // 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); + private: + GrowableArray<instanceKlassHandle> *_original_klasses; + GrowableArray<instanceKlassHandle> *_result; @@ -10969,12 +11198,7 @@ index c5f4bdd..88fdbac 100644 + virtual void do_object(oop 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 jvmtiError do_topological_class_sorting(const jvmtiClassDefinition *class_definitions, int class_count, GrowableArray<instanceKlassHandle> *affected, GrowableArray<instanceKlassHandle> *arr, TRAPS); // Install the redefinition of a class @@ -11035,7 +11259,8 @@ index c5f4bdd..88fdbac 100644 - static void check_class(klassOop k_oop, oop initiating_loader, TRAPS) PRODUCT_RETURN; + static void check_class(klassOop k_oop,/* oop initiating_loader,*/ TRAPS) PRODUCT_RETURN; -+ + +- static void dump_methods() PRODUCT_RETURN; + static void adjust_cpool_cache(klassOop k_oop, oop initiating_loader, TRAPS); + +#ifdef ASSERT @@ -11045,8 +11270,7 @@ index c5f4bdd..88fdbac 100644 + int calculate_redefinition_flags(instanceKlassHandle new_version); + void calculate_instance_update_information(klassOop new_version); + void check_methods_and_mark_as_obsolete(BitMap *emcp_methods, int * emcp_method_count_p); - -- static void dump_methods() PRODUCT_RETURN; ++ + static void calculate_type_check_information(klassOop k); + static void clear_type_check_information(klassOop k); @@ -11114,10 +11338,9 @@ index c5f4bdd..88fdbac 100644 #endif // SHARE_VM_PRIMS_JVMTIREDEFINECLASSES_HPP + diff --git a/src/share/vm/prims/methodComparator.cpp b/src/share/vm/prims/methodComparator.cpp -index 60eaf97..38d3194 100644 --- a/src/share/vm/prims/methodComparator.cpp +++ b/src/share/vm/prims/methodComparator.cpp -@@ -65,6 +65,37 @@ bool MethodComparator::methods_EMCP(methodOop old_method, methodOop new_method) +@@ -65,6 +65,37 @@ if (! args_same(c_old, c_new)) return false; } @@ -11156,7 +11379,6 @@ index 60eaf97..38d3194 100644 } diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp -index f8c627d..aa95bd4 100644 --- a/src/share/vm/prims/nativeLookup.cpp +++ b/src/share/vm/prims/nativeLookup.cpp @@ -35,6 +35,7 @@ @@ -11175,7 +11397,7 @@ index f8c627d..aa95bd4 100644 static void mangle_name_on(outputStream* st, Symbol* name, int begin, int end) { char* bytes = (char*)name->bytes() + begin; char* end_bytes = (char*)name->bytes() + end; -@@ -136,6 +136,40 @@ static JNINativeMethod lookup_special_native_methods[] = { +@@ -136,6 +136,40 @@ { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) } }; @@ -11216,7 +11438,7 @@ index f8c627d..aa95bd4 100644 static address lookup_special_native(char* jni_name) { int i = !JDK_Version::is_gte_jdk14x_version() ? 0 : 2; // see comment in lookup_special_native_methods int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod); -@@ -175,6 +209,9 @@ address NativeLookup::lookup_style(methodHandle method, char* pure_name, const c +@@ -175,6 +209,9 @@ return entry; } } @@ -11227,10 +11449,9 @@ index f8c627d..aa95bd4 100644 // Otherwise call static method findNative in ClassLoader KlassHandle klass (THREAD, SystemDictionary::ClassLoader_klass()); diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp -index 1d3b887..aa223a4 100644 --- a/src/share/vm/runtime/arguments.cpp +++ b/src/share/vm/runtime/arguments.cpp -@@ -1747,6 +1747,15 @@ bool Arguments::check_gc_consistency() { +@@ -1747,6 +1747,15 @@ status = false; } @@ -11247,10 +11468,9 @@ index 1d3b887..aa223a4 100644 } diff --git a/src/share/vm/runtime/deoptimization.cpp b/src/share/vm/runtime/deoptimization.cpp -index 0e2a983..0adca35 100644 --- a/src/share/vm/runtime/deoptimization.cpp +++ b/src/share/vm/runtime/deoptimization.cpp -@@ -595,6 +595,38 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m +@@ -595,6 +595,38 @@ // Cleanup thread deopt data cleanup_deopt_info(thread, array); @@ -11290,10 +11510,9 @@ index 0e2a983..0adca35 100644 if (VerifyStack) { ResourceMark res_mark; diff --git a/src/share/vm/runtime/frame.cpp b/src/share/vm/runtime/frame.cpp -index 7ae9aa8..e9ca96c 100644 --- a/src/share/vm/runtime/frame.cpp +++ b/src/share/vm/runtime/frame.cpp -@@ -403,6 +403,12 @@ void frame::interpreter_frame_set_method(methodOop method) { +@@ -403,6 +403,12 @@ *interpreter_frame_method_addr() = method; } @@ -11306,7 +11525,7 @@ index 7ae9aa8..e9ca96c 100644 void frame::interpreter_frame_set_bcx(intptr_t bcx) { assert(is_interpreted_frame(), "Not an interpreted frame"); if (ProfileInterpreter) { -@@ -418,19 +424,27 @@ void frame::interpreter_frame_set_bcx(intptr_t bcx) { +@@ -418,19 +424,27 @@ // The bcx was just converted from bci to bcp. // Convert the mdx in parallel. methodDataOop mdo = interpreter_frame_method()->method_data(); @@ -11342,10 +11561,9 @@ index 7ae9aa8..e9ca96c 100644 } } diff --git a/src/share/vm/runtime/frame.hpp b/src/share/vm/runtime/frame.hpp -index c55380e..342dec7 100644 --- a/src/share/vm/runtime/frame.hpp +++ b/src/share/vm/runtime/frame.hpp -@@ -346,6 +346,7 @@ class frame VALUE_OBJ_CLASS_SPEC { +@@ -346,6 +346,7 @@ // Method & constant pool cache methodOop interpreter_frame_method() const; void interpreter_frame_set_method(methodOop method); @@ -11354,10 +11572,9 @@ index c55380e..342dec7 100644 constantPoolCacheOop* interpreter_frame_cache_addr() const; #ifdef PPC diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp -index e41e2e3..b39ffc9 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp -@@ -1309,9 +1309,23 @@ class CommandLineFlags { +@@ -1309,9 +1309,23 @@ product(bool, StressLdcRewrite, false, \ "Force ldc -> ldc_w rewrite during RedefineClasses") \ \ @@ -11382,10 +11599,9 @@ index e41e2e3..b39ffc9 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 e1001ee..b034760 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. @@ -11395,10 +11611,9 @@ index e1001ee..b034760 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"); @@ -11408,10 +11623,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) { @@ -11423,10 +11637,9 @@ index 3cbcaca..30839d7 100644 } diff --git a/src/share/vm/runtime/mutex.cpp b/src/share/vm/runtime/mutex.cpp -index 9fc1560..03706c9 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) { @@ -11435,7 +11648,7 @@ index 9fc1560..03706c9 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) { @@ -11444,7 +11657,7 @@ index 9fc1560..03706c9 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 && @@ -11453,10 +11666,9 @@ index 9fc1560..03706c9 100644 !SafepointSynchronize::is_at_safepoint() && this != Interrupt_lock && this != ProfileVM_lock && diff --git a/src/share/vm/runtime/mutex.hpp b/src/share/vm/runtime/mutex.hpp -index 66a3295..a053204 100644 --- a/src/share/vm/runtime/mutex.hpp +++ b/src/share/vm/runtime/mutex.hpp -@@ -109,7 +109,8 @@ class Monitor : public CHeapObj { +@@ -109,7 +109,8 @@ barrier = safepoint + 1, nonleaf = barrier + 1, max_nonleaf = nonleaf + 900, @@ -11467,7 +11679,6 @@ index 66a3295..a053204 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 f1911ea..ef85adf 100644 --- a/src/share/vm/runtime/mutexLocker.cpp +++ b/src/share/vm/runtime/mutexLocker.cpp @@ -49,6 +49,7 @@ @@ -11478,7 +11689,7 @@ index f1911ea..ef85adf 100644 Monitor* SystemDictionary_lock = NULL; Mutex* PackageTable_lock = NULL; Mutex* CompiledIC_lock = NULL; -@@ -90,6 +91,7 @@ Mutex* Shared_SATB_Q_lock = NULL; +@@ -90,6 +91,7 @@ Mutex* DirtyCardQ_FL_lock = NULL; Monitor* DirtyCardQ_CBL_mon = NULL; Mutex* Shared_DirtyCardQ_lock = NULL; @@ -11486,7 +11697,7 @@ index f1911ea..ef85adf 100644 Mutex* ParGCRareEvent_lock = NULL; Mutex* EvacFailureStack_lock = NULL; Mutex* DerivedPointerTableGC_lock = NULL; -@@ -205,6 +207,7 @@ void mutex_init() { +@@ -205,6 +207,7 @@ def(HotCardCache_lock , Mutex , special , true ); def(EvacFailureStack_lock , Mutex , nonleaf , true ); } @@ -11494,7 +11705,7 @@ index f1911ea..ef85adf 100644 def(ParGCRareEvent_lock , Mutex , leaf , true ); def(DerivedPointerTableGC_lock , Mutex, leaf, true ); def(CodeCache_lock , Mutex , special, true ); -@@ -279,6 +282,7 @@ void mutex_init() { +@@ -279,6 +282,7 @@ def(Debug2_lock , Mutex , nonleaf+4, true ); def(Debug3_lock , Mutex , nonleaf+4, true ); def(ProfileVM_lock , Monitor, nonleaf+4, false); // used for profiling of the VMThread @@ -11503,7 +11714,6 @@ index f1911ea..ef85adf 100644 def(JfrQuery_lock , Monitor, nonleaf, true); // JFR locks, keep these in consecutive order diff --git a/src/share/vm/runtime/mutexLocker.hpp b/src/share/vm/runtime/mutexLocker.hpp -index 846b2d4..c20d12d 100644 --- a/src/share/vm/runtime/mutexLocker.hpp +++ b/src/share/vm/runtime/mutexLocker.hpp @@ -43,6 +43,8 @@ @@ -11516,10 +11726,9 @@ index 846b2d4..c20d12d 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 29858be..d37e928 100644 --- a/src/share/vm/runtime/reflection.cpp +++ b/src/share/vm/runtime/reflection.cpp -@@ -469,7 +469,8 @@ bool Reflection::verify_class_access(klassOop current_class, klassOop new_class, +@@ -469,7 +469,8 @@ // sun/reflect/MagicAccessorImpl subclasses to succeed trivially. if ( JDK_Version::is_gte_jdk14x_version() && UseNewReflection @@ -11529,7 +11738,7 @@ index 29858be..d37e928 100644 return true; } -@@ -525,6 +526,12 @@ bool Reflection::verify_field_access(klassOop current_class, +@@ -525,6 +526,12 @@ AccessFlags access, bool classloader_only, bool protected_restriction) { @@ -11542,7 +11751,7 @@ index 29858be..d37e928 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. -@@ -566,7 +573,8 @@ bool Reflection::verify_field_access(klassOop current_class, +@@ -566,7 +573,8 @@ // sun/reflect/MagicAccessorImpl subclasses to succeed trivially. if ( JDK_Version::is_gte_jdk14x_version() && UseNewReflection @@ -11553,10 +11762,9 @@ index 29858be..d37e928 100644 } diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp -index 503ad07..623cf8a 100644 --- a/src/share/vm/runtime/sharedRuntime.cpp +++ b/src/share/vm/runtime/sharedRuntime.cpp -@@ -1139,7 +1139,20 @@ methodHandle SharedRuntime::resolve_helper(JavaThread *thread, +@@ -1139,7 +1139,20 @@ if (JvmtiExport::can_hotswap_or_post_breakpoint()) { int retry_count = 0; while (!HAS_PENDING_EXCEPTION && callee_method->is_old() && @@ -11579,10 +11787,9 @@ index 503ad07..623cf8a 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 7676682..d2862bd 100644 --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp -@@ -212,6 +212,8 @@ Thread::Thread() { +@@ -212,6 +212,8 @@ set_self_raw_id(0); set_lgrp_id(-1); @@ -11591,7 +11798,7 @@ index 7676682..d2862bd 100644 // allocated data structures set_osthread(NULL); set_resource_area(new ResourceArea()); -@@ -246,6 +248,7 @@ Thread::Thread() { +@@ -246,6 +248,7 @@ omFreeProvision = 32 ; omInUseList = NULL ; omInUseCount = 0 ; @@ -11599,7 +11806,7 @@ index 7676682..d2862bd 100644 #ifdef ASSERT _visited_for_critical_count = false; -@@ -857,6 +860,15 @@ bool Thread::owns_locks_but_compiled_lock() const { +@@ -857,6 +860,15 @@ return false; } @@ -11615,7 +11822,7 @@ index 7676682..d2862bd 100644 #endif -@@ -1507,7 +1519,7 @@ void JavaThread::run() { +@@ -1507,7 +1519,7 @@ ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm); assert(JavaThread::current() == this, "sanity check"); @@ -11624,7 +11831,7 @@ index 7676682..d2862bd 100644 DTRACE_THREAD_PROBE(start, this); -@@ -3045,7 +3057,7 @@ static void compiler_thread_entry(JavaThread* thread, TRAPS) { +@@ -3045,7 +3057,7 @@ // Create a CompilerThread CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters) @@ -11633,7 +11840,7 @@ index 7676682..d2862bd 100644 _env = NULL; _log = NULL; _task = NULL; -@@ -3053,6 +3065,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters) +@@ -3053,6 +3065,7 @@ _counters = counters; _buffer_blob = NULL; _scanned_nmethod = NULL; @@ -11641,7 +11848,7 @@ index 7676682..d2862bd 100644 #ifndef PRODUCT _ideal_graph_printer = NULL; -@@ -3082,6 +3095,7 @@ int Threads::_number_of_threads = 0; +@@ -3082,6 +3095,7 @@ int Threads::_number_of_non_daemon_threads = 0; int Threads::_return_code = 0; size_t JavaThread::_stack_size_at_create = 0; @@ -11650,10 +11857,9 @@ index 7676682..d2862bd 100644 // All JavaThreads #define ALL_JAVA_THREADS(X) for (JavaThread* X = _thread_list; X; X = X->next()) diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp -index 7846cc0..a8bf2c5 100644 --- a/src/share/vm/runtime/thread.hpp +++ b/src/share/vm/runtime/thread.hpp -@@ -197,11 +197,14 @@ class Thread: public ThreadShadow { +@@ -197,11 +197,14 @@ void enter_signal_handler() { _num_nested_signal++; } void leave_signal_handler() { _num_nested_signal--; } bool is_inside_signal_handler() const { return _num_nested_signal > 0; } @@ -11668,7 +11874,7 @@ index 7846cc0..a8bf2c5 100644 // Active_handles points to a block of handles JNIHandleBlock* _active_handles; -@@ -522,10 +525,15 @@ public: +@@ -522,10 +525,15 @@ uintptr_t _self_raw_id; // used by get_thread (mutable) int _lgrp_id; @@ -11684,7 +11890,7 @@ index 7846cc0..a8bf2c5 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; } -@@ -563,6 +571,7 @@ public: +@@ -563,6 +571,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; } @@ -11692,7 +11898,7 @@ index 7846cc0..a8bf2c5 100644 bool owns_locks_but_compiled_lock() const; // Deadlock detection -@@ -1745,6 +1754,8 @@ class CompilerThread : public JavaThread { +@@ -1745,6 +1754,8 @@ CompileTask* _task; CompileQueue* _queue; BufferBlob* _buffer_blob; @@ -11701,7 +11907,7 @@ index 7846cc0..a8bf2c5 100644 nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper -@@ -1754,12 +1765,16 @@ class CompilerThread : public JavaThread { +@@ -1754,12 +1765,16 @@ CompilerThread(CompileQueue* queue, CompilerCounters* counters); @@ -11718,7 +11924,7 @@ index 7846cc0..a8bf2c5 100644 // Get/set the thread's compilation environment. ciEnv* env() { return _env; } -@@ -1814,6 +1829,7 @@ class Threads: AllStatic { +@@ -1814,6 +1829,7 @@ static int _number_of_threads; static int _number_of_non_daemon_threads; static int _return_code; @@ -11726,7 +11932,7 @@ index 7846cc0..a8bf2c5 100644 public: // Thread management -@@ -1825,6 +1841,9 @@ class Threads: AllStatic { +@@ -1825,6 +1841,9 @@ static JavaThread* first() { return _thread_list; } static void threads_do(ThreadClosure* tc); @@ -11737,10 +11943,9 @@ index 7846cc0..a8bf2c5 100644 static jint create_vm(JavaVMInitArgs* args, bool* canTryAgain); static void convert_vm_init_libraries_to_agents(); diff --git a/src/share/vm/runtime/vframe.cpp b/src/share/vm/runtime/vframe.cpp -index 323d735..ec1f8ca 100644 --- a/src/share/vm/runtime/vframe.cpp +++ b/src/share/vm/runtime/vframe.cpp -@@ -253,6 +253,46 @@ methodOop interpretedVFrame::method() const { +@@ -253,6 +253,46 @@ return fr().interpreter_frame_method(); } @@ -11788,10 +11993,9 @@ index 323d735..ec1f8ca 100644 int length = method()->max_locals(); diff --git a/src/share/vm/runtime/vframe.hpp b/src/share/vm/runtime/vframe.hpp -index badfea5..edbc5c7 100644 --- a/src/share/vm/runtime/vframe.hpp +++ b/src/share/vm/runtime/vframe.hpp -@@ -163,6 +163,7 @@ class interpretedVFrame: public javaVFrame { +@@ -163,6 +163,7 @@ StackValueCollection* locals() const; StackValueCollection* expressions() const; GrowableArray<MonitorInfo*>* monitors() const; @@ -11800,10 +12004,9 @@ index badfea5..edbc5c7 100644 void set_locals(StackValueCollection* values) const; diff --git a/src/share/vm/runtime/vmThread.cpp b/src/share/vm/runtime/vmThread.cpp -index d4fced2..9efee22 100644 --- a/src/share/vm/runtime/vmThread.cpp +++ b/src/share/vm/runtime/vmThread.cpp -@@ -671,6 +671,9 @@ void VMThread::execute(VM_Operation* op) { +@@ -671,6 +671,9 @@ void VMThread::oops_do(OopClosure* f, CodeBlobClosure* cf) { Thread::oops_do(f, cf); _vm_queue->oops_do(f); @@ -11814,10 +12017,9 @@ index d4fced2..9efee22 100644 //------------------------------------------------------------------------------------------------------------------ diff --git a/src/share/vm/utilities/exceptions.cpp b/src/share/vm/utilities/exceptions.cpp -index 874d8e5..d860aa9 100644 --- a/src/share/vm/utilities/exceptions.cpp +++ b/src/share/vm/utilities/exceptions.cpp -@@ -251,6 +251,8 @@ Handle Exceptions::new_exception(Thread *thread, Symbol* h_name, +@@ -251,6 +251,8 @@ assert(thread->is_Java_thread(), "can only be called by a Java thread"); assert(!thread->has_pending_exception(), "already has exception"); @@ -11826,7 +12028,7 @@ index 874d8e5..d860aa9 100644 Handle h_exception; // Resolve exception klass -@@ -298,6 +300,8 @@ Handle Exceptions::new_exception(Thread *thread, Symbol* h_name, +@@ -298,6 +300,8 @@ h_exception = Handle(thread, thread->pending_exception()); thread->clear_pending_exception(); } @@ -11836,10 +12038,9 @@ index 874d8e5..d860aa9 100644 } diff --git a/src/share/vm/utilities/growableArray.hpp b/src/share/vm/utilities/growableArray.hpp -index 34972be..49fc03d 100644 --- a/src/share/vm/utilities/growableArray.hpp +++ b/src/share/vm/utilities/growableArray.hpp -@@ -135,6 +135,33 @@ class GenericGrowableArray : public ResourceObj { +@@ -135,6 +135,33 @@ assert(on_stack(), "fast ResourceObj path only"); return (void*)resource_allocate_bytes(thread, elementSize * _max); } diff --git a/patches/full-jdk7u45-b08.patch b/hotspot/.hg/patches/full-jdk7u45-b08.patch index ee3ce329..9d61ec1d 100644 --- a/patches/full-jdk7u45-b08.patch +++ b/hotspot/.hg/patches/full-jdk7u45-b08.patch @@ -14,18 +14,6 @@ index 2310141..8ddb2ab 100644 # version 4 and above support fvisibility=hidden (matches jni_x86.h file) # except 4.1.2 gives pointless warnings that can't be disabled (afaik) ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -diff --git a/make/openjdk_distro b/make/openjdk_distro -index 520b33d..ea7eff0 100644 ---- a/make/openjdk_distro -+++ b/make/openjdk_distro -@@ -27,6 +27,6 @@ - # - - # Don't put quotes (fail windows build). --HOTSPOT_VM_DISTRO=OpenJDK -+HOTSPOT_VM_DISTRO=Dynamic Code Evolution - COMPANY_NAME= - PRODUCT_NAME=OpenJDK diff --git a/src/cpu/x86/vm/templateTable_x86_32.cpp b/src/cpu/x86/vm/templateTable_x86_32.cpp index fc19edc..d2cddd3 100644 --- a/src/cpu/x86/vm/templateTable_x86_32.cpp diff --git a/patches/full-jdk7u51-b13.patch b/hotspot/.hg/patches/full-jdk7u51-b13.patch index acfb9325..e9abeb8d 100644 --- a/patches/full-jdk7u51-b13.patch +++ b/hotspot/.hg/patches/full-jdk7u51-b13.patch @@ -13,17 +13,6 @@ diff -r 6c6a2299029a make/bsd/makefiles/gcc.make # version 4 and above support fvisibility=hidden (matches jni_x86.h file) # except 4.1.2 gives pointless warnings that can't be disabled (afaik) ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -diff -r 6c6a2299029a make/openjdk_distro ---- a/make/openjdk_distro Sat Dec 14 11:51:15 2013 -0800 -+++ b/make/openjdk_distro Mon Apr 28 13:12:30 2014 -0700 -@@ -27,6 +27,6 @@ - # - - # Don't put quotes (fail windows build). --HOTSPOT_VM_DISTRO=OpenJDK -+HOTSPOT_VM_DISTRO=Dynamic Code Evolution - COMPANY_NAME= - PRODUCT_NAME=OpenJDK diff -r 6c6a2299029a src/cpu/x86/vm/templateTable_x86_32.cpp --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Sat Dec 14 11:51:15 2013 -0800 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Mon Apr 28 13:12:30 2014 -0700 diff --git a/hotspot/.hg/patches/gc-java8.patch b/hotspot/.hg/patches/gc-java8.patch new file mode 100644 index 00000000..b190c7d8 --- /dev/null +++ b/hotspot/.hg/patches/gc-java8.patch @@ -0,0 +1,613 @@ +Change MarkAndSweep garbage collector to allow changing instances during redefinition. +diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp ++++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +@@ -161,6 +161,12 @@ + } + } + ++HeapWord* CompactibleFreeListSpace::forward_compact_top(size_t size, ++ CompactPoint* cp, HeapWord* compact_top) { ++ ShouldNotReachHere(); ++ return NULL; ++} ++ + // 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. +@@ -2098,7 +2104,7 @@ + // Support for compaction + + void CompactibleFreeListSpace::prepare_for_compaction(CompactPoint* cp) { +- SCAN_AND_FORWARD(cp,end,block_is_obj,block_size); ++ SCAN_AND_FORWARD(cp,end,block_is_obj,block_size,false); + // 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. +@@ -2119,7 +2125,7 @@ + } + + void CompactibleFreeListSpace::compact() { +- SCAN_AND_COMPACT(obj_size); ++ SCAN_AND_COMPACT(obj_size, false); + } + + // 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 +--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp ++++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +@@ -150,6 +150,7 @@ + + // Support for compacting cms + HeapWord* cross_threshold(HeapWord* start, HeapWord* end); ++ HeapWord* forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top); + HeapWord* forward(oop q, size_t size, CompactPoint* cp, HeapWord* compact_top); + + // Initialization helpers. +diff --git a/src/share/vm/gc_implementation/shared/markSweep.cpp b/src/share/vm/gc_implementation/shared/markSweep.cpp +--- a/src/share/vm/gc_implementation/shared/markSweep.cpp ++++ b/src/share/vm/gc_implementation/shared/markSweep.cpp +@@ -46,6 +46,8 @@ + STWGCTimer* MarkSweep::_gc_timer = NULL; + SerialOldTracer* MarkSweep::_gc_tracer = NULL; + ++GrowableArray<HeapWord*>* MarkSweep::_rescued_oops = NULL; ++ + MarkSweep::FollowRootClosure MarkSweep::follow_root_closure; + CodeBlobToOopClosure MarkSweep::follow_code_root_closure(&MarkSweep::follow_root_closure, /*do_marking=*/ true); + +@@ -171,3 +173,100 @@ + } + + #endif ++ ++// (DCEVM) Copy the rescued objects to their destination address after compaction. ++void MarkSweep::copy_rescued_objects_back() { ++ ++ if (_rescued_oops != NULL) { ++ ++ for (int i=0; i<_rescued_oops->length(); i++) { ++ HeapWord* rescued_ptr = _rescued_oops->at(i); ++ oop rescued_obj = (oop) rescued_ptr; ++ ++ int size = rescued_obj->size(); ++ oop new_obj = rescued_obj->forwardee(); ++ ++ assert(rescued_obj->klass()->new_version() != NULL, "just checking"); ++ ++ if (rescued_obj->klass()->new_version()->update_information() != NULL) { ++ MarkSweep::update_fields(rescued_obj, new_obj); ++ } else { ++ rescued_obj->set_klass(rescued_obj->klass()->new_version()); ++ Copy::aligned_disjoint_words((HeapWord*)rescued_obj, (HeapWord*)new_obj, size); ++ } ++ ++ FREE_RESOURCE_ARRAY(HeapWord, rescued_ptr, size); ++ ++ new_obj->init_mark(); ++ assert(new_obj->is_oop(), "must be a valid oop"); ++ } ++ _rescued_oops->clear(); ++ _rescued_oops = NULL; ++ } ++} ++ ++// (DCEVM) Update instances of a class whose fields changed. ++void MarkSweep::update_fields(oop q, oop new_location) { ++ ++ assert(q->klass()->new_version() != NULL, "class of old object must have new version"); ++ ++ Klass* old_klass_oop = q->klass(); ++ Klass* new_klass_oop = q->klass()->new_version(); ++ ++ InstanceKlass *old_klass = InstanceKlass::cast(old_klass_oop); ++ InstanceKlass *new_klass = InstanceKlass::cast(new_klass_oop); ++ ++ int size = q->size_given_klass(old_klass); ++ int new_size = q->size_given_klass(new_klass); ++ ++ HeapWord* tmp = NULL; ++ oop tmp_obj = q; ++ ++ // Save object somewhere, there is an overlap in fields ++ if (new_klass_oop->is_copying_backwards()) { ++ if (((HeapWord *)q >= (HeapWord *)new_location && (HeapWord *)q < (HeapWord *)new_location + new_size) || ++ ((HeapWord *)new_location >= (HeapWord *)q && (HeapWord *)new_location < (HeapWord *)q + size)) { ++ tmp = NEW_RESOURCE_ARRAY(HeapWord, size); ++ q = (oop) tmp; ++ Copy::aligned_disjoint_words((HeapWord*)q, (HeapWord*)tmp_obj, size); ++ } ++ } ++ ++ q->set_klass(new_klass_oop); ++ int *cur = new_klass_oop->update_information(); ++ assert(cur != NULL, "just checking"); ++ MarkSweep::update_fields(new_location, q, cur); ++ ++ if (tmp != NULL) { ++ FREE_RESOURCE_ARRAY(HeapWord, tmp, size); ++ } ++} ++ ++void MarkSweep::update_fields(oop new_location, oop tmp_obj, int *cur) { ++ assert(cur != NULL, "just checking"); ++ char* to = (char*)(HeapWord*)new_location; ++ while (*cur != 0) { ++ int size = *cur; ++ if (size > 0) { ++ cur++; ++ int offset = *cur; ++ HeapWord* from = (HeapWord*)(((char *)(HeapWord*)tmp_obj) + offset); ++ if (size == HeapWordSize) { ++ *((HeapWord*)to) = *from; ++ } else if (size == HeapWordSize * 2) { ++ *((HeapWord*)to) = *from; ++ *(((HeapWord*)to) + 1) = *(from + 1); ++ } else { ++ Copy::conjoint_jbytes(from, to, size); ++ } ++ to += size; ++ cur++; ++ } else { ++ assert(size < 0, ""); ++ int skip = -*cur; ++ Copy::fill_to_bytes(to, skip, 0); ++ to += skip; ++ cur++; ++ } ++ } ++} +diff --git a/src/share/vm/gc_implementation/shared/markSweep.hpp b/src/share/vm/gc_implementation/shared/markSweep.hpp +--- a/src/share/vm/gc_implementation/shared/markSweep.hpp ++++ b/src/share/vm/gc_implementation/shared/markSweep.hpp +@@ -107,8 +107,12 @@ + friend class AdjustPointerClosure; + friend class KeepAliveClosure; + friend class VM_MarkSweep; ++ friend class GenMarkSweep; + friend void marksweep_init(); + ++public: ++ static GrowableArray<HeapWord*>* _rescued_oops; ++ + // + // Vars + // +@@ -169,6 +173,9 @@ + + static inline void push_objarray(oop obj, size_t index); + ++ static void copy_rescued_objects_back(); ++ static void update_fields(oop q, oop new_location); ++ static void update_fields(oop new_location, oop tmp_obj, int *cur); + static void follow_stack(); // Empty marking stack. + + static void follow_klass(Klass* klass); +diff --git a/src/share/vm/memory/genMarkSweep.cpp b/src/share/vm/memory/genMarkSweep.cpp +--- a/src/share/vm/memory/genMarkSweep.cpp ++++ b/src/share/vm/memory/genMarkSweep.cpp +@@ -334,11 +334,16 @@ + // 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. ++ assert(_rescued_oops == NULL, "must be empty before processing"); + GenCollectedHeap* gch = GenCollectedHeap::heap(); + + GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer); + trace("4"); + ++ MarkSweep::copy_rescued_objects_back(); ++ + GenCompactClosure blk; + gch->generation_iterate(&blk, true); ++ ++ MarkSweep::copy_rescued_objects_back(); + } +diff --git a/src/share/vm/memory/space.cpp b/src/share/vm/memory/space.cpp +--- a/src/share/vm/memory/space.cpp ++++ b/src/share/vm/memory/space.cpp +@@ -379,9 +379,8 @@ + _compaction_top = bottom(); + } + +-HeapWord* CompactibleSpace::forward(oop q, size_t size, +- CompactPoint* cp, HeapWord* compact_top) { +- // q is alive ++// (DCEVM) Calculates the compact_top that will be used for placing the next object with the giving size on the heap. ++HeapWord* CompactibleSpace::forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top) { + // 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); +@@ -401,8 +400,15 @@ + compaction_max_size = pointer_delta(cp->space->end(), compact_top); + } + ++ return compact_top; ++} ++ ++HeapWord* CompactibleSpace::forward(oop q, size_t size, ++ CompactPoint* cp, HeapWord* compact_top) { ++ compact_top = forward_compact_top(size, cp, compact_top); ++ + // store the forwarding pointer into the mark word +- if ((HeapWord*)q != compact_top) { ++ if ((HeapWord*)q != compact_top || (size_t)q->size() != size) { + q->forward_to(oop(compact_top)); + assert(q->is_gc_marked(), "encoding the pointer should preserve the mark"); + } else { +@@ -423,6 +429,58 @@ + return compact_top; + } + ++// Compute the forward sizes and leave out objects whose position could ++// possibly overlap other objects. ++HeapWord* CompactibleSpace::forward_with_rescue(HeapWord* q, size_t size, ++ CompactPoint* cp, HeapWord* compact_top) { ++ size_t forward_size = size; ++ ++ // (DCEVM) There is a new version of the class of q => different size ++ if (oop(q)->klass()->new_version() != NULL && oop(q)->klass()->new_version()->update_information() != NULL) { ++ ++ size_t new_size = oop(q)->size_given_klass(oop(q)->klass()->new_version()); ++ assert(size != new_size, "instances without changed size have to be updated prior to GC run"); ++ forward_size = new_size; ++ } ++ ++ compact_top = forward_compact_top(forward_size, cp, compact_top); ++ ++ if (must_rescue(oop(q), oop(compact_top))) { ++ if (MarkSweep::_rescued_oops == NULL) { ++ MarkSweep::_rescued_oops = new GrowableArray<HeapWord*>(128); ++ } ++ MarkSweep::_rescued_oops->append(q); ++ return compact_top; ++ } ++ ++ return forward(oop(q), forward_size, cp, compact_top); ++} ++ ++// Compute the forwarding addresses for the objects that need to be rescued. ++HeapWord* CompactibleSpace::forward_rescued(CompactPoint* cp, HeapWord* compact_top) { ++ // TODO: empty the _rescued_oops after ALL spaces are compacted! ++ if (MarkSweep::_rescued_oops != NULL) { ++ for (int i=0; i<MarkSweep::_rescued_oops->length(); i++) { ++ HeapWord* q = MarkSweep::_rescued_oops->at(i); ++ ++ /* size_t size = oop(q)->size(); changing this for cms for perm gen */ ++ size_t size = block_size(q); ++ ++ // (DCEVM) There is a new version of the class of q => different size ++ if (oop(q)->klass()->new_version() != NULL) { ++ size_t new_size = oop(q)->size_given_klass(oop(q)->klass()->new_version()); ++ assert(size != new_size, "instances without changed size have to be updated prior to GC run"); ++ size = new_size; ++ } ++ ++ compact_top = cp->space->forward(oop(q), size, cp, compact_top); ++ assert(compact_top <= end(), "must not write over end of space!"); ++ } ++ MarkSweep::_rescued_oops->clear(); ++ MarkSweep::_rescued_oops = NULL; ++ } ++ return compact_top; ++} + + bool CompactibleSpace::insert_deadspace(size_t& allowed_deadspace_words, + HeapWord* q, size_t deadlength) { +@@ -444,12 +502,17 @@ + #define adjust_obj_size(s) s + + void CompactibleSpace::prepare_for_compaction(CompactPoint* cp) { +- SCAN_AND_FORWARD(cp, end, block_is_obj, block_size); ++ SCAN_AND_FORWARD(cp, end, block_is_obj, block_size, false); + } + + // Faster object search. + void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) { +- SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size); ++ if (!Universe::is_redefining_gc_run()) { ++ SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size, false); ++ } else { ++ // Redefinition run ++ SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size, true); ++ } + } + + void Space::adjust_pointers() { +@@ -487,6 +550,111 @@ + assert(q == t, "just checking"); + } + ++ ++#ifdef ASSERT ++ ++int CompactibleSpace::space_index(oop obj) { ++ GenCollectedHeap* heap = GenCollectedHeap::heap(); ++ ++ //if (heap->is_in_permanent(obj)) { ++ // return -1; ++ //} ++ ++ int index = 0; ++ for (int i = heap->n_gens() - 1; i >= 0; i--) { ++ Generation* gen = heap->get_gen(i); ++ CompactibleSpace* space = gen->first_compaction_space(); ++ while (space != NULL) { ++ if (space->is_in_reserved(obj)) { ++ return index; ++ } ++ space = space->next_compaction_space(); ++ index++; ++ } ++ } ++ ++ tty->print_cr("could not compute space_index for %08xh", (HeapWord*)obj); ++ index = 0; ++ for (int i = heap->n_gens() - 1; i >= 0; i--) { ++ Generation* gen = heap->get_gen(i); ++ tty->print_cr(" generation %s: %08xh - %08xh", gen->name(), gen->reserved().start(), gen->reserved().end()); ++ ++ CompactibleSpace* space = gen->first_compaction_space(); ++ while (space != NULL) { ++ tty->print_cr(" %2d space %08xh - %08xh", index, space->bottom(), space->end()); ++ space = space->next_compaction_space(); ++ index++; ++ } ++ } ++ ++ ShouldNotReachHere(); ++ return 0; ++} ++#endif ++ ++bool CompactibleSpace::must_rescue(oop old_obj, oop new_obj) { ++ // Only redefined objects can have the need to be rescued. ++ if (oop(old_obj)->klass()->new_version() == NULL) return false; ++ ++ //if (old_obj->is_perm()) { ++ // // This object is in perm gen: Always rescue to satisfy invariant obj->klass() <= obj. ++ // return true; ++ //} ++ ++ int new_size = old_obj->size_given_klass(oop(old_obj)->klass()->new_version()); ++ int original_size = old_obj->size(); ++ ++ Generation* tenured_gen = GenCollectedHeap::heap()->get_gen(1); ++ bool old_in_tenured = tenured_gen->is_in_reserved(old_obj); ++ bool new_in_tenured = tenured_gen->is_in_reserved(new_obj); ++ if (old_in_tenured == new_in_tenured) { ++ // Rescue if object may overlap with a higher memory address. ++ bool overlap = ((HeapWord*)old_obj + original_size < (HeapWord*)new_obj + new_size); ++ if (old_in_tenured) { ++ // Old and new address are in same space, so just compare the address. ++ // Must rescue if object moves towards the top of the space. ++ assert(space_index(old_obj) == space_index(new_obj), "old_obj and new_obj must be in same space"); ++ } else { ++ // In the new generation, eden is located before the from space, so a ++ // simple pointer comparison is sufficient. ++ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(old_obj), "old_obj must be in DefNewGeneration"); ++ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(new_obj), "new_obj must be in DefNewGeneration"); ++ assert(overlap == (space_index(old_obj) < space_index(new_obj)), "slow and fast computation must yield same result"); ++ } ++ return overlap; ++ ++ } else { ++ assert(space_index(old_obj) != space_index(new_obj), "old_obj and new_obj must be in different spaces"); ++ if (tenured_gen->is_in_reserved(new_obj)) { ++ // Must never rescue when moving from the new into the old generation. ++ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(old_obj), "old_obj must be in DefNewGeneration"); ++ assert(space_index(old_obj) > space_index(new_obj), "must be"); ++ return false; ++ ++ } else /* if (tenured_gen->is_in_reserved(old_obj)) */ { ++ // Must always rescue when moving from the old into the new generation. ++ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(new_obj), "new_obj must be in DefNewGeneration"); ++ assert(space_index(old_obj) < space_index(new_obj), "must be"); ++ return true; ++ } ++ } ++} ++ ++HeapWord* CompactibleSpace::rescue(HeapWord* old_obj) { ++ assert(must_rescue(oop(old_obj), oop(old_obj)->forwardee()), "do not call otherwise"); ++ ++ int size = oop(old_obj)->size(); ++ HeapWord* rescued_obj = NEW_RESOURCE_ARRAY(HeapWord, size); ++ Copy::aligned_disjoint_words(old_obj, rescued_obj, size); ++ ++ if (MarkSweep::_rescued_oops == NULL) { ++ MarkSweep::_rescued_oops = new GrowableArray<HeapWord*>(128); ++ } ++ ++ MarkSweep::_rescued_oops->append(rescued_obj); ++ return rescued_obj; ++} ++ + void CompactibleSpace::adjust_pointers() { + // Check first is there is any work to do. + if (used() == 0) { +@@ -497,7 +665,12 @@ + } + + void CompactibleSpace::compact() { +- SCAN_AND_COMPACT(obj_size); ++ if(!Universe::is_redefining_gc_run()) { ++ SCAN_AND_COMPACT(obj_size, false); ++ } else { ++ // Redefinition run ++ SCAN_AND_COMPACT(obj_size, true) ++ } + } + + 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 +--- a/src/share/vm/memory/space.hpp ++++ b/src/share/vm/memory/space.hpp +@@ -450,6 +450,9 @@ + // indicates when the next such action should be taken. + virtual void prepare_for_compaction(CompactPoint* cp); + // MarkSweep support phase3 ++ DEBUG_ONLY(int space_index(oop obj)); ++ bool must_rescue(oop old_obj, oop new_obj); ++ HeapWord* rescue(HeapWord* old_obj); + virtual void adjust_pointers(); + // MarkSweep support phase4 + virtual void compact(); +@@ -479,6 +482,15 @@ + // accordingly". + virtual HeapWord* forward(oop q, size_t size, CompactPoint* cp, + HeapWord* compact_top); ++ // (DCEVM) same as forwad, but can rescue objects. Invoked only during ++ // redefinition runs ++ HeapWord* forward_with_rescue(HeapWord* q, size_t size, CompactPoint* cp, ++ HeapWord* compact_top); ++ ++ HeapWord* forward_rescued(CompactPoint* cp, HeapWord* compact_top); ++ ++ // (tw) Compute new compact top without actually forwarding the object. ++ virtual HeapWord* forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top); + + // Return a size with adjusments as required of the space. + virtual size_t adjust_object_size_v(size_t size) const { return size; } +@@ -509,7 +521,7 @@ + size_t word_len); + }; + +-#define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size) { \ ++#define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size,redefinition_run) { \ + /* Compute the new addresses for the live objects and store it in the mark \ + * Used by universe::mark_sweep_phase2() \ + */ \ +@@ -567,7 +579,17 @@ + /* prefetch beyond q */ \ + Prefetch::write(q, interval); \ + size_t size = block_size(q); \ ++ if (redefinition_run) { \ ++ compact_top = cp->space->forward_with_rescue(q, size, \ ++ cp, compact_top); \ ++ if (q < first_dead && oop(q)->is_gc_marked()) { \ ++ /* Was moved (otherwise, forward would reset mark), \ ++ set first_dead to here */ \ ++ first_dead = q; \ ++ } \ ++ } else { \ + compact_top = cp->space->forward(oop(q), size, cp, compact_top); \ ++ } \ + q += size; \ + end_of_live = q; \ + } else { \ +@@ -616,6 +638,8 @@ + } \ + } \ + \ ++ if (redefinition_run) { compact_top = forward_rescued(cp, compact_top); } \ ++ \ + assert(q == t, "just checking"); \ + if (liveRange != NULL) { \ + liveRange->set_end(q); \ +@@ -662,13 +686,8 @@ + q += size; \ + } \ + \ +- if (_first_dead == t) { \ +- q = t; \ +- } else { \ +- /* $$$ This is funky. Using this to read the previously written \ +- * LiveRange. See also use below. */ \ +- q = (HeapWord*)oop(_first_dead)->mark()->decode_pointer(); \ +- } \ ++ /* (DCEVM) first_dead can be live object if we move/rescue resized objects */ \ ++ q = _first_dead; \ + } \ + \ + const intx interval = PrefetchScanIntervalInBytes; \ +@@ -696,7 +715,7 @@ + assert(q == t, "just checking"); \ + } + +-#define SCAN_AND_COMPACT(obj_size) { \ ++#define SCAN_AND_COMPACT(obj_size, redefinition_run) { \ + /* Copy all live objects to their new location \ + * Used by MarkSweep::mark_sweep_phase4() */ \ + \ +@@ -721,13 +740,9 @@ + } \ + ) /* debug_only */ \ + \ +- if (_first_dead == t) { \ +- q = t; \ +- } else { \ +- /* $$$ Funky */ \ +- q = (HeapWord*) oop(_first_dead)->mark()->decode_pointer(); \ ++ /* (DCEVM) first_dead can be live object if we move/rescue resized objects */ \ ++ q = _first_dead; \ + } \ +- } \ + \ + const intx scan_interval = PrefetchScanIntervalInBytes; \ + const intx copy_interval = PrefetchCopyIntervalInBytes; \ +@@ -745,11 +760,34 @@ + size_t size = obj_size(q); \ + HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); \ + \ ++ if (redefinition_run && must_rescue(oop(q), oop(q)->forwardee())) { \ ++ rescue(q); \ ++ debug_only(Copy::fill_to_words(q, size, 0)); \ ++ q += size; \ ++ continue; \ ++ } \ ++ \ + /* prefetch beyond compaction_top */ \ + Prefetch::write(compaction_top, copy_interval); \ + \ + /* copy object and reinit its mark */ \ +- assert(q != compaction_top, "everything in this pass should be moving"); \ ++ assert(q != compaction_top || oop(q)->klass()->new_version() != NULL, \ ++ "everything in this pass should be moving"); \ ++ if (redefinition_run && oop(q)->klass()->new_version() != NULL) { \ ++ Klass* new_version = oop(q)->klass()->new_version(); \ ++ if (new_version->update_information() == NULL) { \ ++ Copy::aligned_conjoint_words(q, compaction_top, size); \ ++ oop(compaction_top)->set_klass(new_version); \ ++ } else { \ ++ MarkSweep::update_fields(oop(q), oop(compaction_top)); \ ++ } \ ++ oop(compaction_top)->init_mark(); \ ++ assert(oop(compaction_top)->klass() != NULL, "should have a class"); \ ++ \ ++ debug_only(prev_q = q); \ ++ q += size; \ ++ continue; \ ++ } \ + Copy::aligned_conjoint_words(q, compaction_top, size); \ + oop(compaction_top)->init_mark(); \ + assert(oop(compaction_top)->klass() != NULL, "should have a class"); \ +diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp +--- a/src/share/vm/memory/universe.cpp ++++ b/src/share/vm/memory/universe.cpp +@@ -78,6 +78,8 @@ + #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" + #endif // INCLUDE_ALL_GCS + ++bool Universe::_is_redefining_gc_run = false; ++ + // Known objects + Klass* Universe::_boolArrayKlassObj = NULL; + Klass* Universe::_byteArrayKlassObj = NULL; +diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp +--- a/src/share/vm/memory/universe.hpp ++++ b/src/share/vm/memory/universe.hpp +@@ -248,7 +248,13 @@ + + static void compute_verify_oop_data(); + ++ static bool _is_redefining_gc_run; ++ + public: ++ ++ static bool is_redefining_gc_run() { return _is_redefining_gc_run; } ++ static void set_redefining_gc_run(bool b) { _is_redefining_gc_run = b; } ++ + // Known classes in the VM + static Klass* boolArrayKlassObj() { return _boolArrayKlassObj; } + static Klass* byteArrayKlassObj() { return _byteArrayKlassObj; } diff --git a/patches/light-jdk7u40-b43.patch b/hotspot/.hg/patches/light-jdk7u40-b43.patch index ef29e2be..e78e6599 100644 --- a/patches/light-jdk7u40-b43.patch +++ b/hotspot/.hg/patches/light-jdk7u40-b43.patch @@ -1,15 +1,3 @@ -diff --git a/make/openjdk_distro b/make/openjdk_distro -index 520b33d..ea7eff0 100644 ---- a/make/openjdk_distro -+++ b/make/openjdk_distro -@@ -27,6 +27,6 @@ - # - - # Don't put quotes (fail windows build). --HOTSPOT_VM_DISTRO=OpenJDK -+HOTSPOT_VM_DISTRO=Dynamic Code Evolution - COMPANY_NAME= - PRODUCT_NAME=OpenJDK 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 diff --git a/patches/light-jdk7u51-b13.patch b/hotspot/.hg/patches/light-jdk7u51-b13.patch index 3dcee7eb..96049ec2 100644 --- a/patches/light-jdk7u51-b13.patch +++ b/hotspot/.hg/patches/light-jdk7u51-b13.patch @@ -1,15 +1,3 @@ -diff --git a/make/openjdk_distro b/make/openjdk_distro -index 520b33d..ea7eff0 100644 ---- a/make/openjdk_distro -+++ b/make/openjdk_distro -@@ -27,6 +27,6 @@ - # - - # Don't put quotes (fail windows build). --HOTSPOT_VM_DISTRO=OpenJDK -+HOTSPOT_VM_DISTRO=Dynamic Code Evolution - COMPANY_NAME= - PRODUCT_NAME=OpenJDK 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 diff --git a/hotspot/.hg/patches/light-jdk8u5-b13.patch b/hotspot/.hg/patches/light-jdk8u5-b13.patch index 32152bc1..3e7d9894 100644 --- a/hotspot/.hg/patches/light-jdk8u5-b13.patch +++ b/hotspot/.hg/patches/light-jdk8u5-b13.patch @@ -1,20 +1,6 @@ -# HG changeset patch -# Parent 8a67179106085689906732013a282efeeb9bd5f4 - -diff --git a/make/openjdk_distro b/make/openjdk_distro ---- a/make/openjdk_distro -+++ b/make/openjdk_distro -@@ -27,6 +27,6 @@ - # - - # Don't put quotes (fail windows build). --HOTSPOT_VM_DISTRO=OpenJDK -+HOTSPOT_VM_DISTRO=Dynamic Code Evolution - COMPANY_NAME= - PRODUCT_NAME=OpenJDK -diff --git a/src/share/vm/ci/ciObjectFactory.cpp b/src/share/vm/ci/ciObjectFactory.cpp ---- a/src/share/vm/ci/ciObjectFactory.cpp -+++ b/src/share/vm/ci/ciObjectFactory.cpp +diff -r 8a6717910608 src/share/vm/ci/ciObjectFactory.cpp +--- a/src/share/vm/ci/ciObjectFactory.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/ci/ciObjectFactory.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -750,3 +750,27 @@ _unloaded_instances->length(), _unloaded_klasses->length()); @@ -43,9 +29,9 @@ diff --git a/src/share/vm/ci/ciObjectFactory.cpp b/src/share/vm/ci/ciObjectFacto +#endif // ASSERT +} + -diff --git a/src/share/vm/ci/ciObjectFactory.hpp b/src/share/vm/ci/ciObjectFactory.hpp ---- a/src/share/vm/ci/ciObjectFactory.hpp -+++ b/src/share/vm/ci/ciObjectFactory.hpp +diff -r 8a6717910608 src/share/vm/ci/ciObjectFactory.hpp +--- a/src/share/vm/ci/ciObjectFactory.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/ci/ciObjectFactory.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -90,6 +90,7 @@ ciInstance* get_unloaded_instance(ciInstanceKlass* klass); @@ -63,9 +49,9 @@ diff --git a/src/share/vm/ci/ciObjectFactory.hpp b/src/share/vm/ci/ciObjectFacto }; #endif // SHARE_VM_CI_CIOBJECTFACTORY_HPP -diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp ---- a/src/share/vm/classfile/classFileParser.cpp -+++ b/src/share/vm/classfile/classFileParser.cpp +diff -r 8a6717910608 src/share/vm/classfile/classFileParser.cpp +--- a/src/share/vm/classfile/classFileParser.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/classFileParser.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -759,6 +759,7 @@ Array<Klass*>* ClassFileParser::parse_interfaces(int length, Handle protection_domain, @@ -237,9 +223,9 @@ diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile k->set_is_cloneable(); } } -diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp ---- a/src/share/vm/classfile/classFileParser.hpp -+++ b/src/share/vm/classfile/classFileParser.hpp +diff -r 8a6717910608 src/share/vm/classfile/classFileParser.hpp +--- a/src/share/vm/classfile/classFileParser.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/classFileParser.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -214,11 +214,12 @@ Array<Klass*>* parse_interfaces(int length, Handle protection_domain, @@ -285,9 +271,9 @@ diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile TempNewSymbol& parsed_name, bool verify, TRAPS); -diff --git a/src/share/vm/classfile/classLoader.cpp b/src/share/vm/classfile/classLoader.cpp ---- a/src/share/vm/classfile/classLoader.cpp -+++ b/src/share/vm/classfile/classLoader.cpp +diff -r 8a6717910608 src/share/vm/classfile/classLoader.cpp +--- a/src/share/vm/classfile/classLoader.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/classLoader.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -926,6 +926,7 @@ instanceKlassHandle result = parser.parseClassFile(h_name, loader_data, @@ -296,9 +282,9 @@ diff --git a/src/share/vm/classfile/classLoader.cpp b/src/share/vm/classfile/cla parsed_name, false, CHECK_(h)); -diff --git a/src/share/vm/classfile/dictionary.cpp b/src/share/vm/classfile/dictionary.cpp ---- a/src/share/vm/classfile/dictionary.cpp -+++ b/src/share/vm/classfile/dictionary.cpp +diff -r 8a6717910608 src/share/vm/classfile/dictionary.cpp +--- a/src/share/vm/classfile/dictionary.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/dictionary.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -145,7 +145,7 @@ InstanceKlass* ik = InstanceKlass::cast(e); @@ -368,9 +354,9 @@ diff --git a/src/share/vm/classfile/dictionary.cpp b/src/share/vm/classfile/dict } -diff --git a/src/share/vm/classfile/dictionary.hpp b/src/share/vm/classfile/dictionary.hpp ---- a/src/share/vm/classfile/dictionary.hpp -+++ b/src/share/vm/classfile/dictionary.hpp +diff -r 8a6717910608 src/share/vm/classfile/dictionary.hpp +--- a/src/share/vm/classfile/dictionary.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/dictionary.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -78,6 +78,10 @@ void add_klass(Symbol* class_name, ClassLoaderData* loader_data,KlassHandle obj); @@ -394,9 +380,9 @@ diff --git a/src/share/vm/classfile/dictionary.hpp b/src/share/vm/classfile/dict // Unload (that is, break root links to) all unmarked classes and // loaders. Returns "true" iff something was unloaded. bool do_unloading(); -diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp ---- a/src/share/vm/classfile/javaClasses.cpp -+++ b/src/share/vm/classfile/javaClasses.cpp +diff -r 8a6717910608 src/share/vm/classfile/javaClasses.cpp +--- a/src/share/vm/classfile/javaClasses.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/javaClasses.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -1629,6 +1629,8 @@ skip_throwableInit_check = true; } @@ -406,9 +392,9 @@ diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/jav if (method->is_hidden()) { if (skip_hidden) continue; } -diff --git a/src/share/vm/classfile/loaderConstraints.cpp b/src/share/vm/classfile/loaderConstraints.cpp ---- a/src/share/vm/classfile/loaderConstraints.cpp -+++ b/src/share/vm/classfile/loaderConstraints.cpp +diff -r 8a6717910608 src/share/vm/classfile/loaderConstraints.cpp +--- a/src/share/vm/classfile/loaderConstraints.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/loaderConstraints.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -446,7 +446,7 @@ if (k != NULL) { // We found the class in the system dictionary, so we should @@ -418,9 +404,9 @@ diff --git a/src/share/vm/classfile/loaderConstraints.cpp b/src/share/vm/classfi } else { // 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 ---- a/src/share/vm/classfile/systemDictionary.cpp -+++ b/src/share/vm/classfile/systemDictionary.cpp +diff -r 8a6717910608 src/share/vm/classfile/systemDictionary.cpp +--- a/src/share/vm/classfile/systemDictionary.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/systemDictionary.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -174,6 +174,7 @@ // can return a null klass klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD); @@ -572,9 +558,9 @@ diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfil linkage_error = "loader (instance of %s): attempted duplicate class " "definition for name: \"%s\""; } else { -diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp ---- a/src/share/vm/classfile/systemDictionary.hpp -+++ b/src/share/vm/classfile/systemDictionary.hpp +diff -r 8a6717910608 src/share/vm/classfile/systemDictionary.hpp +--- a/src/share/vm/classfile/systemDictionary.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/systemDictionary.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -269,7 +269,7 @@ // Resolve from stream (called by jni_DefineClass and JVM_DefineClass) static Klass* resolve_from_stream(Symbol* class_name, Handle class_loader, @@ -612,9 +598,9 @@ diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfil static instanceKlassHandle find_or_define_instance_class(Symbol* class_name, Handle class_loader, instanceKlassHandle k, TRAPS); -diff --git a/src/share/vm/classfile/verifier.cpp b/src/share/vm/classfile/verifier.cpp ---- a/src/share/vm/classfile/verifier.cpp -+++ b/src/share/vm/classfile/verifier.cpp +diff -r 8a6717910608 src/share/vm/classfile/verifier.cpp +--- a/src/share/vm/classfile/verifier.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/verifier.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -189,7 +189,7 @@ Symbol* name = klass->name(); Klass* refl_magic_klass = SystemDictionary::reflect_MagicAccessorImpl_klass(); @@ -642,9 +628,9 @@ diff --git a/src/share/vm/classfile/verifier.cpp b/src/share/vm/classfile/verifi int num_methods = methods->length(); for (int index = 0; index < num_methods; index++) { -diff --git a/src/share/vm/classfile/verifier.hpp b/src/share/vm/classfile/verifier.hpp ---- a/src/share/vm/classfile/verifier.hpp -+++ b/src/share/vm/classfile/verifier.hpp +diff -r 8a6717910608 src/share/vm/classfile/verifier.hpp +--- a/src/share/vm/classfile/verifier.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/classfile/verifier.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -331,6 +331,7 @@ VerificationType object_type() const; @@ -653,193 +639,9 @@ diff --git a/src/share/vm/classfile/verifier.hpp b/src/share/vm/classfile/verifi instanceKlassHandle _klass; // the class being verified methodHandle _method; // current method being verified VerificationType _this_type; // the verification type of the current class -diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp ---- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp -+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp -@@ -161,6 +161,12 @@ - } - } - -+HeapWord* CompactibleFreeListSpace::forward_compact_top(size_t size, -+ CompactPoint* cp, HeapWord* compact_top) { -+ ShouldNotReachHere(); -+ return NULL; -+} -+ - // 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. -@@ -2098,7 +2104,7 @@ - // Support for compaction - - void CompactibleFreeListSpace::prepare_for_compaction(CompactPoint* cp) { -- SCAN_AND_FORWARD(cp,end,block_is_obj,block_size); -+ SCAN_AND_FORWARD(cp,end,block_is_obj,block_size,false); - // 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. -@@ -2119,7 +2125,7 @@ - } - - void CompactibleFreeListSpace::compact() { -- SCAN_AND_COMPACT(obj_size); -+ SCAN_AND_COMPACT(obj_size, false); - } - - // 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 ---- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp -+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp -@@ -150,6 +150,7 @@ - - // Support for compacting cms - HeapWord* cross_threshold(HeapWord* start, HeapWord* end); -+ HeapWord* forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top); - HeapWord* forward(oop q, size_t size, CompactPoint* cp, HeapWord* compact_top); - - // Initialization helpers. -diff --git a/src/share/vm/gc_implementation/shared/markSweep.cpp b/src/share/vm/gc_implementation/shared/markSweep.cpp ---- a/src/share/vm/gc_implementation/shared/markSweep.cpp -+++ b/src/share/vm/gc_implementation/shared/markSweep.cpp -@@ -32,6 +32,8 @@ - #include "oops/objArrayKlass.inline.hpp" - #include "oops/oop.inline.hpp" - -+GrowableArray<HeapWord*>* MarkSweep::_rescued_oops = NULL; -+ - uint MarkSweep::_total_invocations = 0; - - Stack<oop, mtGC> MarkSweep::_marking_stack; -@@ -171,3 +173,100 @@ - } - - #endif -+ -+// (DCEVM) Copy the rescued objects to their destination address after compaction. -+void MarkSweep::copy_rescued_objects_back() { -+ -+ if (_rescued_oops != NULL) { -+ -+ for (int i=0; i<_rescued_oops->length(); i++) { -+ HeapWord* rescued_ptr = _rescued_oops->at(i); -+ oop rescued_obj = (oop) rescued_ptr; -+ -+ int size = rescued_obj->size(); -+ oop new_obj = rescued_obj->forwardee(); -+ -+ assert(rescued_obj->klass()->new_version() != NULL, "just checking"); -+ -+ if (rescued_obj->klass()->new_version()->update_information() != NULL) { -+ MarkSweep::update_fields(rescued_obj, new_obj); -+ } else { -+ rescued_obj->set_klass(rescued_obj->klass()->new_version()); -+ Copy::aligned_disjoint_words((HeapWord*)rescued_obj, (HeapWord*)new_obj, size); -+ } -+ -+ FREE_RESOURCE_ARRAY(HeapWord, rescued_ptr, size); -+ -+ new_obj->init_mark(); -+ assert(new_obj->is_oop(), "must be a valid oop"); -+ } -+ _rescued_oops->clear(); -+ _rescued_oops = NULL; -+ } -+} -+ -+// (DCEVM) Update instances of a class whose fields changed. -+void MarkSweep::update_fields(oop q, oop new_location) { -+ -+ assert(q->klass()->new_version() != NULL, "class of old object must have new version"); -+ -+ Klass* old_klass_oop = q->klass(); -+ Klass* new_klass_oop = q->klass()->new_version(); -+ -+ InstanceKlass *old_klass = InstanceKlass::cast(old_klass_oop); -+ InstanceKlass *new_klass = InstanceKlass::cast(new_klass_oop); -+ -+ int size = q->size_given_klass(old_klass); -+ int new_size = q->size_given_klass(new_klass); -+ -+ HeapWord* tmp = NULL; -+ oop tmp_obj = q; -+ -+ // Save object somewhere, there is an overlap in fields -+ if (new_klass_oop->is_copying_backwards()) { -+ if (((HeapWord *)q >= (HeapWord *)new_location && (HeapWord *)q < (HeapWord *)new_location + new_size) || -+ ((HeapWord *)new_location >= (HeapWord *)q && (HeapWord *)new_location < (HeapWord *)q + size)) { -+ tmp = NEW_RESOURCE_ARRAY(HeapWord, size); -+ q = (oop) tmp; -+ Copy::aligned_disjoint_words((HeapWord*)q, (HeapWord*)tmp_obj, size); -+ } -+ } -+ -+ q->set_klass(new_klass_oop); -+ int *cur = new_klass_oop->update_information(); -+ assert(cur != NULL, "just checking"); -+ MarkSweep::update_fields(new_location, q, cur); -+ -+ if (tmp != NULL) { -+ FREE_RESOURCE_ARRAY(HeapWord, tmp, size); -+ } -+} -+ -+void MarkSweep::update_fields(oop new_location, oop tmp_obj, int *cur) { -+ assert(cur != NULL, "just checking"); -+ char* to = (char*)(HeapWord*)new_location; -+ while (*cur != 0) { -+ int size = *cur; -+ if (size > 0) { -+ cur++; -+ int offset = *cur; -+ HeapWord* from = (HeapWord*)(((char *)(HeapWord*)tmp_obj) + offset); -+ if (size == HeapWordSize) { -+ *((HeapWord*)to) = *from; -+ } else if (size == HeapWordSize * 2) { -+ *((HeapWord*)to) = *from; -+ *(((HeapWord*)to) + 1) = *(from + 1); -+ } else { -+ Copy::conjoint_jbytes(from, to, size); -+ } -+ to += size; -+ cur++; -+ } else { -+ assert(size < 0, ""); -+ int skip = -*cur; -+ Copy::fill_to_bytes(to, skip, 0); -+ to += skip; -+ cur++; -+ } -+ } -+} -diff --git a/src/share/vm/gc_implementation/shared/markSweep.hpp b/src/share/vm/gc_implementation/shared/markSweep.hpp ---- a/src/share/vm/gc_implementation/shared/markSweep.hpp -+++ b/src/share/vm/gc_implementation/shared/markSweep.hpp -@@ -107,8 +107,12 @@ - friend class AdjustPointerClosure; - friend class KeepAliveClosure; - friend class VM_MarkSweep; -+ friend class GenMarkSweep; - friend void marksweep_init(); - -+public: -+ static GrowableArray<HeapWord*>* _rescued_oops; -+ - // - // Vars - // -@@ -169,6 +173,9 @@ - - static inline void push_objarray(oop obj, size_t index); - -+ static void copy_rescued_objects_back(); -+ static void update_fields(oop q, oop new_location); -+ static void update_fields(oop new_location, oop tmp_obj, int *cur); - static void follow_stack(); // Empty marking stack. - - static void follow_klass(Klass* klass); -diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp ---- a/src/share/vm/interpreter/linkResolver.cpp -+++ b/src/share/vm/interpreter/linkResolver.cpp +diff -r 8a6717910608 src/share/vm/interpreter/linkResolver.cpp +--- a/src/share/vm/interpreter/linkResolver.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/interpreter/linkResolver.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -215,8 +215,8 @@ // Klass resolution @@ -869,434 +671,18 @@ diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interprete THROW(vmSymbols::java_lang_IllegalAccessError()); } -@@ -1199,6 +1199,16 @@ +@@ -1199,6 +1199,8 @@ // 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(); -+ + // (DCEVM) Check that the receiver is a subtype of the holder of the resolved method. -+ if (!inst->is_subtype_of(resolved_method->method_holder())) { -+ inst->print(); -+ tty->print_cr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ resolved_method->method_holder()->print(); -+ tty->print_cr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ resolved_method->print(); -+ } + assert(inst->is_subtype_of(resolved_method->method_holder()), "receiver and resolved method holder are inconsistent"); selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index)); } } -diff --git a/src/share/vm/memory/genMarkSweep.cpp b/src/share/vm/memory/genMarkSweep.cpp ---- a/src/share/vm/memory/genMarkSweep.cpp -+++ b/src/share/vm/memory/genMarkSweep.cpp -@@ -334,11 +334,16 @@ - // 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. -+ assert(_rescued_oops == NULL, "must be empty before processing"); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - - GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer); - trace("4"); - -+ MarkSweep::copy_rescued_objects_back(); -+ - GenCompactClosure blk; - gch->generation_iterate(&blk, true); -+ -+ MarkSweep::copy_rescued_objects_back(); - } -diff --git a/src/share/vm/memory/space.cpp b/src/share/vm/memory/space.cpp ---- a/src/share/vm/memory/space.cpp -+++ b/src/share/vm/memory/space.cpp -@@ -379,9 +379,8 @@ - _compaction_top = bottom(); - } - --HeapWord* CompactibleSpace::forward(oop q, size_t size, -- CompactPoint* cp, HeapWord* compact_top) { -- // q is alive -+// (DCEVM) Calculates the compact_top that will be used for placing the next object with the giving size on the heap. -+HeapWord* CompactibleSpace::forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top) { - // 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); -@@ -401,8 +400,15 @@ - compaction_max_size = pointer_delta(cp->space->end(), compact_top); - } - -+ return compact_top; -+} -+ -+HeapWord* CompactibleSpace::forward(oop q, size_t size, -+ CompactPoint* cp, HeapWord* compact_top) { -+ compact_top = forward_compact_top(size, cp, compact_top); -+ - // store the forwarding pointer into the mark word -- if ((HeapWord*)q != compact_top) { -+ if ((HeapWord*)q != compact_top || (size_t)q->size() != size) { - q->forward_to(oop(compact_top)); - assert(q->is_gc_marked(), "encoding the pointer should preserve the mark"); - } else { -@@ -423,6 +429,58 @@ - return compact_top; - } - -+// Compute the forward sizes and leave out objects whose position could -+// possibly overlap other objects. -+HeapWord* CompactibleSpace::forward_with_rescue(HeapWord* q, size_t size, -+ CompactPoint* cp, HeapWord* compact_top) { -+ size_t forward_size = size; -+ -+ // (DCEVM) There is a new version of the class of q => different size -+ if (oop(q)->klass()->new_version() != NULL && oop(q)->klass()->new_version()->update_information() != NULL) { -+ -+ size_t new_size = oop(q)->size_given_klass(oop(q)->klass()->new_version()); -+ assert(size != new_size, "instances without changed size have to be updated prior to GC run"); -+ forward_size = new_size; -+ } -+ -+ compact_top = forward_compact_top(forward_size, cp, compact_top); -+ -+ if (must_rescue(oop(q), oop(compact_top))) { -+ if (MarkSweep::_rescued_oops == NULL) { -+ MarkSweep::_rescued_oops = new GrowableArray<HeapWord*>(128); -+ } -+ MarkSweep::_rescued_oops->append(q); -+ return compact_top; -+ } -+ -+ return forward(oop(q), forward_size, cp, compact_top); -+} -+ -+// Compute the forwarding addresses for the objects that need to be rescued. -+HeapWord* CompactibleSpace::forward_rescued(CompactPoint* cp, HeapWord* compact_top) { -+ // TODO: empty the _rescued_oops after ALL spaces are compacted! -+ if (MarkSweep::_rescued_oops != NULL) { -+ for (int i=0; i<MarkSweep::_rescued_oops->length(); i++) { -+ HeapWord* q = MarkSweep::_rescued_oops->at(i); -+ -+ /* size_t size = oop(q)->size(); changing this for cms for perm gen */ -+ size_t size = block_size(q); -+ -+ // (DCEVM) There is a new version of the class of q => different size -+ if (oop(q)->klass()->new_version() != NULL) { -+ size_t new_size = oop(q)->size_given_klass(oop(q)->klass()->new_version()); -+ assert(size != new_size, "instances without changed size have to be updated prior to GC run"); -+ size = new_size; -+ } -+ -+ compact_top = cp->space->forward(oop(q), size, cp, compact_top); -+ assert(compact_top <= end(), "must not write over end of space!"); -+ } -+ MarkSweep::_rescued_oops->clear(); -+ MarkSweep::_rescued_oops = NULL; -+ } -+ return compact_top; -+} - - bool CompactibleSpace::insert_deadspace(size_t& allowed_deadspace_words, - HeapWord* q, size_t deadlength) { -@@ -444,12 +502,17 @@ - #define adjust_obj_size(s) s - - void CompactibleSpace::prepare_for_compaction(CompactPoint* cp) { -- SCAN_AND_FORWARD(cp, end, block_is_obj, block_size); -+ SCAN_AND_FORWARD(cp, end, block_is_obj, block_size, false); - } - - // Faster object search. - void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) { -- SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size); -+ if (!Universe::is_redefining_gc_run()) { -+ SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size, false); -+ } else { -+ // Redefinition run -+ SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size, true); -+ } - } - - void Space::adjust_pointers() { -@@ -487,6 +550,111 @@ - assert(q == t, "just checking"); - } - -+ -+#ifdef ASSERT -+ -+int CompactibleSpace::space_index(oop obj) { -+ GenCollectedHeap* heap = GenCollectedHeap::heap(); -+ -+ //if (heap->is_in_permanent(obj)) { -+ // return -1; -+ //} -+ -+ int index = 0; -+ for (int i = heap->n_gens() - 1; i >= 0; i--) { -+ Generation* gen = heap->get_gen(i); -+ CompactibleSpace* space = gen->first_compaction_space(); -+ while (space != NULL) { -+ if (space->is_in_reserved(obj)) { -+ return index; -+ } -+ space = space->next_compaction_space(); -+ index++; -+ } -+ } -+ -+ tty->print_cr("could not compute space_index for %08xh", (HeapWord*)obj); -+ index = 0; -+ for (int i = heap->n_gens() - 1; i >= 0; i--) { -+ Generation* gen = heap->get_gen(i); -+ tty->print_cr(" generation %s: %08xh - %08xh", gen->name(), gen->reserved().start(), gen->reserved().end()); -+ -+ CompactibleSpace* space = gen->first_compaction_space(); -+ while (space != NULL) { -+ tty->print_cr(" %2d space %08xh - %08xh", index, space->bottom(), space->end()); -+ space = space->next_compaction_space(); -+ index++; -+ } -+ } -+ -+ ShouldNotReachHere(); -+ return 0; -+} -+#endif -+ -+bool CompactibleSpace::must_rescue(oop old_obj, oop new_obj) { -+ // Only redefined objects can have the need to be rescued. -+ if (oop(old_obj)->klass()->new_version() == NULL) return false; -+ -+ //if (old_obj->is_perm()) { -+ // // This object is in perm gen: Always rescue to satisfy invariant obj->klass() <= obj. -+ // return true; -+ //} -+ -+ int new_size = old_obj->size_given_klass(oop(old_obj)->klass()->new_version()); -+ int original_size = old_obj->size(); -+ -+ Generation* tenured_gen = GenCollectedHeap::heap()->get_gen(1); -+ bool old_in_tenured = tenured_gen->is_in_reserved(old_obj); -+ bool new_in_tenured = tenured_gen->is_in_reserved(new_obj); -+ if (old_in_tenured == new_in_tenured) { -+ // Rescue if object may overlap with a higher memory address. -+ bool overlap = ((HeapWord*)old_obj + original_size < (HeapWord*)new_obj + new_size); -+ if (old_in_tenured) { -+ // Old and new address are in same space, so just compare the address. -+ // Must rescue if object moves towards the top of the space. -+ assert(space_index(old_obj) == space_index(new_obj), "old_obj and new_obj must be in same space"); -+ } else { -+ // In the new generation, eden is located before the from space, so a -+ // simple pointer comparison is sufficient. -+ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(old_obj), "old_obj must be in DefNewGeneration"); -+ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(new_obj), "new_obj must be in DefNewGeneration"); -+ assert(overlap == (space_index(old_obj) < space_index(new_obj)), "slow and fast computation must yield same result"); -+ } -+ return overlap; -+ -+ } else { -+ assert(space_index(old_obj) != space_index(new_obj), "old_obj and new_obj must be in different spaces"); -+ if (tenured_gen->is_in_reserved(new_obj)) { -+ // Must never rescue when moving from the new into the old generation. -+ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(old_obj), "old_obj must be in DefNewGeneration"); -+ assert(space_index(old_obj) > space_index(new_obj), "must be"); -+ return false; -+ -+ } else /* if (tenured_gen->is_in_reserved(old_obj)) */ { -+ // Must always rescue when moving from the old into the new generation. -+ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(new_obj), "new_obj must be in DefNewGeneration"); -+ assert(space_index(old_obj) < space_index(new_obj), "must be"); -+ return true; -+ } -+ } -+} -+ -+HeapWord* CompactibleSpace::rescue(HeapWord* old_obj) { -+ assert(must_rescue(oop(old_obj), oop(old_obj)->forwardee()), "do not call otherwise"); -+ -+ int size = oop(old_obj)->size(); -+ HeapWord* rescued_obj = NEW_RESOURCE_ARRAY(HeapWord, size); -+ Copy::aligned_disjoint_words(old_obj, rescued_obj, size); -+ -+ if (MarkSweep::_rescued_oops == NULL) { -+ MarkSweep::_rescued_oops = new GrowableArray<HeapWord*>(128); -+ } -+ -+ MarkSweep::_rescued_oops->append(rescued_obj); -+ return rescued_obj; -+} -+ - void CompactibleSpace::adjust_pointers() { - // Check first is there is any work to do. - if (used() == 0) { -@@ -497,7 +665,12 @@ - } - - void CompactibleSpace::compact() { -- SCAN_AND_COMPACT(obj_size); -+ if(!Universe::is_redefining_gc_run()) { -+ SCAN_AND_COMPACT(obj_size, false); -+ } else { -+ // Redefinition run -+ SCAN_AND_COMPACT(obj_size, true) -+ } - } - - 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 ---- a/src/share/vm/memory/space.hpp -+++ b/src/share/vm/memory/space.hpp -@@ -450,6 +450,9 @@ - // indicates when the next such action should be taken. - virtual void prepare_for_compaction(CompactPoint* cp); - // MarkSweep support phase3 -+ DEBUG_ONLY(int space_index(oop obj)); -+ bool must_rescue(oop old_obj, oop new_obj); -+ HeapWord* rescue(HeapWord* old_obj); - virtual void adjust_pointers(); - // MarkSweep support phase4 - virtual void compact(); -@@ -479,6 +482,15 @@ - // accordingly". - virtual HeapWord* forward(oop q, size_t size, CompactPoint* cp, - HeapWord* compact_top); -+ // (DCEVM) same as forwad, but can rescue objects. Invoked only during -+ // redefinition runs -+ HeapWord* forward_with_rescue(HeapWord* q, size_t size, CompactPoint* cp, -+ HeapWord* compact_top); -+ -+ HeapWord* forward_rescued(CompactPoint* cp, HeapWord* compact_top); -+ -+ // (tw) Compute new compact top without actually forwarding the object. -+ virtual HeapWord* forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top); - - // Return a size with adjusments as required of the space. - virtual size_t adjust_object_size_v(size_t size) const { return size; } -@@ -509,7 +521,7 @@ - size_t word_len); - }; - --#define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size) { \ -+#define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size,redefinition_run) { \ - /* Compute the new addresses for the live objects and store it in the mark \ - * Used by universe::mark_sweep_phase2() \ - */ \ -@@ -567,7 +579,17 @@ - /* prefetch beyond q */ \ - Prefetch::write(q, interval); \ - size_t size = block_size(q); \ -+ if (redefinition_run) { \ -+ compact_top = cp->space->forward_with_rescue(q, size, \ -+ cp, compact_top); \ -+ if (q < first_dead && oop(q)->is_gc_marked()) { \ -+ /* Was moved (otherwise, forward would reset mark), \ -+ set first_dead to here */ \ -+ first_dead = q; \ -+ } \ -+ } else { \ - compact_top = cp->space->forward(oop(q), size, cp, compact_top); \ -+ } \ - q += size; \ - end_of_live = q; \ - } else { \ -@@ -616,6 +638,8 @@ - } \ - } \ - \ -+ if (redefinition_run) { compact_top = forward_rescued(cp, compact_top); } \ -+ \ - assert(q == t, "just checking"); \ - if (liveRange != NULL) { \ - liveRange->set_end(q); \ -@@ -662,13 +686,8 @@ - q += size; \ - } \ - \ -- if (_first_dead == t) { \ -- q = t; \ -- } else { \ -- /* $$$ This is funky. Using this to read the previously written \ -- * LiveRange. See also use below. */ \ -- q = (HeapWord*)oop(_first_dead)->mark()->decode_pointer(); \ -- } \ -+ /* (DCEVM) first_dead can be live object if we move/rescue resized objects */ \ -+ q = _first_dead; \ - } \ - \ - const intx interval = PrefetchScanIntervalInBytes; \ -@@ -696,7 +715,7 @@ - assert(q == t, "just checking"); \ - } - --#define SCAN_AND_COMPACT(obj_size) { \ -+#define SCAN_AND_COMPACT(obj_size, redefinition_run) { \ - /* Copy all live objects to their new location \ - * Used by MarkSweep::mark_sweep_phase4() */ \ - \ -@@ -721,13 +740,9 @@ - } \ - ) /* debug_only */ \ - \ -- if (_first_dead == t) { \ -- q = t; \ -- } else { \ -- /* $$$ Funky */ \ -- q = (HeapWord*) oop(_first_dead)->mark()->decode_pointer(); \ -+ /* (DCEVM) first_dead can be live object if we move/rescue resized objects */ \ -+ q = _first_dead; \ - } \ -- } \ - \ - const intx scan_interval = PrefetchScanIntervalInBytes; \ - const intx copy_interval = PrefetchCopyIntervalInBytes; \ -@@ -745,11 +760,34 @@ - size_t size = obj_size(q); \ - HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); \ - \ -+ if (redefinition_run && must_rescue(oop(q), oop(q)->forwardee())) { \ -+ rescue(q); \ -+ debug_only(Copy::fill_to_words(q, size, 0)); \ -+ q += size; \ -+ continue; \ -+ } \ -+ \ - /* prefetch beyond compaction_top */ \ - Prefetch::write(compaction_top, copy_interval); \ - \ - /* copy object and reinit its mark */ \ -- assert(q != compaction_top, "everything in this pass should be moving"); \ -+ assert(q != compaction_top || oop(q)->klass()->new_version() != NULL, \ -+ "everything in this pass should be moving"); \ -+ if (redefinition_run && oop(q)->klass()->new_version() != NULL) { \ -+ Klass* new_version = oop(q)->klass()->new_version(); \ -+ if (new_version->update_information() == NULL) { \ -+ Copy::aligned_conjoint_words(q, compaction_top, size); \ -+ oop(compaction_top)->set_klass(new_version); \ -+ } else { \ -+ MarkSweep::update_fields(oop(q), oop(compaction_top)); \ -+ } \ -+ oop(compaction_top)->init_mark(); \ -+ assert(oop(compaction_top)->klass() != NULL, "should have a class"); \ -+ \ -+ debug_only(prev_q = q); \ -+ q += size; \ -+ continue; \ -+ } \ - Copy::aligned_conjoint_words(q, compaction_top, size); \ - oop(compaction_top)->init_mark(); \ - assert(oop(compaction_top)->klass() != NULL, "should have a class"); \ -diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp ---- a/src/share/vm/memory/universe.cpp -+++ b/src/share/vm/memory/universe.cpp -@@ -78,6 +78,8 @@ - #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" - #endif // INCLUDE_ALL_GCS - -+bool Universe::_is_redefining_gc_run = false; -+ - // Known objects - Klass* Universe::_boolArrayKlassObj = NULL; - Klass* Universe::_byteArrayKlassObj = NULL; +diff -r 8a6717910608 src/share/vm/memory/universe.cpp +--- a/src/share/vm/memory/universe.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/memory/universe.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -157,6 +159,42 @@ f(doubleArrayKlassObj()); } @@ -1340,23 +726,9 @@ diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp void Universe::oops_do(OopClosure* f, bool do_all) { f->do_oop((oop*) &_int_mirror); -diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp ---- a/src/share/vm/memory/universe.hpp -+++ b/src/share/vm/memory/universe.hpp -@@ -248,7 +248,13 @@ - - static void compute_verify_oop_data(); - -+ static bool _is_redefining_gc_run; -+ - public: -+ -+ static bool is_redefining_gc_run() { return _is_redefining_gc_run; } -+ static void set_redefining_gc_run(bool b) { _is_redefining_gc_run = b; } -+ - // Known classes in the VM - static Klass* boolArrayKlassObj() { return _boolArrayKlassObj; } - static Klass* byteArrayKlassObj() { return _byteArrayKlassObj; } +diff -r 8a6717910608 src/share/vm/memory/universe.hpp +--- a/src/share/vm/memory/universe.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/memory/universe.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -401,6 +407,7 @@ static void run_finalizers_on_exit(); @@ -1365,9 +737,9 @@ diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp // Apply "f" to the addresses of all the direct heap pointers maintained // as static fields of "Universe". -diff --git a/src/share/vm/oops/cpCache.cpp b/src/share/vm/oops/cpCache.cpp ---- a/src/share/vm/oops/cpCache.cpp -+++ b/src/share/vm/oops/cpCache.cpp +diff -r 8a6717910608 src/share/vm/oops/cpCache.cpp +--- a/src/share/vm/oops/cpCache.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/cpCache.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -336,7 +336,8 @@ if (has_appendix) { const int appendix_index = f2_as_index() + _indy_resolved_references_appendix_offset; @@ -1430,9 +802,9 @@ diff --git a/src/share/vm/oops/cpCache.cpp b/src/share/vm/oops/cpCache.cpp #endif // INCLUDE_JVMTI -diff --git a/src/share/vm/oops/cpCache.hpp b/src/share/vm/oops/cpCache.hpp ---- a/src/share/vm/oops/cpCache.hpp -+++ b/src/share/vm/oops/cpCache.hpp +diff -r 8a6717910608 src/share/vm/oops/cpCache.hpp +--- a/src/share/vm/oops/cpCache.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/cpCache.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -373,6 +373,10 @@ bool * trace_name_printed); bool check_no_old_or_obsolete_entries(); @@ -1455,9 +827,9 @@ diff --git a/src/share/vm/oops/cpCache.hpp b/src/share/vm/oops/cpCache.hpp #endif // INCLUDE_JVMTI // Deallocate - no fields to deallocate -diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp ---- a/src/share/vm/oops/instanceKlass.cpp -+++ b/src/share/vm/oops/instanceKlass.cpp +diff -r 8a6717910608 src/share/vm/oops/instanceKlass.cpp +--- a/src/share/vm/oops/instanceKlass.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/instanceKlass.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -718,7 +718,8 @@ } #endif @@ -1601,9 +973,9 @@ diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKla } // end has_previous_version() -diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp ---- a/src/share/vm/oops/instanceKlass.hpp -+++ b/src/share/vm/oops/instanceKlass.hpp +diff -r 8a6717910608 src/share/vm/oops/instanceKlass.hpp +--- a/src/share/vm/oops/instanceKlass.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/instanceKlass.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -139,6 +139,7 @@ friend class VMStructs; friend class ClassFileParser; @@ -1648,9 +1020,9 @@ diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKla void methods_do(void f(Method* method)); void array_klasses_do(void f(Klass* k)); void array_klasses_do(void f(Klass* k, TRAPS), TRAPS); -diff --git a/src/share/vm/oops/klass.cpp b/src/share/vm/oops/klass.cpp ---- a/src/share/vm/oops/klass.cpp -+++ b/src/share/vm/oops/klass.cpp +diff -r 8a6717910608 src/share/vm/oops/klass.cpp +--- a/src/share/vm/oops/klass.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/klass.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -170,6 +170,13 @@ set_next_link(NULL); TRACE_INIT_ID(this); @@ -1690,9 +1062,9 @@ diff --git a/src/share/vm/oops/klass.cpp b/src/share/vm/oops/klass.cpp bool Klass::is_loader_alive(BoolObjectClosure* is_alive) { assert(ClassLoaderDataGraph::contains((address)this), "is in the metaspace"); -diff --git a/src/share/vm/oops/klass.hpp b/src/share/vm/oops/klass.hpp ---- a/src/share/vm/oops/klass.hpp -+++ b/src/share/vm/oops/klass.hpp +diff -r 8a6717910608 src/share/vm/oops/klass.hpp +--- a/src/share/vm/oops/klass.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/klass.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -149,6 +149,10 @@ oop _java_mirror; // Superclass @@ -1800,9 +1172,9 @@ diff --git a/src/share/vm/oops/klass.hpp b/src/share/vm/oops/klass.hpp // Compiler support static ByteSize super_offset() { return in_ByteSize(offset_of(Klass, _super)); } -diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.cpp ---- a/src/share/vm/oops/klassVtable.cpp -+++ b/src/share/vm/oops/klassVtable.cpp +diff -r 8a6717910608 src/share/vm/oops/klassVtable.cpp +--- a/src/share/vm/oops/klassVtable.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/klassVtable.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -1409,6 +1409,8 @@ void klassVtable::verify_against(outputStream* st, klassVtable* vt, int index) { @@ -1832,9 +1204,9 @@ diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.c } } -diff --git a/src/share/vm/oops/method.cpp b/src/share/vm/oops/method.cpp ---- a/src/share/vm/oops/method.cpp -+++ b/src/share/vm/oops/method.cpp +diff -r 8a6717910608 src/share/vm/oops/method.cpp +--- a/src/share/vm/oops/method.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/method.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -1185,6 +1185,8 @@ // Reset correct method/const method, method size, and parameter info @@ -1855,9 +1227,9 @@ diff --git a/src/share/vm/oops/method.cpp b/src/share/vm/oops/method.cpp ClassLoaderData* cld = loader_data; if (!SafepointSynchronize::is_at_safepoint()) { -diff --git a/src/share/vm/oops/method.hpp b/src/share/vm/oops/method.hpp ---- a/src/share/vm/oops/method.hpp -+++ b/src/share/vm/oops/method.hpp +diff -r 8a6717910608 src/share/vm/oops/method.hpp +--- a/src/share/vm/oops/method.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/oops/method.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -105,6 +105,10 @@ AccessFlags _access_flags; // Access flags int _vtable_index; // vtable index of this method (see VtableIndexFlag) @@ -1893,9 +1265,9 @@ diff --git a/src/share/vm/oops/method.hpp b/src/share/vm/oops/method.hpp // signature Symbol* signature() const { return constants()->symbol_at(signature_index()); } int signature_index() const { return constMethod()->signature_index(); } -diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp ---- a/src/share/vm/prims/jni.cpp -+++ b/src/share/vm/prims/jni.cpp +diff -r 8a6717910608 src/share/vm/prims/jni.cpp +--- a/src/share/vm/prims/jni.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/prims/jni.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -406,6 +406,7 @@ } Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader, @@ -1904,9 +1276,9 @@ diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp CHECK_NULL); if (TraceClassResolution && k != NULL) { -diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp ---- a/src/share/vm/prims/jvm.cpp -+++ b/src/share/vm/prims/jvm.cpp +diff -r 8a6717910608 src/share/vm/prims/jvm.cpp +--- a/src/share/vm/prims/jvm.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/prims/jvm.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -904,6 +904,7 @@ Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader, protection_domain, &st, @@ -1915,9 +1287,9 @@ diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp CHECK_NULL); if (TraceClassResolution && k != NULL) { -diff --git a/src/share/vm/prims/jvmtiEnv.cpp b/src/share/vm/prims/jvmtiEnv.cpp ---- a/src/share/vm/prims/jvmtiEnv.cpp -+++ b/src/share/vm/prims/jvmtiEnv.cpp +diff -r 8a6717910608 src/share/vm/prims/jvmtiEnv.cpp +--- a/src/share/vm/prims/jvmtiEnv.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/prims/jvmtiEnv.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -42,6 +42,7 @@ #include "prims/jvmtiManageCapabilities.hpp" #include "prims/jvmtiRawMonitor.hpp" @@ -1963,9 +1335,9 @@ diff --git a/src/share/vm/prims/jvmtiEnv.cpp b/src/share/vm/prims/jvmtiEnv.cpp VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine); VMThread::execute(&op); return (op.check_error()); -diff --git a/src/share/vm/prims/jvmtiExport.hpp b/src/share/vm/prims/jvmtiExport.hpp ---- a/src/share/vm/prims/jvmtiExport.hpp -+++ b/src/share/vm/prims/jvmtiExport.hpp +diff -r 8a6717910608 src/share/vm/prims/jvmtiExport.hpp +--- a/src/share/vm/prims/jvmtiExport.hpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/prims/jvmtiExport.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -188,6 +188,7 @@ // systems as needed to relax invariant checks. static bool _has_redefined_a_class; @@ -1974,9 +1346,9 @@ diff --git a/src/share/vm/prims/jvmtiExport.hpp b/src/share/vm/prims/jvmtiExport inline static void set_has_redefined_a_class() { JVMTI_ONLY(_has_redefined_a_class = true;) } -diff --git a/src/share/vm/prims/jvmtiImpl.cpp b/src/share/vm/prims/jvmtiImpl.cpp ---- a/src/share/vm/prims/jvmtiImpl.cpp -+++ b/src/share/vm/prims/jvmtiImpl.cpp +diff -r 8a6717910608 src/share/vm/prims/jvmtiImpl.cpp +--- a/src/share/vm/prims/jvmtiImpl.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/prims/jvmtiImpl.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -289,6 +289,11 @@ Symbol* m_name = _method->name(); Symbol* m_signature = _method->signature(); @@ -1989,10 +1361,9 @@ diff --git a/src/share/vm/prims/jvmtiImpl.cpp b/src/share/vm/prims/jvmtiImpl.cpp // search previous versions if they exist PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh()); for (PreviousVersionNode * pv_node = pvw.next_previous_version(); -diff --git a/src/share/vm/prims/jvmtiRedefineClasses2.cpp b/src/share/vm/prims/jvmtiRedefineClasses2.cpp -new file mode 100644 ---- /dev/null -+++ b/src/share/vm/prims/jvmtiRedefineClasses2.cpp +diff -r 8a6717910608 src/share/vm/prims/jvmtiRedefineClasses2.cpp +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/share/vm/prims/jvmtiRedefineClasses2.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -0,0 +1,2034 @@ +/* + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. @@ -4028,10 +3399,9 @@ new file mode 100644 + 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/jvmtiRedefineClasses2.hpp b/src/share/vm/prims/jvmtiRedefineClasses2.hpp -new file mode 100644 ---- /dev/null -+++ b/src/share/vm/prims/jvmtiRedefineClasses2.hpp +diff -r 8a6717910608 src/share/vm/prims/jvmtiRedefineClasses2.hpp +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/share/vm/prims/jvmtiRedefineClasses2.hpp Wed Apr 30 11:27:18 2014 -0700 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. @@ -4189,65 +3559,9 @@ new file mode 100644 +}; + +#endif // SHARE_VM_PRIMS_JVMTIENHANCEDREDEFINECLASSES_HPP -diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp ---- a/src/share/vm/runtime/arguments.cpp -+++ b/src/share/vm/runtime/arguments.cpp -@@ -59,8 +59,8 @@ - #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" - #endif // INCLUDE_ALL_GCS - --// Note: This is a special bug reporting site for the JVM --#define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp" -+// (DCEVM) The DCE VM has its own JIRA bug tracking system. -+#define DEFAULT_VENDOR_URL_BUG "https://github.com/Guidewire/DCEVM/issues" - #define DEFAULT_JAVA_LAUNCHER "generic" - - // Disable options not supported in this release, with a warning if they -@@ -1507,6 +1507,10 @@ - - void Arguments::set_ergonomics_flags() { - -+ if (AllowEnhancedClassRedefinition) { -+ // (DCEVM) enforces serial GC -+ FLAG_SET_ERGO(bool, UseSerialGC, true); -+ } - if (os::is_server_class_machine()) { - // If no other collector is requested explicitly, - // let the VM select the collector based on -@@ -1948,6 +1952,17 @@ - if (UseConcMarkSweepGC || UseParNewGC) i++; - if (UseParallelGC || UseParallelOldGC) i++; - if (UseG1GC) i++; -+ -+ if (AllowEnhancedClassRedefinition) { -+ // (DCEVM) Must use serial GC. This limitation applies because the instance size changing GC modifications -+ // are only built into the mark and compact algorithm. -+ if (!UseSerialGC && i >= 1) { -+ jio_fprintf(defaultStream::error_stream(), -+ "Must use the serial GC in the DCEVM\n"); -+ status = false; -+ } -+ } -+ - if (i > 1) { - jio_fprintf(defaultStream::error_stream(), - "Conflicting collector combinations in option list; " -diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp ---- a/src/share/vm/runtime/globals.hpp -+++ b/src/share/vm/runtime/globals.hpp -@@ -1273,6 +1273,9 @@ - product(intx, TraceRedefineClasses, 0, \ - "Trace level for JVMTI RedefineClasses") \ - \ -+ product(bool, AllowEnhancedClassRedefinition, true, \ -+ "Allow enhanced class redefinition beyond swapping method bodies")\ -+ \ - develop(bool, StressMethodComparator, false, \ - "Run the MethodComparator on all loaded methods") \ - \ -diff --git a/src/share/vm/runtime/reflection.cpp b/src/share/vm/runtime/reflection.cpp ---- a/src/share/vm/runtime/reflection.cpp -+++ b/src/share/vm/runtime/reflection.cpp +diff -r 8a6717910608 src/share/vm/runtime/reflection.cpp +--- a/src/share/vm/runtime/reflection.cpp Tue Mar 11 13:02:13 2014 -0700 ++++ b/src/share/vm/runtime/reflection.cpp Wed Apr 30 11:27:18 2014 -0700 @@ -519,6 +519,12 @@ AccessFlags access, bool classloader_only, diff --git a/hotspot/.hg/patches/series b/hotspot/.hg/patches/series index b17eafbf..e59ea4e6 100644 --- a/hotspot/.hg/patches/series +++ b/hotspot/.hg/patches/series @@ -1,3 +1,17 @@ +# Change distribution name +distro-name.patch + +# Add AllowEnhancedRedefinition argument +arguments-java8.patch + +# GC changes to allow modifying instances during redefinition run +gc-java8.patch #+jdk8 # Rest of the changes -light-jdk8u5-b13.patch #+light #+jdk8 #+u5-b13 +full-jdk7u11-b21.patch #+full-jdk7u11-b21 +full-jdk7u45-b08.patch #+full-jdk7u45-b08 +full-jdk7u51-b13.patch #+full-jdk7u51-b13 +light-jdk7u40-b43.patch #+light-jdk7u40-b43 +light-jdk7u51-b13.patch #+light-jdk7u51-b13 +light-jdk8u5-b13.patch #+light-jdk8u5-b13 + diff --git a/patches/light-jdk8u5-b13.patch b/patches/light-jdk8u5-b13.patch deleted file mode 100644 index 5491fd46..00000000 --- a/patches/light-jdk8u5-b13.patch +++ /dev/null @@ -1,4258 +0,0 @@ -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 -@@ -27,6 +27,6 @@ - # - - # Don't put quotes (fail windows build). --HOTSPOT_VM_DISTRO=OpenJDK -+HOTSPOT_VM_DISTRO=Dynamic Code Evolution - COMPANY_NAME= - PRODUCT_NAME=OpenJDK -diff -r 8a6717910608 src/share/vm/ci/ciObjectFactory.cpp ---- a/src/share/vm/ci/ciObjectFactory.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/ci/ciObjectFactory.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -750,3 +750,27 @@ - _unloaded_instances->length(), - _unloaded_klasses->length()); - } -+ -+int ciObjectFactory::compare_cimetadata(ciMetadata** a, ciMetadata** b) { -+ Metadata* am = (*a)->constant_encoding(); -+ Metadata* bm = (*b)->constant_encoding(); -+ return ((am > bm) ? 1 : ((am == bm) ? 0 : -1)); -+} -+ -+// (DCEVM) Resoring the ciObject arrays after class redefinition -+void ciObjectFactory::resort_shared_ci_metadata() { -+ if (_shared_ci_metadata == NULL) return; -+ _shared_ci_metadata->sort(ciObjectFactory::compare_cimetadata); -+ -+#ifdef ASSERT -+ if (CIObjectFactoryVerify) { -+ Metadata* last = NULL; -+ for (int j = 0; j< _shared_ci_metadata->length(); j++) { -+ Metadata* o = _shared_ci_metadata->at(j)->constant_encoding(); -+ assert(last < o, "out of order"); -+ last = o; -+ } -+ } -+#endif // ASSERT -+} -+ -diff -r 8a6717910608 src/share/vm/ci/ciObjectFactory.hpp ---- a/src/share/vm/ci/ciObjectFactory.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/ci/ciObjectFactory.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -90,6 +90,7 @@ - - ciInstance* get_unloaded_instance(ciInstanceKlass* klass); - -+ static int compare_cimetadata(ciMetadata** a, ciMetadata** b); - public: - static bool is_initialized() { return _initialized; } - -@@ -145,6 +146,8 @@ - - void print_contents(); - void print(); -+ -+ static void resort_shared_ci_metadata(); - }; - - #endif // SHARE_VM_CI_CIOBJECTFACTORY_HPP -diff -r 8a6717910608 src/share/vm/classfile/classFileParser.cpp ---- a/src/share/vm/classfile/classFileParser.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/classFileParser.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -759,6 +759,7 @@ - Array<Klass*>* ClassFileParser::parse_interfaces(int length, - Handle protection_domain, - Symbol* class_name, -+ bool pick_newest, - bool* has_default_methods, - TRAPS) { - if (length == 0) { -@@ -777,7 +778,11 @@ - "Interface name has bad constant pool index %u in class file %s", - interface_index, CHECK_NULL); - if (_cp->tag_at(interface_index).is_klass()) { -- interf = KlassHandle(THREAD, _cp->resolved_klass_at(interface_index)); -+ Klass* resolved_klass = _cp->resolved_klass_at(interface_index); -+ if (pick_newest) { -+ resolved_klass = resolved_klass->newest_version(); -+ } -+ interf = KlassHandle(THREAD, resolved_klass); - } else { - Symbol* unresolved_klass = _cp->klass_name_at(interface_index); - -@@ -791,6 +796,9 @@ - Klass* k = SystemDictionary::resolve_super_or_fail(class_name, - unresolved_klass, class_loader, protection_domain, - false, CHECK_NULL); -+ if (pick_newest) { -+ k = k->newest_version(); -+ } - interf = KlassHandle(THREAD, k); - } - -@@ -3093,6 +3101,7 @@ - } - - instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index, -+ bool pick_newest, - TRAPS) { - instanceKlassHandle super_klass; - if (super_class_index == 0) { -@@ -3109,7 +3118,11 @@ - // However, make sure it is not an array type. - bool is_array = false; - if (_cp->tag_at(super_class_index).is_klass()) { -- super_klass = instanceKlassHandle(THREAD, _cp->resolved_klass_at(super_class_index)); -+ Klass* resolved_klass = _cp->resolved_klass_at(super_class_index); -+ if (pick_newest) { -+ resolved_klass = resolved_klass->newest_version(); -+ } -+ super_klass = instanceKlassHandle(THREAD, resolved_klass); - if (_need_verify) - is_array = super_klass->oop_is_array(); - } else if (_need_verify) { -@@ -3658,8 +3671,10 @@ - instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, - ClassLoaderData* loader_data, - Handle protection_domain, -+ KlassHandle old_klass, - KlassHandle host_klass, - GrowableArray<Handle>* cp_patches, -+ GrowableArray<Symbol*>* parsed_super_symbols, - TempNewSymbol& parsed_name, - bool verify, - TRAPS) { -@@ -3672,6 +3687,7 @@ - JvmtiCachedClassFileData *cached_class_file = NULL; - Handle class_loader(THREAD, loader_data->class_loader()); - bool has_default_methods = false; -+ bool pick_newest = !old_klass.is_null(); - ResourceMark rm(THREAD); - - ClassFileStream* cfs = stream(); -@@ -3688,7 +3704,7 @@ - - init_parsed_class_attributes(loader_data); - -- if (JvmtiExport::should_post_class_file_load_hook()) { -+ if (parsed_super_symbols == NULL && JvmtiExport::should_post_class_file_load_hook()) { - // 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 -@@ -3823,6 +3839,26 @@ - CHECK_(nullHandle)); - } - -+ // (DCEVM) Do not parse full class file, only get super symbols and return. -+ if (parsed_super_symbols != NULL) { -+ u2 super_class_index = cfs->get_u2_fast(); -+ -+ if (super_class_index != 0) { -+ parsed_super_symbols->append(cp->klass_name_at(super_class_index)); -+ } -+ -+ // Interfaces -+ u2 itfs_len = cfs->get_u2_fast(); -+ Array<Klass*>* local_interfaces = -+ parse_interfaces(itfs_len, protection_domain, _class_name, pick_newest, &has_default_methods, CHECK_NULL); -+ -+ for (int i = 0; i < local_interfaces->length(); i++) { -+ Klass* o = local_interfaces->at(i); -+ parsed_super_symbols->append(o->name()); -+ } -+ return NULL; -+ } -+ - Klass* preserve_this_klass; // for storing result across HandleMark - - // release all handles when parsing is done -@@ -3849,13 +3885,14 @@ - - u2 super_class_index = cfs->get_u2_fast(); - instanceKlassHandle super_klass = parse_super_class(super_class_index, -+ pick_newest, - CHECK_NULL); - - // Interfaces - u2 itfs_len = cfs->get_u2_fast(); - Array<Klass*>* local_interfaces = - parse_interfaces(itfs_len, protection_domain, _class_name, -- &has_default_methods, CHECK_(nullHandle)); -+ pick_newest, &has_default_methods, CHECK_(nullHandle)); - - u2 java_fields_count = 0; - // Fields (offsets are filled in later) -@@ -3897,6 +3934,9 @@ - true, - CHECK_(nullHandle)); - -+ if (pick_newest) { -+ k = k->newest_version(); -+ } - KlassHandle kh (THREAD, k); - super_klass = instanceKlassHandle(THREAD, kh()); - } -@@ -4056,7 +4096,7 @@ - fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts); - - // Fill in has_finalizer, has_vanilla_constructor, and layout_helper -- set_precomputed_flags(this_klass); -+ set_precomputed_flags(this_klass, old_klass); - - // reinitialize modifiers, using the InnerClasses attribute - int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle)); -@@ -4283,7 +4323,7 @@ - } - - --void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) { -+void ClassFileParser::set_precomputed_flags(instanceKlassHandle k, KlassHandle old_klass) { - Klass* super = k->super(); - - // Check if this klass has an empty finalize method (i.e. one with return bytecode only), -@@ -4291,7 +4331,9 @@ - if (!_has_empty_finalizer) { - if (_has_finalizer || - (super != NULL && super->has_finalizer())) { -- k->set_has_finalizer(); -+ if (old_klass.is_null() || old_klass->has_finalizer()) { -+ k->set_has_finalizer(); -+ } - } - } - -@@ -4307,7 +4349,7 @@ - - // Check if this klass supports the java.lang.Cloneable interface - if (SystemDictionary::Cloneable_klass_loaded()) { -- if (k->is_subtype_of(SystemDictionary::Cloneable_klass())) { -+ if (k->is_subtype_of(SystemDictionary::Cloneable_klass()) || k->is_subtype_of(SystemDictionary::Cloneable_klass()->newest_version())) { - k->set_is_cloneable(); - } - } -diff -r 8a6717910608 src/share/vm/classfile/classFileParser.hpp ---- a/src/share/vm/classfile/classFileParser.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/classFileParser.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -214,11 +214,12 @@ - Array<Klass*>* parse_interfaces(int length, - Handle protection_domain, - Symbol* class_name, -+ bool pick_newest, - bool* has_default_methods, - TRAPS); - void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS); - -- instanceKlassHandle parse_super_class(int super_class_index, TRAPS); -+ instanceKlassHandle parse_super_class(int super_class_index, bool pick_newest, TRAPS); - // Field parsing - void parse_field_attributes(u2 attributes_count, - bool is_static, u2 signature_index, -@@ -299,7 +300,7 @@ - unsigned int nonstatic_oop_map_count, - int* nonstatic_oop_offsets, - unsigned int* nonstatic_oop_counts); -- void set_precomputed_flags(instanceKlassHandle k); -+ void set_precomputed_flags(instanceKlassHandle k, KlassHandle old_klass); - Array<Klass*>* compute_transitive_interfaces(instanceKlassHandle super, - Array<Klass*>* local_ifs, TRAPS); - -@@ -461,17 +462,20 @@ - instanceKlassHandle parseClassFile(Symbol* name, - ClassLoaderData* loader_data, - Handle protection_domain, -+ KlassHandle old_klass, - TempNewSymbol& parsed_name, - bool verify, - TRAPS) { - KlassHandle no_host_klass; -- return parseClassFile(name, loader_data, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD); -+ return parseClassFile(name, loader_data, protection_domain, old_klass, no_host_klass, NULL, NULL, parsed_name, verify, THREAD); - } - instanceKlassHandle parseClassFile(Symbol* name, - ClassLoaderData* loader_data, - Handle protection_domain, -+ KlassHandle old_klass, - KlassHandle host_klass, - GrowableArray<Handle>* cp_patches, -+ GrowableArray<Symbol*>* parsed_super_symbols, - TempNewSymbol& parsed_name, - bool verify, - TRAPS); -diff -r 8a6717910608 src/share/vm/classfile/classLoader.cpp ---- a/src/share/vm/classfile/classLoader.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/classLoader.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -926,6 +926,7 @@ - instanceKlassHandle result = parser.parseClassFile(h_name, - loader_data, - protection_domain, -+ KlassHandle(), - parsed_name, - false, - CHECK_(h)); -diff -r 8a6717910608 src/share/vm/classfile/dictionary.cpp ---- a/src/share/vm/classfile/dictionary.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/dictionary.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -145,7 +145,7 @@ - InstanceKlass* ik = InstanceKlass::cast(e); - - // Non-unloadable classes were handled in always_strong_oops_do -- if (!is_strongly_reachable(loader_data, e)) { -+ if (!ik->is_redefining() && !is_strongly_reachable(loader_data, e)) { - // Entry was not visited in phase1 (negated test from phase1) - assert(!loader_data->is_the_null_class_loader_data(), "unloading entry with null class loader"); - ClassLoaderData* k_def_class_loader_data = ik->class_loader_data(); -@@ -336,6 +336,32 @@ - add_entry(index, entry); - } - -+// (DCEVM) Updates the klass entry to point to the new Klass*. Necessary only for class redefinition. -+bool Dictionary::update_klass(int index, unsigned int hash, Symbol* name, ClassLoaderData* loader_data, KlassHandle k, KlassHandle old_class) { -+ -+ // There are several entries for the same class in the dictionary: One extra entry for each parent classloader of the classloader of the class. -+ bool found = false; -+ for (int index = 0; index < table_size(); index++) { -+ for (DictionaryEntry* entry = bucket(index); entry != NULL; entry = entry->next()) { -+ if (entry->klass() == old_class()) { -+ entry->set_literal(k()); -+ found = true; -+ } -+ } -+ } -+ return found; -+} -+ -+// (DCEVM) Undo previous updates to the system dictionary -+void Dictionary::rollback_redefinition() { -+ for (int index = 0; index < table_size(); index++) { -+ for (DictionaryEntry* entry = bucket(index); entry != NULL; entry = entry->next()) { -+ if (entry->klass()->is_redefining()) { -+ entry->set_literal(entry->klass()->old_version()); -+ } -+ } -+ } -+} - - // This routine does not lock the system dictionary. - // -@@ -366,7 +392,7 @@ - ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { - DictionaryEntry* entry = get_entry(index, hash, name, loader_data); - if (entry != NULL && entry->is_valid_protection_domain(protection_domain)) { -- return entry->klass(); -+ return intercept_for_version(entry->klass()); - } else { - return NULL; - } -@@ -379,7 +405,7 @@ - assert (index == index_for(name, loader_data), "incorrect index?"); - - DictionaryEntry* entry = get_entry(index, hash, name, loader_data); -- return (entry != NULL) ? entry->klass() : (Klass*)NULL; -+ return intercept_for_version((entry != NULL) ? entry->klass() : (Klass*)NULL); - } - - -@@ -391,7 +417,7 @@ - assert (index == index_for(name, NULL), "incorrect index?"); - - DictionaryEntry* entry = get_entry(index, hash, name, NULL); -- return (entry != NULL) ? entry->klass() : (Klass*)NULL; -+ return intercept_for_version((entry != NULL) ? entry->klass() : (Klass*)NULL); - } - - -diff -r 8a6717910608 src/share/vm/classfile/dictionary.hpp ---- a/src/share/vm/classfile/dictionary.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/dictionary.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -78,6 +78,10 @@ - - void add_klass(Symbol* class_name, ClassLoaderData* loader_data,KlassHandle obj); - -+ bool update_klass(int index, unsigned int hash, Symbol* name, ClassLoaderData* loader_data, KlassHandle k, KlassHandle old_class); -+ -+ void rollback_redefinition(); -+ - Klass* find_class(int index, unsigned int hash, - Symbol* name, ClassLoaderData* loader_data); - -@@ -107,6 +111,11 @@ - return (loader_data->is_the_null_class_loader_data() || !ClassUnloading); - } - -+ // (DCEVM) During enhanced class redefinition we want old version if new is being redefined -+ static Klass* intercept_for_version(Klass* k) { -+ return (k != NULL && k->is_redefining()) ? k->old_version() : k; -+ } -+ - // Unload (that is, break root links to) all unmarked classes and - // loaders. Returns "true" iff something was unloaded. - bool do_unloading(); -diff -r 8a6717910608 src/share/vm/classfile/javaClasses.cpp ---- a/src/share/vm/classfile/javaClasses.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/javaClasses.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -1629,6 +1629,8 @@ - skip_throwableInit_check = true; - } - } -+ // (DCEVM): Line numbers from newest version must be used for EMCP-swapped methods -+ method = method->newest_version(); - if (method->is_hidden()) { - if (skip_hidden) continue; - } -diff -r 8a6717910608 src/share/vm/classfile/loaderConstraints.cpp ---- a/src/share/vm/classfile/loaderConstraints.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/loaderConstraints.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -446,7 +446,7 @@ - if (k != NULL) { - // We found the class in the system dictionary, so we should - // make sure that the Klass* matches what we already have. -- guarantee(k == probe->klass(), "klass should be in dictionary"); -+ guarantee(k == probe->klass()->newest_version(), "klass should be in dictionary"); - } else { - // If we don't find the class in the system dictionary, it - // has to be in the placeholders table. -diff -r 8a6717910608 src/share/vm/classfile/systemDictionary.cpp ---- a/src/share/vm/classfile/systemDictionary.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/systemDictionary.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -174,6 +174,7 @@ - // can return a null klass - klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD); - } -+ assert(klass == NULL || klass->is_newest_version() || klass->newest_version()->is_redefining(), "must be"); - return klass; - } - -@@ -216,7 +217,7 @@ - // Forwards to resolve_instance_class_or_null - - Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { -- assert(!THREAD->is_Compiler_thread(), -+ assert(!THREAD->is_Compiler_thread() || JvmtiThreadState::state_for(JavaThread::current())->get_class_being_redefined() != NULL, - 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()->name()->as_C_string())); -@@ -1029,8 +1030,10 @@ - instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, - loader_data, - protection_domain, -+ KlassHandle(), - host_klass, - cp_patches, -+ NULL, - parsed_name, - true, - THREAD); -@@ -1085,6 +1088,7 @@ - Handle protection_domain, - ClassFileStream* st, - bool verify, -+ KlassHandle old_class, - TRAPS) { - - // Classloaders that support parallelism, e.g. bootstrap classloader, -@@ -1112,9 +1116,15 @@ - instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, - loader_data, - protection_domain, -+ old_class, - parsed_name, - verify, - THREAD); -+ // (DCEVM) During enhanced class redefinition, mark loaded class as being redefined -+ if (!old_class.is_null() && !k.is_null()) { -+ k->set_redefining(true); -+ k->set_old_version(old_class()); -+ } - - const char* pkg = "java/"; - if (!HAS_PENDING_EXCEPTION && -@@ -1149,10 +1159,11 @@ - // 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 -- if (is_parallelCapable(class_loader)) { -+ // (DCEVM) TODO: for class redefinition the parallel version does not work, check if this is a problem? -+ if (is_parallelCapable(class_loader) && old_class.is_null()) { - k = find_or_define_instance_class(class_name, class_loader, k, THREAD); - } else { -- define_instance_class(k, THREAD); -+ define_instance_class(k, old_class, THREAD); - } - } - -@@ -1166,7 +1177,7 @@ - MutexLocker mu(SystemDictionary_lock, THREAD); - - Klass* check = find_class(parsed_name, loader_data); -- assert(check == k(), "should be present in the dictionary"); -+ assert((check == k() && !k->is_redefining()) || (k->is_redefining() && check == k->old_version()), "should be present in the dictionary"); - - Klass* check2 = find_class(h_name, defining_loader_data); - assert(check == check2, "name inconsistancy in SystemDictionary"); -@@ -1386,7 +1397,11 @@ - } - } - --void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { -+void SystemDictionary::rollback_redefinition() { -+ dictionary()->rollback_redefinition(); -+} -+ -+void SystemDictionary::define_instance_class(instanceKlassHandle k, KlassHandle old_class, TRAPS) { - - ClassLoaderData* loader_data = k->class_loader_data(); - Handle class_loader_h(THREAD, loader_data->class_loader()); -@@ -1416,7 +1431,17 @@ - Symbol* name_h = k->name(); - unsigned int d_hash = dictionary()->compute_hash(name_h, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); -- check_constraints(d_index, d_hash, k, class_loader_h, true, CHECK); -+ -+ // (DCEVM) Update version of the Klass* in the system dictionary -+ // TODO: Check for thread safety! -+ if (!old_class.is_null()) { -+ bool ok = dictionary()->update_klass(d_index, d_hash, name_h, loader_data, k, old_class); -+ assert (ok, "must have found old class and updated!"); -+ } -+ check_constraints(d_index, d_hash, k, class_loader_h, old_class.is_null(), CHECK); -+ -+ // FIXME: (DCEVM) clean this... -+ if(!old_class.is_null() && TraceRedefineClasses >= 3){ tty->print_cr("Class has been updated!"); } - - // Register class just loaded with class loader (placed in Vector) - // Note we do this before updating the dictionary, as this can -@@ -1449,8 +1474,9 @@ - } - k->eager_initialize(THREAD); - -+ // (DCEVM) Only notify jvmti if not redefining a class. - // notify jvmti -- if (JvmtiExport::should_post_class_load()) { -+ if (JvmtiExport::should_post_class_load() && old_class.is_null()) { - assert(THREAD->is_Java_thread(), "thread->is_Java_thread()"); - JvmtiExport::post_class_load((JavaThread *) THREAD, k()); - -@@ -1524,7 +1550,7 @@ - } - } - -- define_instance_class(k, THREAD); -+ define_instance_class(k, KlassHandle(), THREAD); - - Handle linkage_exception = Handle(); // null handle - -@@ -1654,6 +1680,14 @@ - Universe::flush_dependents_on(k); - } - -+// (DCEVM) Remove from hierarchy - Undo add_to_hierarchy. -+void SystemDictionary::remove_from_hierarchy(instanceKlassHandle k) { -+ assert(k.not_null(), "just checking"); -+ -+ // remove receiver from sibling list -+ k->remove_from_sibling_list(); -+ // TODO (DCEVM): Remove from interfaces. -+} - - // ---------------------------------------------------------------------------- - // GC support -@@ -2000,7 +2034,7 @@ - // also holds array classes - - assert(check->oop_is_instance(), "noninstance in systemdictionary"); -- if ((defining == true) || (k() != check)) { -+ if ((defining == true) && ((k() != check) && k->old_version() != check)) { - linkage_error = "loader (instance of %s): attempted duplicate class " - "definition for name: \"%s\""; - } else { -diff -r 8a6717910608 src/share/vm/classfile/systemDictionary.hpp ---- a/src/share/vm/classfile/systemDictionary.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/systemDictionary.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -269,7 +269,7 @@ - // Resolve from stream (called by jni_DefineClass and JVM_DefineClass) - static Klass* resolve_from_stream(Symbol* class_name, Handle class_loader, - Handle protection_domain, -- ClassFileStream* st, bool verify, TRAPS); -+ ClassFileStream* st, bool verify, KlassHandle old_class, TRAPS); - - // Lookup an already loaded class. If not found NULL is returned. - static Klass* find(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS); -@@ -339,6 +339,8 @@ - // System loader lock - static oop system_loader_lock() { return _system_loader_lock_obj; } - -+ // (DCEVM) Remove link to hierarchy -+ static void remove_from_hierarchy(instanceKlassHandle k); - private: - // Extended Redefine classes support (tbi) - static void preloaded_classes_do(KlassClosure* f); -@@ -408,6 +410,9 @@ - initialize_wk_klasses_until((WKID) limit, start_id, THREAD); - } - -+ // (DCEVM) rollback class redefinition -+ static void rollback_redefinition(); -+ - public: - #define WK_KLASS_DECLARE(name, symbol, option) \ - static Klass* name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); } \ -@@ -613,7 +618,7 @@ - // after waiting, but before reentering SystemDictionary_lock - // to preserve lock order semantics. - static void double_lock_wait(Handle lockObject, TRAPS); -- static void define_instance_class(instanceKlassHandle k, TRAPS); -+ static void define_instance_class(instanceKlassHandle k, KlassHandle old_class, TRAPS); - static instanceKlassHandle find_or_define_instance_class(Symbol* class_name, - Handle class_loader, - instanceKlassHandle k, TRAPS); -diff -r 8a6717910608 src/share/vm/classfile/verifier.cpp ---- a/src/share/vm/classfile/verifier.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/verifier.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -189,7 +189,7 @@ - Symbol* name = klass->name(); - Klass* refl_magic_klass = SystemDictionary::reflect_MagicAccessorImpl_klass(); - -- bool is_reflect = refl_magic_klass != NULL && klass->is_subtype_of(refl_magic_klass); -+ bool is_reflect = refl_magic_klass != NULL && (klass->is_subtype_of(refl_magic_klass) || klass->is_subtype_of(refl_magic_klass->newest_version())); - - return (should_verify_for(klass->class_loader(), should_verify_class) && - // return if the class is a bootstrapping class -@@ -518,7 +518,7 @@ - - ClassVerifier::ClassVerifier( - instanceKlassHandle klass, TRAPS) -- : _thread(THREAD), _exception_type(NULL), _message(NULL), _klass(klass) { -+ : _thread(THREAD), _exception_type(NULL), _message(NULL), _klass(klass->newest_version()), _klass_to_verify(klass) { - _this_type = VerificationType::reference_type(klass->name()); - // Create list to hold symbols in reference area. - _symbols = new GrowableArray<Symbol*>(100, 0, NULL); -@@ -548,7 +548,7 @@ - _klass->external_name()); - } - -- Array<Method*>* methods = _klass->methods(); -+ Array<Method*>* methods = _klass_to_verify->methods(); - int num_methods = methods->length(); - - for (int index = 0; index < num_methods; index++) { -diff -r 8a6717910608 src/share/vm/classfile/verifier.hpp ---- a/src/share/vm/classfile/verifier.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/classfile/verifier.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -331,6 +331,7 @@ - - VerificationType object_type() const; - -+ instanceKlassHandle _klass_to_verify; - instanceKlassHandle _klass; // the class being verified - methodHandle _method; // current method being verified - VerificationType _this_type; // the verification type of the current class -diff -r 8a6717910608 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp ---- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -161,6 +161,12 @@ - } - } - -+HeapWord* CompactibleFreeListSpace::forward_compact_top(size_t size, -+ CompactPoint* cp, HeapWord* compact_top) { -+ ShouldNotReachHere(); -+ return NULL; -+} -+ - // 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. -@@ -2098,7 +2104,7 @@ - // Support for compaction - - void CompactibleFreeListSpace::prepare_for_compaction(CompactPoint* cp) { -- SCAN_AND_FORWARD(cp,end,block_is_obj,block_size); -+ SCAN_AND_FORWARD(cp,end,block_is_obj,block_size,false); - // 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. -@@ -2119,7 +2125,7 @@ - } - - void CompactibleFreeListSpace::compact() { -- SCAN_AND_COMPACT(obj_size); -+ SCAN_AND_COMPACT(obj_size, false); - } - - // fragmentation_metric = 1 - [sum of (fbs**2) / (sum of fbs)**2] -diff -r 8a6717910608 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp ---- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -150,6 +150,7 @@ - - // Support for compacting cms - HeapWord* cross_threshold(HeapWord* start, HeapWord* end); -+ HeapWord* forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top); - HeapWord* forward(oop q, size_t size, CompactPoint* cp, HeapWord* compact_top); - - // Initialization helpers. -diff -r 8a6717910608 src/share/vm/gc_implementation/shared/markSweep.cpp ---- a/src/share/vm/gc_implementation/shared/markSweep.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/gc_implementation/shared/markSweep.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -32,6 +32,8 @@ - #include "oops/objArrayKlass.inline.hpp" - #include "oops/oop.inline.hpp" - -+GrowableArray<HeapWord*>* MarkSweep::_rescued_oops = NULL; -+ - uint MarkSweep::_total_invocations = 0; - - Stack<oop, mtGC> MarkSweep::_marking_stack; -@@ -171,3 +173,100 @@ - } - - #endif -+ -+// (DCEVM) Copy the rescued objects to their destination address after compaction. -+void MarkSweep::copy_rescued_objects_back() { -+ -+ if (_rescued_oops != NULL) { -+ -+ for (int i=0; i<_rescued_oops->length(); i++) { -+ HeapWord* rescued_ptr = _rescued_oops->at(i); -+ oop rescued_obj = (oop) rescued_ptr; -+ -+ int size = rescued_obj->size(); -+ oop new_obj = rescued_obj->forwardee(); -+ -+ assert(rescued_obj->klass()->new_version() != NULL, "just checking"); -+ -+ if (rescued_obj->klass()->new_version()->update_information() != NULL) { -+ MarkSweep::update_fields(rescued_obj, new_obj); -+ } else { -+ rescued_obj->set_klass(rescued_obj->klass()->new_version()); -+ Copy::aligned_disjoint_words((HeapWord*)rescued_obj, (HeapWord*)new_obj, size); -+ } -+ -+ FREE_RESOURCE_ARRAY(HeapWord, rescued_ptr, size); -+ -+ new_obj->init_mark(); -+ assert(new_obj->is_oop(), "must be a valid oop"); -+ } -+ _rescued_oops->clear(); -+ _rescued_oops = NULL; -+ } -+} -+ -+// (DCEVM) Update instances of a class whose fields changed. -+void MarkSweep::update_fields(oop q, oop new_location) { -+ -+ assert(q->klass()->new_version() != NULL, "class of old object must have new version"); -+ -+ Klass* old_klass_oop = q->klass(); -+ Klass* new_klass_oop = q->klass()->new_version(); -+ -+ InstanceKlass *old_klass = InstanceKlass::cast(old_klass_oop); -+ InstanceKlass *new_klass = InstanceKlass::cast(new_klass_oop); -+ -+ int size = q->size_given_klass(old_klass); -+ int new_size = q->size_given_klass(new_klass); -+ -+ HeapWord* tmp = NULL; -+ oop tmp_obj = q; -+ -+ // Save object somewhere, there is an overlap in fields -+ if (new_klass_oop->is_copying_backwards()) { -+ if (((HeapWord *)q >= (HeapWord *)new_location && (HeapWord *)q < (HeapWord *)new_location + new_size) || -+ ((HeapWord *)new_location >= (HeapWord *)q && (HeapWord *)new_location < (HeapWord *)q + size)) { -+ tmp = NEW_RESOURCE_ARRAY(HeapWord, size); -+ q = (oop) tmp; -+ Copy::aligned_disjoint_words((HeapWord*)q, (HeapWord*)tmp_obj, size); -+ } -+ } -+ -+ q->set_klass(new_klass_oop); -+ int *cur = new_klass_oop->update_information(); -+ assert(cur != NULL, "just checking"); -+ MarkSweep::update_fields(new_location, q, cur); -+ -+ if (tmp != NULL) { -+ FREE_RESOURCE_ARRAY(HeapWord, tmp, size); -+ } -+} -+ -+void MarkSweep::update_fields(oop new_location, oop tmp_obj, int *cur) { -+ assert(cur != NULL, "just checking"); -+ char* to = (char*)(HeapWord*)new_location; -+ while (*cur != 0) { -+ int size = *cur; -+ if (size > 0) { -+ cur++; -+ int offset = *cur; -+ HeapWord* from = (HeapWord*)(((char *)(HeapWord*)tmp_obj) + offset); -+ if (size == HeapWordSize) { -+ *((HeapWord*)to) = *from; -+ } else if (size == HeapWordSize * 2) { -+ *((HeapWord*)to) = *from; -+ *(((HeapWord*)to) + 1) = *(from + 1); -+ } else { -+ Copy::conjoint_jbytes(from, to, size); -+ } -+ to += size; -+ cur++; -+ } else { -+ assert(size < 0, ""); -+ int skip = -*cur; -+ Copy::fill_to_bytes(to, skip, 0); -+ to += skip; -+ cur++; -+ } -+ } -+} -diff -r 8a6717910608 src/share/vm/gc_implementation/shared/markSweep.hpp ---- a/src/share/vm/gc_implementation/shared/markSweep.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/gc_implementation/shared/markSweep.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -107,8 +107,12 @@ - friend class AdjustPointerClosure; - friend class KeepAliveClosure; - friend class VM_MarkSweep; -+ friend class GenMarkSweep; - friend void marksweep_init(); - -+public: -+ static GrowableArray<HeapWord*>* _rescued_oops; -+ - // - // Vars - // -@@ -169,6 +173,9 @@ - - static inline void push_objarray(oop obj, size_t index); - -+ static void copy_rescued_objects_back(); -+ static void update_fields(oop q, oop new_location); -+ static void update_fields(oop new_location, oop tmp_obj, int *cur); - static void follow_stack(); // Empty marking stack. - - static void follow_klass(Klass* klass); -diff -r 8a6717910608 src/share/vm/interpreter/linkResolver.cpp ---- a/src/share/vm/interpreter/linkResolver.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/interpreter/linkResolver.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -215,8 +215,8 @@ - // Klass resolution - - void LinkResolver::check_klass_accessability(KlassHandle ref_klass, KlassHandle sel_klass, TRAPS) { -- if (!Reflection::verify_class_access(ref_klass(), -- sel_klass(), -+ if (!Reflection::verify_class_access(ref_klass()->newest_version(), -+ sel_klass()->newest_version(), - true)) { - ResourceMark rm(THREAD); - Exceptions::fthrow( -@@ -444,7 +444,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() && -- sel_klass() == SystemDictionary::Object_klass() && -+ sel_klass()->newest_version() == SystemDictionary::Object_klass()->newest_version() && - resolved_klass->oop_is_array()) { - // We need to change "protected" to "public". - assert(flags.is_protected(), "clone not protected?"); -@@ -802,7 +802,7 @@ - } - - // Final fields can only be accessed from its own class. -- if (is_put && fd.access_flags().is_final() && sel_klass() != current_klass()) { -+ if (is_put && fd.access_flags().is_final() && sel_klass() != current_klass() && sel_klass() != current_klass()->active_version()) { - THROW(vmSymbols::java_lang_IllegalAccessError()); - } - -@@ -1199,6 +1199,16 @@ - // 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(); -+ -+ // (DCEVM) Check that the receiver is a subtype of the holder of the resolved method. -+ if (!inst->is_subtype_of(resolved_method->method_holder())) { -+ inst->print(); -+ tty->print_cr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ resolved_method->method_holder()->print(); -+ tty->print_cr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ resolved_method->print(); -+ } -+ assert(inst->is_subtype_of(resolved_method->method_holder()), "receiver and resolved method holder are inconsistent"); - selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index)); - } - } -diff -r 8a6717910608 src/share/vm/memory/genMarkSweep.cpp ---- a/src/share/vm/memory/genMarkSweep.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/memory/genMarkSweep.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -334,11 +334,16 @@ - // 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. -+ assert(_rescued_oops == NULL, "must be empty before processing"); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - - GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer); - trace("4"); - -+ MarkSweep::copy_rescued_objects_back(); -+ - GenCompactClosure blk; - gch->generation_iterate(&blk, true); -+ -+ MarkSweep::copy_rescued_objects_back(); - } -diff -r 8a6717910608 src/share/vm/memory/space.cpp ---- a/src/share/vm/memory/space.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/memory/space.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -379,9 +379,8 @@ - _compaction_top = bottom(); - } - --HeapWord* CompactibleSpace::forward(oop q, size_t size, -- CompactPoint* cp, HeapWord* compact_top) { -- // q is alive -+// (DCEVM) Calculates the compact_top that will be used for placing the next object with the giving size on the heap. -+HeapWord* CompactibleSpace::forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top) { - // 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); -@@ -401,8 +400,15 @@ - compaction_max_size = pointer_delta(cp->space->end(), compact_top); - } - -+ return compact_top; -+} -+ -+HeapWord* CompactibleSpace::forward(oop q, size_t size, -+ CompactPoint* cp, HeapWord* compact_top) { -+ compact_top = forward_compact_top(size, cp, compact_top); -+ - // store the forwarding pointer into the mark word -- if ((HeapWord*)q != compact_top) { -+ if ((HeapWord*)q != compact_top || (size_t)q->size() != size) { - q->forward_to(oop(compact_top)); - assert(q->is_gc_marked(), "encoding the pointer should preserve the mark"); - } else { -@@ -423,6 +429,58 @@ - return compact_top; - } - -+// Compute the forward sizes and leave out objects whose position could -+// possibly overlap other objects. -+HeapWord* CompactibleSpace::forward_with_rescue(HeapWord* q, size_t size, -+ CompactPoint* cp, HeapWord* compact_top) { -+ size_t forward_size = size; -+ -+ // (DCEVM) There is a new version of the class of q => different size -+ if (oop(q)->klass()->new_version() != NULL && oop(q)->klass()->new_version()->update_information() != NULL) { -+ -+ size_t new_size = oop(q)->size_given_klass(oop(q)->klass()->new_version()); -+ assert(size != new_size, "instances without changed size have to be updated prior to GC run"); -+ forward_size = new_size; -+ } -+ -+ compact_top = forward_compact_top(forward_size, cp, compact_top); -+ -+ if (must_rescue(oop(q), oop(compact_top))) { -+ if (MarkSweep::_rescued_oops == NULL) { -+ MarkSweep::_rescued_oops = new GrowableArray<HeapWord*>(128); -+ } -+ MarkSweep::_rescued_oops->append(q); -+ return compact_top; -+ } -+ -+ return forward(oop(q), forward_size, cp, compact_top); -+} -+ -+// Compute the forwarding addresses for the objects that need to be rescued. -+HeapWord* CompactibleSpace::forward_rescued(CompactPoint* cp, HeapWord* compact_top) { -+ // TODO: empty the _rescued_oops after ALL spaces are compacted! -+ if (MarkSweep::_rescued_oops != NULL) { -+ for (int i=0; i<MarkSweep::_rescued_oops->length(); i++) { -+ HeapWord* q = MarkSweep::_rescued_oops->at(i); -+ -+ /* size_t size = oop(q)->size(); changing this for cms for perm gen */ -+ size_t size = block_size(q); -+ -+ // (DCEVM) There is a new version of the class of q => different size -+ if (oop(q)->klass()->new_version() != NULL) { -+ size_t new_size = oop(q)->size_given_klass(oop(q)->klass()->new_version()); -+ assert(size != new_size, "instances without changed size have to be updated prior to GC run"); -+ size = new_size; -+ } -+ -+ compact_top = cp->space->forward(oop(q), size, cp, compact_top); -+ assert(compact_top <= end(), "must not write over end of space!"); -+ } -+ MarkSweep::_rescued_oops->clear(); -+ MarkSweep::_rescued_oops = NULL; -+ } -+ return compact_top; -+} - - bool CompactibleSpace::insert_deadspace(size_t& allowed_deadspace_words, - HeapWord* q, size_t deadlength) { -@@ -444,12 +502,17 @@ - #define adjust_obj_size(s) s - - void CompactibleSpace::prepare_for_compaction(CompactPoint* cp) { -- SCAN_AND_FORWARD(cp, end, block_is_obj, block_size); -+ SCAN_AND_FORWARD(cp, end, block_is_obj, block_size, false); - } - - // Faster object search. - void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) { -- SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size); -+ if (!Universe::is_redefining_gc_run()) { -+ SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size, false); -+ } else { -+ // Redefinition run -+ SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size, true); -+ } - } - - void Space::adjust_pointers() { -@@ -487,6 +550,111 @@ - assert(q == t, "just checking"); - } - -+ -+#ifdef ASSERT -+ -+int CompactibleSpace::space_index(oop obj) { -+ GenCollectedHeap* heap = GenCollectedHeap::heap(); -+ -+ //if (heap->is_in_permanent(obj)) { -+ // return -1; -+ //} -+ -+ int index = 0; -+ for (int i = heap->n_gens() - 1; i >= 0; i--) { -+ Generation* gen = heap->get_gen(i); -+ CompactibleSpace* space = gen->first_compaction_space(); -+ while (space != NULL) { -+ if (space->is_in_reserved(obj)) { -+ return index; -+ } -+ space = space->next_compaction_space(); -+ index++; -+ } -+ } -+ -+ tty->print_cr("could not compute space_index for %08xh", (HeapWord*)obj); -+ index = 0; -+ for (int i = heap->n_gens() - 1; i >= 0; i--) { -+ Generation* gen = heap->get_gen(i); -+ tty->print_cr(" generation %s: %08xh - %08xh", gen->name(), gen->reserved().start(), gen->reserved().end()); -+ -+ CompactibleSpace* space = gen->first_compaction_space(); -+ while (space != NULL) { -+ tty->print_cr(" %2d space %08xh - %08xh", index, space->bottom(), space->end()); -+ space = space->next_compaction_space(); -+ index++; -+ } -+ } -+ -+ ShouldNotReachHere(); -+ return 0; -+} -+#endif -+ -+bool CompactibleSpace::must_rescue(oop old_obj, oop new_obj) { -+ // Only redefined objects can have the need to be rescued. -+ if (oop(old_obj)->klass()->new_version() == NULL) return false; -+ -+ //if (old_obj->is_perm()) { -+ // // This object is in perm gen: Always rescue to satisfy invariant obj->klass() <= obj. -+ // return true; -+ //} -+ -+ int new_size = old_obj->size_given_klass(oop(old_obj)->klass()->new_version()); -+ int original_size = old_obj->size(); -+ -+ Generation* tenured_gen = GenCollectedHeap::heap()->get_gen(1); -+ bool old_in_tenured = tenured_gen->is_in_reserved(old_obj); -+ bool new_in_tenured = tenured_gen->is_in_reserved(new_obj); -+ if (old_in_tenured == new_in_tenured) { -+ // Rescue if object may overlap with a higher memory address. -+ bool overlap = ((HeapWord*)old_obj + original_size < (HeapWord*)new_obj + new_size); -+ if (old_in_tenured) { -+ // Old and new address are in same space, so just compare the address. -+ // Must rescue if object moves towards the top of the space. -+ assert(space_index(old_obj) == space_index(new_obj), "old_obj and new_obj must be in same space"); -+ } else { -+ // In the new generation, eden is located before the from space, so a -+ // simple pointer comparison is sufficient. -+ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(old_obj), "old_obj must be in DefNewGeneration"); -+ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(new_obj), "new_obj must be in DefNewGeneration"); -+ assert(overlap == (space_index(old_obj) < space_index(new_obj)), "slow and fast computation must yield same result"); -+ } -+ return overlap; -+ -+ } else { -+ assert(space_index(old_obj) != space_index(new_obj), "old_obj and new_obj must be in different spaces"); -+ if (tenured_gen->is_in_reserved(new_obj)) { -+ // Must never rescue when moving from the new into the old generation. -+ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(old_obj), "old_obj must be in DefNewGeneration"); -+ assert(space_index(old_obj) > space_index(new_obj), "must be"); -+ return false; -+ -+ } else /* if (tenured_gen->is_in_reserved(old_obj)) */ { -+ // Must always rescue when moving from the old into the new generation. -+ assert(GenCollectedHeap::heap()->get_gen(0)->is_in_reserved(new_obj), "new_obj must be in DefNewGeneration"); -+ assert(space_index(old_obj) < space_index(new_obj), "must be"); -+ return true; -+ } -+ } -+} -+ -+HeapWord* CompactibleSpace::rescue(HeapWord* old_obj) { -+ assert(must_rescue(oop(old_obj), oop(old_obj)->forwardee()), "do not call otherwise"); -+ -+ int size = oop(old_obj)->size(); -+ HeapWord* rescued_obj = NEW_RESOURCE_ARRAY(HeapWord, size); -+ Copy::aligned_disjoint_words(old_obj, rescued_obj, size); -+ -+ if (MarkSweep::_rescued_oops == NULL) { -+ MarkSweep::_rescued_oops = new GrowableArray<HeapWord*>(128); -+ } -+ -+ MarkSweep::_rescued_oops->append(rescued_obj); -+ return rescued_obj; -+} -+ - void CompactibleSpace::adjust_pointers() { - // Check first is there is any work to do. - if (used() == 0) { -@@ -497,7 +665,12 @@ - } - - void CompactibleSpace::compact() { -- SCAN_AND_COMPACT(obj_size); -+ if(!Universe::is_redefining_gc_run()) { -+ SCAN_AND_COMPACT(obj_size, false); -+ } else { -+ // Redefinition run -+ SCAN_AND_COMPACT(obj_size, true) -+ } - } - - void Space::print_short() const { print_short_on(tty); } -diff -r 8a6717910608 src/share/vm/memory/space.hpp ---- a/src/share/vm/memory/space.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/memory/space.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -450,6 +450,9 @@ - // indicates when the next such action should be taken. - virtual void prepare_for_compaction(CompactPoint* cp); - // MarkSweep support phase3 -+ DEBUG_ONLY(int space_index(oop obj)); -+ bool must_rescue(oop old_obj, oop new_obj); -+ HeapWord* rescue(HeapWord* old_obj); - virtual void adjust_pointers(); - // MarkSweep support phase4 - virtual void compact(); -@@ -479,6 +482,15 @@ - // accordingly". - virtual HeapWord* forward(oop q, size_t size, CompactPoint* cp, - HeapWord* compact_top); -+ // (DCEVM) same as forwad, but can rescue objects. Invoked only during -+ // redefinition runs -+ HeapWord* forward_with_rescue(HeapWord* q, size_t size, CompactPoint* cp, -+ HeapWord* compact_top); -+ -+ HeapWord* forward_rescued(CompactPoint* cp, HeapWord* compact_top); -+ -+ // (tw) Compute new compact top without actually forwarding the object. -+ virtual HeapWord* forward_compact_top(size_t size, CompactPoint* cp, HeapWord* compact_top); - - // Return a size with adjusments as required of the space. - virtual size_t adjust_object_size_v(size_t size) const { return size; } -@@ -509,7 +521,7 @@ - size_t word_len); - }; - --#define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size) { \ -+#define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size,redefinition_run) { \ - /* Compute the new addresses for the live objects and store it in the mark \ - * Used by universe::mark_sweep_phase2() \ - */ \ -@@ -567,7 +579,17 @@ - /* prefetch beyond q */ \ - Prefetch::write(q, interval); \ - size_t size = block_size(q); \ -+ if (redefinition_run) { \ -+ compact_top = cp->space->forward_with_rescue(q, size, \ -+ cp, compact_top); \ -+ if (q < first_dead && oop(q)->is_gc_marked()) { \ -+ /* Was moved (otherwise, forward would reset mark), \ -+ set first_dead to here */ \ -+ first_dead = q; \ -+ } \ -+ } else { \ - compact_top = cp->space->forward(oop(q), size, cp, compact_top); \ -+ } \ - q += size; \ - end_of_live = q; \ - } else { \ -@@ -616,6 +638,8 @@ - } \ - } \ - \ -+ if (redefinition_run) { compact_top = forward_rescued(cp, compact_top); } \ -+ \ - assert(q == t, "just checking"); \ - if (liveRange != NULL) { \ - liveRange->set_end(q); \ -@@ -662,13 +686,8 @@ - q += size; \ - } \ - \ -- if (_first_dead == t) { \ -- q = t; \ -- } else { \ -- /* $$$ This is funky. Using this to read the previously written \ -- * LiveRange. See also use below. */ \ -- q = (HeapWord*)oop(_first_dead)->mark()->decode_pointer(); \ -- } \ -+ /* (DCEVM) first_dead can be live object if we move/rescue resized objects */ \ -+ q = _first_dead; \ - } \ - \ - const intx interval = PrefetchScanIntervalInBytes; \ -@@ -696,7 +715,7 @@ - assert(q == t, "just checking"); \ - } - --#define SCAN_AND_COMPACT(obj_size) { \ -+#define SCAN_AND_COMPACT(obj_size, redefinition_run) { \ - /* Copy all live objects to their new location \ - * Used by MarkSweep::mark_sweep_phase4() */ \ - \ -@@ -721,13 +740,9 @@ - } \ - ) /* debug_only */ \ - \ -- if (_first_dead == t) { \ -- q = t; \ -- } else { \ -- /* $$$ Funky */ \ -- q = (HeapWord*) oop(_first_dead)->mark()->decode_pointer(); \ -+ /* (DCEVM) first_dead can be live object if we move/rescue resized objects */ \ -+ q = _first_dead; \ - } \ -- } \ - \ - const intx scan_interval = PrefetchScanIntervalInBytes; \ - const intx copy_interval = PrefetchCopyIntervalInBytes; \ -@@ -745,11 +760,34 @@ - size_t size = obj_size(q); \ - HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); \ - \ -+ if (redefinition_run && must_rescue(oop(q), oop(q)->forwardee())) { \ -+ rescue(q); \ -+ debug_only(Copy::fill_to_words(q, size, 0)); \ -+ q += size; \ -+ continue; \ -+ } \ -+ \ - /* prefetch beyond compaction_top */ \ - Prefetch::write(compaction_top, copy_interval); \ - \ - /* copy object and reinit its mark */ \ -- assert(q != compaction_top, "everything in this pass should be moving"); \ -+ assert(q != compaction_top || oop(q)->klass()->new_version() != NULL, \ -+ "everything in this pass should be moving"); \ -+ if (redefinition_run && oop(q)->klass()->new_version() != NULL) { \ -+ Klass* new_version = oop(q)->klass()->new_version(); \ -+ if (new_version->update_information() == NULL) { \ -+ Copy::aligned_conjoint_words(q, compaction_top, size); \ -+ oop(compaction_top)->set_klass(new_version); \ -+ } else { \ -+ MarkSweep::update_fields(oop(q), oop(compaction_top)); \ -+ } \ -+ oop(compaction_top)->init_mark(); \ -+ assert(oop(compaction_top)->klass() != NULL, "should have a class"); \ -+ \ -+ debug_only(prev_q = q); \ -+ q += size; \ -+ continue; \ -+ } \ - Copy::aligned_conjoint_words(q, compaction_top, size); \ - oop(compaction_top)->init_mark(); \ - assert(oop(compaction_top)->klass() != NULL, "should have a class"); \ -diff -r 8a6717910608 src/share/vm/memory/universe.cpp ---- a/src/share/vm/memory/universe.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/memory/universe.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -78,6 +78,8 @@ - #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" - #endif // INCLUDE_ALL_GCS - -+bool Universe::_is_redefining_gc_run = false; -+ - // Known objects - Klass* Universe::_boolArrayKlassObj = NULL; - Klass* Universe::_byteArrayKlassObj = NULL; -@@ -157,6 +159,42 @@ - f(doubleArrayKlassObj()); - } - -+// (DCEVM) This method should iterate all pointers that are not within heap objects. -+void Universe::root_oops_do(OopClosure *oopClosure) { -+ -+ class AlwaysTrueClosure: public BoolObjectClosure { -+ public: -+ void do_object(oop p) { ShouldNotReachHere(); } -+ bool do_object_b(oop p) { return true; } -+ }; -+ AlwaysTrueClosure always_true; -+ -+ Universe::oops_do(oopClosure); -+// ReferenceProcessor::oops_do(oopClosure); (tw) check why no longer there -+ JNIHandles::oops_do(oopClosure); // Global (strong) JNI handles -+ Threads::oops_do(oopClosure, NULL, NULL); -+ ObjectSynchronizer::oops_do(oopClosure); -+ FlatProfiler::oops_do(oopClosure); -+ JvmtiExport::oops_do(oopClosure); -+ -+ // Now adjust pointers in remaining weak roots. (All of which should -+ // have been cleared if they pointed to non-surviving objects.) -+ // Global (weak) JNI handles -+ JNIHandles::weak_oops_do(&always_true, oopClosure); -+ -+ CodeCache::oops_do(oopClosure); -+ StringTable::oops_do(oopClosure); -+ -+ // (DCEVM) TODO: Check if this is correct? -+ //CodeCache::scavenge_root_nmethods_oops_do(oopClosure); -+ //Management::oops_do(oopClosure); -+ //ref_processor()->weak_oops_do(&oopClosure); -+ //PSScavenge::reference_processor()->weak_oops_do(&oopClosure); -+ -+ // SO_AllClasses -+ SystemDictionary::oops_do(oopClosure); -+} -+ - void Universe::oops_do(OopClosure* f, bool do_all) { - - f->do_oop((oop*) &_int_mirror); -diff -r 8a6717910608 src/share/vm/memory/universe.hpp ---- a/src/share/vm/memory/universe.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/memory/universe.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -248,7 +248,13 @@ - - static void compute_verify_oop_data(); - -+ static bool _is_redefining_gc_run; -+ - public: -+ -+ static bool is_redefining_gc_run() { return _is_redefining_gc_run; } -+ static void set_redefining_gc_run(bool b) { _is_redefining_gc_run = b; } -+ - // Known classes in the VM - static Klass* boolArrayKlassObj() { return _boolArrayKlassObj; } - static Klass* byteArrayKlassObj() { return _byteArrayKlassObj; } -@@ -401,6 +407,7 @@ - static void run_finalizers_on_exit(); - - // Iteration -+ static void root_oops_do(OopClosure *f); - - // Apply "f" to the addresses of all the direct heap pointers maintained - // as static fields of "Universe". -diff -r 8a6717910608 src/share/vm/oops/cpCache.cpp ---- a/src/share/vm/oops/cpCache.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/cpCache.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -336,7 +336,8 @@ - if (has_appendix) { - const int appendix_index = f2_as_index() + _indy_resolved_references_appendix_offset; - assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob"); -- assert(resolved_references->obj_at(appendix_index) == NULL, "init just once"); -+ // FIXME (DCEVM) relaxing for now... -+ //assert(resolved_references->obj_at(appendix_index) == NULL, "init just once"); - resolved_references->obj_at_put(appendix_index, appendix()); - } - -@@ -344,7 +345,8 @@ - if (has_method_type) { - const int method_type_index = f2_as_index() + _indy_resolved_references_method_type_offset; - assert(method_type_index >= 0 && method_type_index < resolved_references->length(), "oob"); -- assert(resolved_references->obj_at(method_type_index) == NULL, "init just once"); -+ // FIXME (DCEVM) relaxing for now... -+ //assert(resolved_references->obj_at(method_type_index) == NULL, "init just once"); - resolved_references->obj_at_put(method_type_index, method_type()); - } - -@@ -532,6 +534,26 @@ - // the method is in the interesting class so the entry is interesting - return true; - } -+ -+// Enhanced RedefineClasses() API support (DCEVM): -+// Clear cached entry, let it be re-resolved -+void ConstantPoolCacheEntry::clear_entry() { -+ // Clear entry during class redefinition. Note that we still keep flags. -+ if (has_appendix()) { -+ // (DCEVM): Now this gets really ugly. If this entry is used by invokehandle, we cannot -+ // clear it just like that (data is used by _invokehandle bytecode which wouldn't re-resolve anything). -+ // FIXME: (DCEVM) need to figure out if we need to rewrite it somehow or it should be fine... -+ return; -+ } -+ _indices = constant_pool_index(); -+ _f1 = NULL; -+ _f2 = 0; -+ -+ // FIXME: (DCEVM) we want to clear flags, but parameter size is actually used -+ // after we return from the method, before entry is re-initialized. So let's -+ // keep parameter size the same. -+ _flags &= 0x0000000f; -+} - #endif // INCLUDE_JVMTI - - void ConstantPoolCacheEntry::print(outputStream* st, int index) const { -@@ -660,6 +682,14 @@ - } - } - } -+ -+// Enhanced RedefineClasses() API support (DCEVM): -+// Clear all entries -+void ConstantPoolCache::clear_entries() { -+ for (int i = 0; i < length(); i++) { -+ entry_at(i)->clear_entry(); -+ } -+} - #endif // INCLUDE_JVMTI - - -diff -r 8a6717910608 src/share/vm/oops/cpCache.hpp ---- a/src/share/vm/oops/cpCache.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/cpCache.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -373,6 +373,10 @@ - bool * trace_name_printed); - bool check_no_old_or_obsolete_entries(); - bool is_interesting_method_entry(Klass* k); -+ -+ // Enhanced RedefineClasses() API support (DCEVM): -+ // Clear cached entry, let it be re-resolved -+ void clear_entry(); - #endif // INCLUDE_JVMTI - - // Debugging & Printing -@@ -472,6 +476,10 @@ - int methods_length, bool * trace_name_printed); - bool check_no_old_or_obsolete_entries(); - void dump_cache(); -+ -+ // Enhanced RedefineClasses() API support (DCEVM): -+ // Clear all entries -+ void clear_entries(); - #endif // INCLUDE_JVMTI - - // Deallocate - no fields to deallocate -diff -r 8a6717910608 src/share/vm/oops/instanceKlass.cpp ---- a/src/share/vm/oops/instanceKlass.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/instanceKlass.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -718,7 +718,8 @@ - } - #endif - this_oop->set_init_state(linked); -- if (JvmtiExport::should_post_class_prepare()) { -+ // (DCEVM) Must check for old version in order to prevent infinite loops. -+ if (JvmtiExport::should_post_class_prepare() && this_oop->old_version() == NULL /* JVMTI deadlock otherwise */) { - Thread *thread = THREAD; - assert(thread->is_Java_thread(), "thread->is_Java_thread()"); - JvmtiExport::post_class_prepare((JavaThread *) thread, this_oop()); -@@ -795,7 +796,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. -- while(this_oop->is_being_initialized() && !this_oop->is_reentrant_initialization(self)) { -+ // (DCEVM) Wait also for the old class version to be fully initialized. -+ while((this_oop->is_being_initialized() && !this_oop->is_reentrant_initialization(self)) -+ || (this_oop->old_version() != NULL && InstanceKlass::cast(this_oop->old_version())->is_being_initialized())) { - wait = true; - ol.waitUninterruptibly(CHECK); - } -@@ -1051,6 +1054,18 @@ - return false; - } - -+bool InstanceKlass::implements_interface_any_version(Klass* k) const { -+ k = k->newest_version(); -+ if (this->newest_version() == k) return true; -+ assert(k->is_interface(), "should be an interface class"); -+ for (int i = 0; i < transitive_interfaces()->length(); i++) { -+ if (transitive_interfaces()->at(i)->newest_version() == k) { -+ return true; -+ } -+ } -+ return false; -+} -+ - bool InstanceKlass::is_same_or_direct_interface(Klass *k) const { - // Verify direct super interface - if (this == k) return true; -@@ -1314,6 +1329,18 @@ - } - } - -+void InstanceKlass::store_update_information(GrowableArray<int> &values) { -+ int *arr = NEW_C_HEAP_ARRAY(int, values.length(), mtClass); -+ for (int i=0; i<values.length(); i++) { -+ arr[i] = values.at(i); -+ } -+ set_update_information(arr); -+} -+ -+void InstanceKlass::clear_update_information() { -+ FREE_C_HEAP_ARRAY(int, update_information(), mtClass); -+ set_update_information(NULL); -+} - - void InstanceKlass::do_local_static_fields(FieldClosure* cl) { - for (JavaFieldStream fs(this); !fs.done(); fs.next()) { -@@ -1797,6 +1824,18 @@ - return id; - } - -+bool InstanceKlass::update_jmethod_id(Method* method, jmethodID newMethodID) { -+ size_t idnum = (size_t)method->method_idnum(); -+ jmethodID* jmeths = methods_jmethod_ids_acquire(); -+ size_t length; // length assigned as debugging crumb -+ jmethodID id = NULL; -+ if (jmeths != NULL && // If there is a cache -+ (length = (size_t)jmeths[0]) > idnum) { // and if it is long enough, -+ jmeths[idnum+1] = newMethodID; // Set method id (may be NULL) -+ return true; -+ } -+ return false; -+} - - // - // Walk the list of dependent nmethods searching for nmethods which -@@ -1875,6 +1914,13 @@ - last = b; - b = b->next(); - } -+ -+ // (DCEVM) Hack as dependencies get wrong version of Klass* -+ if (this->old_version() != NULL) { -+ InstanceKlass::cast(this->old_version())->remove_dependent_nmethod(nm); -+ return; -+ } -+ - #ifdef ASSERT - tty->print_cr("### %s can't find dependent nmethod:", this->external_name()); - nm->print(); -@@ -2884,6 +2930,24 @@ - assert(is_klass(), "must be klass"); - Klass::print_on(st); - -+ // (DCEVM) Output revision number and revision numbers of older / newer and oldest / newest version of this class. -+ if (AllowEnhancedClassRedefinition) { -+ st->print(BULLET"revision: %d", revision_number()); -+ if (new_version() != NULL) { -+ st->print(" (newer=%d)", new_version()->revision_number()); -+ } -+ if (newest_version() != new_version() && newest_version() != this) { -+ st->print(" (newest=%d)", newest_version()->revision_number()); -+ } -+ if (old_version() != NULL) { -+ st->print(" (old=%d)", old_version()->revision_number()); -+ } -+ if (oldest_version() != old_version() && oldest_version() != this) { -+ st->print(" (oldest=%d)", oldest_version()->revision_number()); -+ } -+ st->cr(); -+ } -+ - st->print(BULLET"instance size: %d", size_helper()); st->cr(); - st->print(BULLET"klass size: %d", size()); st->cr(); - st->print(BULLET"access: "); access_flags().print_on(st); st->cr(); -@@ -3219,7 +3283,7 @@ - } - - guarantee(sib->is_klass(), "should be klass"); -- guarantee(sib->super() == super, "siblings should have same superklass"); -+ guarantee(sib->super() == super || super->newest_version() == SystemDictionary::Object_klass(), "siblings should have same superklass"); - } - - // Verify implementor fields -@@ -3384,6 +3448,7 @@ - - // Purge previous versions - static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_count) { -+ // FIXME: (DCEVM) Should we purge something? - if (ik->previous_versions() != NULL) { - // This klass has previous versions so see what we can cleanup - // while it is safe to do so. -@@ -3621,7 +3686,7 @@ - - // Determine if InstanceKlass has a previous version. - bool InstanceKlass::has_previous_version() const { -- return (_previous_versions != NULL && _previous_versions->length() > 0); -+ return _old_version != NULL || (_previous_versions != NULL && _previous_versions->length() > 0); - } // end has_previous_version() - - -diff -r 8a6717910608 src/share/vm/oops/instanceKlass.hpp ---- a/src/share/vm/oops/instanceKlass.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/instanceKlass.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -139,6 +139,7 @@ - friend class VMStructs; - friend class ClassFileParser; - friend class CompileReplay; -+ friend class VM_EnhancedRedefineClasses; - - protected: - // Constructor -@@ -637,7 +638,7 @@ - // If the _previous_versions array is non-NULL, then this klass - // has been redefined at least once even if we aren't currently - // tracking a previous version. -- bool has_been_redefined() const { return _previous_versions != NULL; } -+ bool has_been_redefined() const { return _old_version != NULL || _previous_versions != NULL; } - bool has_previous_version() const; - void init_previous_versions() { - _previous_versions = NULL; -@@ -711,6 +712,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(Method* method); -+ bool update_jmethod_id(Method* method, jmethodID newMethodID); - - // annotations support - Annotations* annotations() const { return _annotations; } -@@ -780,6 +782,7 @@ - // subclass/subinterface checks - bool implements_interface(Klass* k) const; - bool is_same_or_direct_interface(Klass* k) const; -+ bool implements_interface_any_version(Klass* k) const; - - // Access to the implementor of an interface. - Klass* implementor() const -@@ -831,6 +834,10 @@ - void do_nonstatic_fields(FieldClosure* cl); // including inherited fields - void do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAPS); - -+ // (DCEVM) instance update information to be used in GC run -+ void store_update_information(GrowableArray<int> &values); -+ void clear_update_information(); -+ - void methods_do(void f(Method* method)); - void array_klasses_do(void f(Klass* k)); - void array_klasses_do(void f(Klass* k, TRAPS), TRAPS); -diff -r 8a6717910608 src/share/vm/oops/klass.cpp ---- a/src/share/vm/oops/klass.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/klass.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -170,6 +170,13 @@ - set_next_link(NULL); - TRACE_INIT_ID(this); - -+ set_redefinition_flags(Klass::NoRedefinition); -+ set_redefining(false); -+ set_new_version(NULL); -+ set_old_version(NULL); -+ set_redefinition_index(-1); -+ set_revision_number(-1); -+ - set_prototype_header(markOopDesc::prototype()); - set_biased_lock_revocation_count(0); - set_last_biased_lock_bulk_revocation_time(0); -@@ -375,6 +382,24 @@ - debug_only(verify();) - } - -+// (DCEVM) -+void Klass::remove_from_sibling_list() { -+ debug_only(verify();) -+ // remove ourselves to superklass' subklass list -+ InstanceKlass* super = superklass(); -+ assert(super != NULL, "should have super"); -+ if (super->subklass() == this) { -+ // first subklass -+ super->set_subklass(next_sibling()); -+ } else { -+ Klass* sib = super->subklass(); -+ while (sib->next_sibling() != this) { -+ sib = sib->next_sibling(); -+ }; -+ sib->set_next_sibling(next_sibling()); -+ } -+} -+ - bool Klass::is_loader_alive(BoolObjectClosure* is_alive) { - assert(ClassLoaderDataGraph::contains((address)this), "is in the metaspace"); - -diff -r 8a6717910608 src/share/vm/oops/klass.hpp ---- a/src/share/vm/oops/klass.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/klass.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -149,6 +149,10 @@ - oop _java_mirror; - // Superclass - Klass* _super; -+ // Old class -+ Klass* _old_version; -+ // New class -+ Klass* _new_version; - // First subclass (NULL if none); _subklass->next_sibling() is next one - Klass* _subklass; - // Sibling link (or NULL); links all subklasses of a klass -@@ -164,6 +168,16 @@ - jint _modifier_flags; // Processed access flags, for use by Class.getModifiers. - AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. - -+ // (DCEVM) fields for enhanced class redefinition -+ jint _revision_number; // The revision number for redefined classes -+ jint _redefinition_index; // Index of this class when performing the redefinition -+ bool _subtype_changed; -+ int _redefinition_flags; // Level of class redefinition -+ bool _is_copying_backwards; // Does the class need to copy fields backwards? => possibly overwrite itself? -+ bool _original_field_offsets_changed; // Did the original field offsets of this class change during class redefinition? -+ int * _update_information; // Update information -+ bool _is_redefining; -+ - // Biased locking implementation and statistics - // (the 64-bit chunk goes first, to avoid some fragmentation) - jlong _last_biased_lock_bulk_revocation_time; -@@ -208,6 +222,53 @@ - Array<Klass*>* secondary_supers() const { return _secondary_supers; } - void set_secondary_supers(Array<Klass*>* k) { _secondary_supers = k; } - -+ // BEGIN class redefinition utilities -+ -+ // double links between new and old version of a class -+ Klass* old_version() const { return _old_version; } -+ void set_old_version(Klass* klass) { assert(_old_version == NULL || klass == NULL, "Can only be set once!"); _old_version = klass; } -+ Klass* new_version() const { return _new_version; } -+ void set_new_version(Klass* klass) { assert(_new_version == NULL || klass == NULL, "Can only be set once!"); _new_version = klass; } -+ -+ // A subtype of this class is no longer a subtype -+ bool has_subtype_changed() const { return _subtype_changed; } -+ void set_subtype_changed(bool b) { assert(is_newest_version() || new_version()->is_newest_version(), "must be newest or second newest version"); -+ _subtype_changed = b; } -+ // state of being redefined -+ int redefinition_index() const { return _redefinition_index; } -+ void set_redefinition_index(int index) { _redefinition_index = index; } -+ void set_redefining(bool b) { _is_redefining = b; } -+ bool is_redefining() const { return _is_redefining; } -+ int redefinition_flags() const { return _redefinition_flags; } -+ bool check_redefinition_flag(int flags) const { return (_redefinition_flags & flags) != 0; } -+ void set_redefinition_flags(int flags) { _redefinition_flags = flags; } -+ void set_redefinition_flag(int flag) { _redefinition_flags |= flag; } -+ void clear_redefinition_flag(int flag) { _redefinition_flags &= ~flag; } -+ bool is_copying_backwards() const { return _is_copying_backwards; } -+ void set_copying_backwards(bool b) { _is_copying_backwards = b; } -+ -+ // update information -+ int *update_information() const { return _update_information; } -+ void set_update_information(int *info) { _update_information = info; } -+ -+ // Revision number for redefined classes, -1 for originally loaded classes -+ bool was_redefined() const { return _revision_number != -1; } -+ jint revision_number() const { return _revision_number; } -+ void set_revision_number(jint number) { _revision_number = number; } -+ -+ const Klass* oldest_version() const { return _old_version == NULL ? this : _old_version->oldest_version(); } -+ Klass* oldest_version() { return _old_version == NULL ? this : _old_version->oldest_version(); } -+ -+ const Klass* newest_version() const { return _new_version == NULL ? this : _new_version->newest_version(); } -+ Klass* newest_version() { return _new_version == NULL ? this : _new_version->newest_version(); } -+ -+ const Klass* active_version() const { return _new_version == NULL || _new_version->is_redefining() ? this : _new_version->active_version(); } -+ Klass* active_version() { return _new_version == NULL || _new_version->is_redefining() ? this : _new_version->active_version(); } -+ -+ bool is_newest_version() const { return _new_version == NULL; } -+ -+ // END class redefinition utilities -+ - // Return the element of the _super chain of the given depth. - // If there is no such element, return either NULL or this. - Klass* primary_super_of_depth(juint i) const { -@@ -261,6 +322,7 @@ - Klass* subklass() const; - Klass* next_sibling() const; - void append_to_sibling_list(); // add newly created receiver to superklass' subklass list -+ void remove_from_sibling_list(); // (DCEVM) remove receiver from sibling list - - void set_next_link(Klass* k) { _next_link = k; } - Klass* next_link() const { return _next_link; } // The next klass defined by the class loader. -@@ -287,6 +349,16 @@ - void set_next_sibling(Klass* s); - - public: -+ // (DCEVM) Different class redefinition flags of code evolution. -+ enum RedefinitionFlags { -+ NoRedefinition, // This class is not redefined at all! -+ ModifyClass = 1, // There are changes to the class meta data. -+ ModifyClassSize = ModifyClass << 1, // The size of the class meta data changes. -+ ModifyInstances = ModifyClassSize << 1, // There are change to the instance format. -+ ModifyInstanceSize = ModifyInstances << 1, // The size of instances changes. -+ RemoveSuperType = ModifyInstanceSize << 1, // A super type of this class is removed. -+ MarkedAsAffected = RemoveSuperType << 1 // This class has been marked as an affected class. -+ }; - - // Compiler support - static ByteSize super_offset() { return in_ByteSize(offset_of(Klass, _super)); } -diff -r 8a6717910608 src/share/vm/oops/klassVtable.cpp ---- a/src/share/vm/oops/klassVtable.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/klassVtable.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -1409,6 +1409,8 @@ - - void klassVtable::verify_against(outputStream* st, klassVtable* vt, int index) { - vtableEntry* vte = &vt->table()[index]; -+ // (DCEVM) FIXME-isd: do we need the following line? -+ if (vte->method() == NULL || table()[index].method() == NULL) return; - if (vte->method()->name() != table()[index].method()->name() || - vte->method()->signature() != table()[index].method()->signature()) { - fatal("mismatched name/signature of vtable entries"); -@@ -1428,6 +1430,8 @@ - - void vtableEntry::verify(klassVtable* vt, outputStream* st) { - NOT_PRODUCT(FlagSetting fs(IgnoreLockingAssertions, true)); -+ // FIXME: (DCEVM) does not hold? -+ if (method() != NULL) { - assert(method() != NULL, "must have set method"); - method()->verify(); - // we sub_type, because it could be a miranda method -@@ -1435,7 +1439,9 @@ - #ifndef PRODUCT - print(); - #endif -- fatal(err_msg("vtableEntry " PTR_FORMAT ": method is from subclass", this)); -+ // (DCEVM) the following fatal does not work for old versions of classes -+ //fatal(err_msg("vtableEntry " PTR_FORMAT ": method is from subclass", this)); -+ } - } - } - -diff -r 8a6717910608 src/share/vm/oops/method.cpp ---- a/src/share/vm/oops/method.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/method.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -1185,6 +1185,8 @@ - - // Reset correct method/const method, method size, and parameter info - newm->set_constMethod(newcm); -+ newm->set_new_version(newm->new_version()); -+ newm->set_old_version(newm->old_version()); - newm->constMethod()->set_code_size(new_code_length); - newm->constMethod()->set_constMethod_size(new_const_method_size); - newm->set_method_size(new_method_size); -@@ -1788,6 +1790,10 @@ - - // Add a method id to the jmethod_ids - jmethodID Method::make_jmethod_id(ClassLoaderData* loader_data, Method* m) { -+ // FIXME: (DCEVM) ??? -+ if (m != m->newest_version()) { -+ m = m->newest_version(); -+ } - ClassLoaderData* cld = loader_data; - - if (!SafepointSynchronize::is_at_safepoint()) { -diff -r 8a6717910608 src/share/vm/oops/method.hpp ---- a/src/share/vm/oops/method.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/oops/method.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -105,6 +105,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) -+ // (DCEVM) Newer version of method available? -+ Method* _new_version; -+ Method* _old_version; -+ - #ifdef CC_INTERP - int _result_index; // C++ interpreter needs for converting results to/from stack - #endif -@@ -175,6 +179,23 @@ - int name_index() const { return constMethod()->name_index(); } - void set_name_index(int index) { constMethod()->set_name_index(index); } - -+ Method* new_version() const { return _new_version; } -+ void set_new_version(Method* m) { _new_version = m; } -+ Method* newest_version() { return (_new_version == NULL) ? this : _new_version->newest_version(); } -+ -+ Method* old_version() const { return _old_version; } -+ void set_old_version(Method* m) { -+ /*if (m == NULL) { -+ _old_version = NULL; -+ return; -+ }*/ -+ -+ assert(_old_version == NULL, "may only be set once"); -+ assert(this->code_size() == m->code_size(), "must have same code length"); -+ _old_version = m; -+ } -+ const Method* oldest_version() const { return (_old_version == NULL) ? this : _old_version->oldest_version(); } -+ - // signature - Symbol* signature() const { return constants()->symbol_at(signature_index()); } - int signature_index() const { return constMethod()->signature_index(); } -diff -r 8a6717910608 src/share/vm/prims/jni.cpp ---- a/src/share/vm/prims/jni.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/prims/jni.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -406,6 +406,7 @@ - } - Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader, - Handle(), &st, true, -+ KlassHandle(), - CHECK_NULL); - - if (TraceClassResolution && k != NULL) { -diff -r 8a6717910608 src/share/vm/prims/jvm.cpp ---- a/src/share/vm/prims/jvm.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/prims/jvm.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -904,6 +904,7 @@ - Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader, - protection_domain, &st, - verify != 0, -+ KlassHandle(), - CHECK_NULL); - - if (TraceClassResolution && k != NULL) { -diff -r 8a6717910608 src/share/vm/prims/jvmtiEnv.cpp ---- a/src/share/vm/prims/jvmtiEnv.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/prims/jvmtiEnv.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -42,6 +42,7 @@ - #include "prims/jvmtiManageCapabilities.hpp" - #include "prims/jvmtiRawMonitor.hpp" - #include "prims/jvmtiRedefineClasses.hpp" -+#include "prims/jvmtiRedefineClasses2.hpp" - #include "prims/jvmtiTagMap.hpp" - #include "prims/jvmtiThreadState.inline.hpp" - #include "prims/jvmtiUtil.hpp" -@@ -206,8 +207,10 @@ - // is_modifiable_class_ptr - pre-checked for NULL - jvmtiError - JvmtiEnv::IsModifiableClass(oop k_mirror, jboolean* is_modifiable_class_ptr) { -- *is_modifiable_class_ptr = VM_RedefineClasses::is_modifiable_class(k_mirror)? -- JNI_TRUE : JNI_FALSE; -+ bool is_modifiable_class = AllowEnhancedClassRedefinition ? -+ VM_EnhancedRedefineClasses::is_modifiable_class(k_mirror) : -+ VM_RedefineClasses::is_modifiable_class(k_mirror); -+ *is_modifiable_class_ptr = is_modifiable_class ? JNI_TRUE : JNI_FALSE; - return JVMTI_ERROR_NONE; - } /* end IsModifiableClass */ - -@@ -276,6 +279,11 @@ - } - class_definitions[index].klass = jcls; - } -+ if (AllowEnhancedClassRedefinition) { -+ VM_EnhancedRedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform); -+ VMThread::execute(&op); -+ return (op.check_error()); -+ } - VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform); - VMThread::execute(&op); - return (op.check_error()); -@@ -287,6 +295,11 @@ - jvmtiError - JvmtiEnv::RedefineClasses(jint class_count, const jvmtiClassDefinition* class_definitions) { - //TODO: add locking -+ if (AllowEnhancedClassRedefinition) { -+ VM_EnhancedRedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine); -+ VMThread::execute(&op); -+ return (op.check_error()); -+ } - VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine); - VMThread::execute(&op); - return (op.check_error()); -diff -r 8a6717910608 src/share/vm/prims/jvmtiExport.hpp ---- a/src/share/vm/prims/jvmtiExport.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/prims/jvmtiExport.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -188,6 +188,7 @@ - // systems as needed to relax invariant checks. - static bool _has_redefined_a_class; - friend class VM_RedefineClasses; -+ friend class VM_EnhancedRedefineClasses; - inline static void set_has_redefined_a_class() { - JVMTI_ONLY(_has_redefined_a_class = true;) - } -diff -r 8a6717910608 src/share/vm/prims/jvmtiImpl.cpp ---- a/src/share/vm/prims/jvmtiImpl.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/prims/jvmtiImpl.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -289,6 +289,11 @@ - Symbol* m_name = _method->name(); - Symbol* m_signature = _method->signature(); - -+ // (DCEVM) Go through old versions of method -+ for (Method* m = _method->old_version(); m != NULL; m = m->old_version()) { -+ (m->*meth_act)(_bci); -+ } -+ - // search previous versions if they exist - PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh()); - for (PreviousVersionNode * pv_node = pvw.next_previous_version(); -diff -r 8a6717910608 src/share/vm/prims/jvmtiRedefineClasses2.cpp ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/src/share/vm/prims/jvmtiRedefineClasses2.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -0,0 +1,2034 @@ -+/* -+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. -+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -+ * -+ * This code is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 only, as -+ * published by the Free Software Foundation. -+ * -+ * This code is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * version 2 for more details (a copy is included in the LICENSE file that -+ * accompanied this code). -+ * -+ * You should have received a copy of the GNU General Public License version -+ * 2 along with this work; if not, write to the Free Software Foundation, -+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -+ * or visit www.oracle.com if you need additional information or have any -+ * questions. -+ * -+ */ -+ -+#include "precompiled.hpp" -+#include "classfile/systemDictionary.hpp" -+#include "classfile/verifier.hpp" -+#include "code/codeCache.hpp" -+#include "interpreter/oopMapCache.hpp" -+#include "interpreter/rewriter.hpp" -+#include "memory/gcLocker.hpp" -+#include "memory/universe.inline.hpp" -+#include "memory/metaspaceShared.hpp" -+#include "oops/fieldStreams.hpp" -+#include "oops/klassVtable.hpp" -+#include "prims/jvmtiImpl.hpp" -+#include "prims/jvmtiRedefineClasses2.hpp" -+#include "prims/methodComparator.hpp" -+#include "prims/jvmtiClassFileReconstituter.hpp" -+#include "runtime/deoptimization.hpp" -+#include "runtime/relocator.hpp" -+#include "utilities/bitMap.inline.hpp" -+#include "compiler/compileBroker.hpp" -+#include "oops/instanceMirrorKlass.hpp" -+#include "utilities/pair.hpp" -+ -+ -+Array<Method*>* VM_EnhancedRedefineClasses::_old_methods = NULL; -+Array<Method*>* VM_EnhancedRedefineClasses::_new_methods = NULL; -+int* VM_EnhancedRedefineClasses::_matching_old_methods = NULL; -+int* VM_EnhancedRedefineClasses::_matching_new_methods = NULL; -+int* VM_EnhancedRedefineClasses::_deleted_methods = NULL; -+int* VM_EnhancedRedefineClasses::_added_methods = NULL; -+int VM_EnhancedRedefineClasses::_matching_methods_length = 0; -+int VM_EnhancedRedefineClasses::_deleted_methods_length = 0; -+int VM_EnhancedRedefineClasses::_added_methods_length = 0; -+GrowableArray<instanceKlassHandle>* VM_EnhancedRedefineClasses::_affected_klasses = NULL; -+ -+ -+// Holds the revision number of the current class redefinition -+int VM_EnhancedRedefineClasses::_revision_number = -1; -+ -+VM_EnhancedRedefineClasses::VM_EnhancedRedefineClasses(jint class_count, const jvmtiClassDefinition *class_defs, JvmtiClassLoadKind class_load_kind) -+ : VM_GC_Operation(Universe::heap()->total_full_collections(), GCCause::_heap_inspection) { -+ RC_TIMER_START(_timer_total); -+ _class_count = class_count; -+ _class_defs = class_defs; -+ _class_load_kind = class_load_kind; -+ _result = JVMTI_ERROR_NONE; -+} -+ -+VM_EnhancedRedefineClasses::~VM_EnhancedRedefineClasses() { -+ RC_TIMER_STOP(_timer_total); -+} -+ -+void VM_EnhancedRedefineClasses::swap_all_method_annotations(ConstMethod* old_method, ConstMethod* new_method) { -+ return; // FIXME-isd: swap annotations! -+ -+ AnnotationArray* save; -+ -+ save = old_method->method_annotations(); -+ old_method->set_method_annotations(new_method->method_annotations()); -+ new_method->set_method_annotations(save); -+ -+ save = old_method->parameter_annotations(); -+ old_method->set_parameter_annotations(new_method->parameter_annotations()); -+ new_method->set_parameter_annotations(save); -+ -+ save = old_method->default_annotations(); -+ old_method->set_default_annotations(new_method->default_annotations()); -+ new_method->set_default_annotations(save); -+ -+ save = old_method->type_annotations(); -+ old_method->set_type_annotations(new_method->type_annotations()); -+ new_method->set_type_annotations(save); -+} -+ -+void VM_EnhancedRedefineClasses::add_affected_klasses( Klass* klass ) -+{ -+ assert(!_affected_klasses->contains(klass), "must not occur more than once!"); -+ assert(klass->new_version() == NULL, "Only last version is valid entry in system dictionary"); -+ -+ Klass* k = klass; -+ -+ if (k->check_redefinition_flag(Klass::MarkedAsAffected)) { -+ _affected_klasses->append(klass); -+ return; -+ } -+ -+ for (juint i = 0; i < k->super_depth(); i++) { -+ Klass* primary = k->primary_super_of_depth(i); -+ // super_depth returns "8" for interfaces, but they don't have primaries other than Object. -+ if (primary == NULL) break; -+ if (primary->check_redefinition_flag(Klass::MarkedAsAffected)) { -+ RC_TRACE(0x00000001, ("Found affected class: %s", k->name()->as_C_string())); -+ k->set_redefinition_flag(Klass::MarkedAsAffected); -+ _affected_klasses->append(klass); -+ return; -+ } -+ } -+ -+ // Check secondary supers -+ int cnt = k->secondary_supers()->length(); -+ for (int i = 0; i < cnt; i++) { -+ Klass* secondary = k->secondary_supers()->at(i); -+ if (secondary->check_redefinition_flag(Klass::MarkedAsAffected)) { -+ RC_TRACE(0x00000001, ("Found affected class: %s", k->name()->as_C_string())); -+ k->set_redefinition_flag(Klass::MarkedAsAffected); -+ _affected_klasses->append(klass); -+ return; -+ } -+ } -+} -+ -+ -+// Searches for all affected classes and performs a sorting such that a supertype is always before a subtype. -+jvmtiError VM_EnhancedRedefineClasses::find_sorted_affected_classes() { -+ -+ assert(_affected_klasses, ""); -+ for (int i = 0; i < _class_count; i++) { -+ oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass); -+ instanceKlassHandle klass_handle(Thread::current(), java_lang_Class::as_Klass(mirror)); -+ klass_handle->set_redefinition_flag(Klass::MarkedAsAffected); -+ assert(klass_handle->new_version() == NULL, "Must be new class"); -+ } -+ -+ // Find classes not directly redefined, but affected by a redefinition (because one of its supertypes is redefined) -+ SystemDictionary::classes_do(VM_EnhancedRedefineClasses::add_affected_klasses); -+ RC_TRACE(0x00000001, ("%d classes affected", _affected_klasses->length())); -+ -+ // Sort the affected klasses such that a supertype is always on a smaller array index than its subtype. -+ jvmtiError result = do_topological_class_sorting(_class_defs, _class_count, Thread::current()); -+ if (RC_TRACE_ENABLED(0x00000001)) { -+ RC_TRACE(0x00000001, ("Redefine order: ")); -+ for (int i = 0; i < _affected_klasses->length(); i++) { -+ RC_TRACE(0x00000001, ("%s", _affected_klasses->at(i)->name()->as_C_string())); -+ } -+ } -+ -+ return result; -+} -+ -+// Searches for the class bytes of the given class and returns them as a byte array. -+jvmtiError VM_EnhancedRedefineClasses::find_class_bytes(instanceKlassHandle the_class, const unsigned char **class_bytes, jint *class_byte_count, jboolean *not_changed) { -+ -+ *not_changed = false; -+ -+ // Search for the index in the redefinition array that corresponds to the current class -+ int j; -+ for (j=0; j<_class_count; j++) { -+ oop mirror = JNIHandles::resolve_non_null(_class_defs[j].klass); -+ Klass* the_class_oop = java_lang_Class::as_Klass(mirror); -+ if (the_class_oop == the_class()) { -+ break; -+ } -+ } -+ -+ if (j == _class_count) { -+ -+ *not_changed = true; -+ -+ // 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. -+ -+ if (the_class->get_cached_class_file_bytes() == NULL) { -+ // not cached, we need to reconstitute the class file from VM representation -+ constantPoolHandle constants(Thread::current(), the_class->constants()); -+ MonitorLockerEx ml(constants->lock()); // lock constant pool while we query it -+ //ObjectLocker ol(constants, Thread::current()); // lock constant pool while we query it -+ -+ JvmtiClassFileReconstituter reconstituter(the_class); -+ if (reconstituter.get_error() != JVMTI_ERROR_NONE) { -+ return reconstituter.get_error(); -+ } -+ -+ *class_byte_count = (jint)reconstituter.class_file_size(); -+ *class_bytes = (unsigned char*)reconstituter.class_file_bytes(); -+ } else { -+ -+ // it is cached, get it from the cache -+ *class_byte_count = the_class->get_cached_class_file_len(); -+ *class_bytes = the_class->get_cached_class_file_bytes(); -+ } -+ -+ } else { -+ -+ // Redefine with bytecodes at index j -+ *class_bytes = _class_defs[j].class_bytes; -+ *class_byte_count = _class_defs[j].class_byte_count; -+ } -+ -+ return JVMTI_ERROR_NONE; -+ } -+ -+// Prologue of the VM operation, called on the Java thread in parallel to normal program execution -+bool VM_EnhancedRedefineClasses::doit_prologue() { -+ -+ _revision_number++; -+ RC_TRACE(0x00000001, -+ ("Redefinition with revision number %d started!", _revision_number)); -+ -+ assert(Thread::current()->is_Java_thread(), "must be Java thread"); -+ RC_TIMER_START(_timer_prologue); -+ -+ if (!check_arguments()) { -+ RC_TIMER_STOP(_timer_prologue); -+ return false; -+ } -+ -+ // 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); -+ -+ assert(_affected_klasses == NULL, ""); -+ _affected_klasses = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<instanceKlassHandle>(_class_count, true); -+ -+ _result = load_new_class_versions(Thread::current()); -+ -+ RC_TRACE(0x00000001, -+ ("Loaded new class versions!")); -+ if (_result != JVMTI_ERROR_NONE) { -+ RC_TRACE(0x00000001, -+ ("error occured: %d!", _result)); -+ delete _new_classes; -+ _new_classes = NULL; -+ delete _affected_klasses; -+ _affected_klasses = NULL; -+ RC_TIMER_STOP(_timer_prologue); -+ return false; -+ } -+ -+ VM_GC_Operation::doit_prologue(); -+ RC_TIMER_STOP(_timer_prologue); -+ -+ RC_TRACE(0x00000001, ("doit_prologue finished!")); -+ return true; -+} -+ -+// Checks basic properties of the arguments of the redefinition command. -+jvmtiError VM_EnhancedRedefineClasses::check_arguments_error() { -+ if (_class_defs == NULL) return JVMTI_ERROR_NULL_POINTER; -+ for (int i = 0; i < _class_count; i++) { -+ if (_class_defs[i].klass == NULL) return JVMTI_ERROR_INVALID_CLASS; -+ if (_class_defs[i].class_byte_count == 0) return JVMTI_ERROR_INVALID_CLASS_FORMAT; -+ if (_class_defs[i].class_bytes == NULL) return JVMTI_ERROR_NULL_POINTER; -+ } -+ return JVMTI_ERROR_NONE; -+ } -+ -+// Returns false and sets an result error code if the redefinition should be aborted. -+bool VM_EnhancedRedefineClasses::check_arguments() { -+ jvmtiError error = check_arguments_error(); -+ if (error != JVMTI_ERROR_NONE || _class_count == 0) { -+ _result = error; -+ return false; -+ } -+ return true; -+} -+ -+jvmtiError VM_EnhancedRedefineClasses::check_exception() const { -+ Thread* THREAD = Thread::current(); -+ if (HAS_PENDING_EXCEPTION) { -+ -+ Symbol* ex_name = PENDING_EXCEPTION->klass()->name(); -+ RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("parse_stream exception: '%s'", ex_name->as_C_string())); -+ CLEAR_PENDING_EXCEPTION; -+ -+ if (ex_name == vmSymbols::java_lang_UnsupportedClassVersionError()) { -+ return JVMTI_ERROR_UNSUPPORTED_VERSION; -+ } else if (ex_name == vmSymbols::java_lang_ClassFormatError()) { -+ return JVMTI_ERROR_INVALID_CLASS_FORMAT; -+ } else if (ex_name == vmSymbols::java_lang_ClassCircularityError()) { -+ return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; -+ } else if (ex_name == vmSymbols::java_lang_NoClassDefFoundError()) { -+ // The message will be "XXX (wrong name: YYY)" -+ return JVMTI_ERROR_NAMES_DONT_MATCH; -+ } else if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { -+ return JVMTI_ERROR_OUT_OF_MEMORY; -+ } else { -+ // Just in case more exceptions can be thrown.. -+ return JVMTI_ERROR_FAILS_VERIFICATION; -+ } -+ } -+ -+ return JVMTI_ERROR_NONE; -+} -+ -+// Loads all new class versions and stores the InstanceKlass handles in an array. -+jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) { -+ -+ ResourceMark rm(THREAD); -+ -+ RC_TRACE(0x00000001, -+ ("loading new class versions (%d)", _class_count)); -+ -+ // Retrieve an array of all classes that need to be redefined -+ jvmtiError err = find_sorted_affected_classes(); -+ if (err != JVMTI_ERROR_NONE) { -+ RC_TRACE(0x00000001, -+ ("Error finding sorted affected classes: %d", (int)err)); -+ return err; -+ } -+ -+ -+ JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current()); -+ -+ _max_redefinition_flags = Klass::NoRedefinition; -+ jvmtiError result = JVMTI_ERROR_NONE; -+ -+ for (int i = 0; i < _affected_klasses->length(); i++) { -+ instanceKlassHandle the_class = _affected_klasses->at(i); -+ -+ RC_TRACE(0x00000001, -+ ("Processing affected class %s (%d of %d)", -+ the_class->name()->as_C_string(), -+ i + 1, -+ _affected_klasses->length())); -+ -+ the_class->link_class(THREAD); -+ result = check_exception(); -+ if (result != JVMTI_ERROR_NONE) break; -+ -+ // Find new class bytes -+ const unsigned char* class_bytes; -+ jint class_byte_count; -+ jvmtiError error; -+ jboolean not_changed; -+ if ((error = find_class_bytes(the_class, &class_bytes, &class_byte_count, ¬_changed)) != JVMTI_ERROR_NONE) { -+ RC_TRACE_WITH_THREAD(0x00000002, THREAD, -+ ("Error finding class bytes: %d", (int)error)); -+ result = error; -+ break; -+ } -+ assert(class_bytes != NULL && class_byte_count != 0, "Class bytes defined at this point!"); -+ -+ -+ // Set redefined class handle in JvmtiThreadState class. -+ // This redefined class is sent to agent event handler for class file -+ // load hook event. -+ state->set_class_being_redefined(&the_class, _class_load_kind); -+ -+ RC_TIMER_STOP(_timer_prologue); -+ RC_TIMER_START(_timer_class_loading); -+ -+ // Parse the stream. -+ Handle the_class_loader(THREAD, the_class->class_loader()); -+ Handle protection_domain(THREAD, the_class->protection_domain()); -+ ClassFileStream st((u1*) class_bytes, class_byte_count, (char *)"__VM_EhnancedRedefineClasses__"); -+ -+ Klass* klass = -+ SystemDictionary::resolve_from_stream( -+ the_class->name(), -+ the_class_loader, -+ protection_domain, -+ &st, -+ true, -+ the_class, -+ THREAD); -+ instanceKlassHandle new_class(THREAD, klass); -+ -+ RC_TIMER_STOP(_timer_class_loading); -+ RC_TIMER_START(_timer_prologue); -+ -+ // Clear class_being_redefined just to be sure. -+ state->clear_class_being_redefined(); -+ -+ result = check_exception(); -+ if (result != JVMTI_ERROR_NONE) break; -+ -+ not_changed = false; -+ -+#ifdef ASSERT -+ -+ assert(new_class() != NULL, "Class could not be loaded!"); -+ assert(new_class() != the_class(), "must be different"); -+ assert(new_class->new_version() == NULL && new_class->old_version() != NULL, ""); -+ -+ -+ Array<Klass*>* k_interfaces = new_class->local_interfaces(); -+ for (int j = 0; j < k_interfaces->length(); j++) { -+ assert(k_interfaces->at(j)->is_newest_version(), "just checking"); -+ } -+ -+ if (!THREAD->is_Compiler_thread()) { -+ RC_TRACE(0x00000001, ("name=%s loader="INTPTR_FORMAT" protection_domain="INTPTR_FORMAT, -+ the_class->name()->as_C_string(), -+ (intptr_t) (oopDesc*) the_class->class_loader(), -+ (intptr_t) (oopDesc*) the_class->protection_domain())); -+ // If we are on the compiler thread, we must not try to resolve a class. -+ Klass* systemLookup = SystemDictionary::resolve_or_null(the_class->name(), the_class->class_loader(), the_class->protection_domain(), THREAD); -+ -+ if (systemLookup != NULL) { -+ assert(systemLookup == new_class->old_version(), "Old class must be in system dictionary!"); -+ Klass *subklass = new_class()->subklass(); -+ 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; -+ } -+ } -+ -+#endif -+ -+ if (RC_TRACE_ENABLED(0x00000001)) { -+ if (new_class->layout_helper() != the_class->layout_helper()) { -+ RC_TRACE(0x00000001, -+ ("Instance size change for class %s: new=%d old=%d", -+ new_class->name()->as_C_string(), -+ new_class->layout_helper(), -+ the_class->layout_helper())); -+ } -+ } -+ -+ // Set the new version of the class -+ new_class->set_revision_number(_revision_number); -+ new_class->set_redefinition_index(i); -+ the_class->set_new_version(new_class()); -+ _new_classes->append(new_class); -+ -+ assert(new_class->new_version() == NULL, ""); -+ -+ int redefinition_flags = Klass::NoRedefinition; -+ -+ if (not_changed) { -+ redefinition_flags = Klass::NoRedefinition; -+ } else { -+ redefinition_flags = calculate_redefinition_flags(new_class); -+ if (redefinition_flags >= Klass::RemoveSuperType) { -+ result = JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; -+ break; -+ } -+ } -+ -+ if (new_class->super() != NULL) { -+ redefinition_flags = redefinition_flags | new_class->super()->redefinition_flags(); -+ } -+ -+ for (int j = 0; j<new_class->local_interfaces()->length(); j++) { -+ redefinition_flags = redefinition_flags | (new_class->local_interfaces()->at(j))->redefinition_flags(); -+ } -+ -+ new_class->set_redefinition_flags(redefinition_flags); -+ -+ _max_redefinition_flags = _max_redefinition_flags | redefinition_flags; -+ -+ if ((redefinition_flags & Klass::ModifyInstances) != 0) { -+ // TODO: Check if watch access flags of static fields are updated correctly. -+ calculate_instance_update_information(_new_classes->at(i)()); -+ } else { -+ // Fields were not changed, transfer special flags only -+ assert(new_class->layout_helper() >> 1 == new_class->old_version()->layout_helper() >> 1, "must be equal"); -+ assert(new_class->fields()->length() == InstanceKlass::cast(new_class->old_version())->fields()->length(), "must be equal"); -+ -+ JavaFieldStream old_fs(the_class); -+ JavaFieldStream new_fs(new_class); -+ for (; !old_fs.done() && !new_fs.done(); old_fs.next(), new_fs.next()) { -+ AccessFlags flags = new_fs.access_flags(); -+ 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); -+ } -+ } -+ -+ if (RC_TRACE_ENABLED(0x00000001)) { -+ RC_TRACE(0x00000001, -+ ("Super class is %s", new_class->super()->name()->as_C_string())); -+ } -+ -+#ifdef ASSERT -+ assert(new_class->super() == NULL || new_class->super()->new_version() == NULL, "Super klass must be newest version!"); -+ -+ the_class->vtable()->verify(tty); -+ new_class->vtable()->verify(tty); -+#endif -+ -+ if (i == _affected_klasses->length() - 1) { -+ // This was the last class processed => check if additional classes have been loaded in the meantime -+ for (int j = 0; j<_affected_klasses->length(); j++) { -+ -+ Klass* initial_klass = _affected_klasses->at(j)(); -+ Klass *initial_subklass = initial_klass->subklass(); -+ Klass *cur_klass = initial_subklass; -+ while(cur_klass != NULL) { -+ -+ if(cur_klass->oop_is_instance() && cur_klass->is_newest_version() && !cur_klass->is_redefining()) { -+ instanceKlassHandle handle(THREAD, cur_klass); -+ if (!_affected_klasses->contains(handle)) { -+ -+ int k = i + 1; -+ for (; k<_affected_klasses->length(); k++) { -+ if (_affected_klasses->at(k)->is_subtype_of(cur_klass)) { -+ break; -+ } -+ } -+ _affected_klasses->insert_before(k, handle); -+ RC_TRACE(0x00000001, -+ ("Adding newly loaded class to affected classes: %s", cur_klass->name()->as_C_string())); -+ } -+ } -+ -+ cur_klass = cur_klass->next_sibling(); -+ } -+ } -+ -+ int new_count = _affected_klasses->length() - 1 - i; -+ if (new_count != 0) { -+ RC_TRACE(0x00000001, -+ ("Found new number of affected classes: %d", new_count)); -+ } -+ } -+ } -+ -+ if (result != JVMTI_ERROR_NONE) { -+ rollback(); -+ return result; -+ } -+ -+ 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()); -+ -+ RC_TRACE(0x00000001, -+ ("Linking class %d/%d %s", i, _affected_klasses->length(), the_class->name()->as_C_string())); -+ new_class->link_class(THREAD); -+ -+ result = check_exception(); -+ if (result != JVMTI_ERROR_NONE) break; -+ } -+ RC_TIMER_STOP(_timer_class_linking); -+ RC_TIMER_START(_timer_prologue); -+ -+ if (result != JVMTI_ERROR_NONE) { -+ rollback(); -+ return result; -+ } -+ -+ RC_TRACE(0x00000001, ("All classes loaded!")); -+ -+#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()->new_version() == NULL)) { -+ new_version()->print(); -+ new_version->super()->print(); -+ } -+ assert(new_version->super() == NULL || new_version->super()->new_version() == NULL, "Super class must be newest version"); -+ } -+ -+ SystemDictionary::classes_do(check_class, THREAD); -+ -+#endif -+ -+ RC_TRACE(0x00000001, ("Finished verification!")); -+ return JVMTI_ERROR_NONE; -+} -+ -+int VM_EnhancedRedefineClasses::calculate_redefinition_flags(instanceKlassHandle new_class) { -+ -+ int result = Klass::NoRedefinition; -+ RC_TRACE(0x00000001, -+ ("Comparing different class versions of class %s", new_class->name()->as_C_string())); -+ -+ assert(new_class->old_version() != NULL, "must have old version"); -+ instanceKlassHandle the_class(new_class->old_version()); -+ -+ // Check whether class is in the error init state. -+ 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); -+ } -+ -+ int i; -+ -+ ////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ // Check superclasses -+ assert(new_class->super() == NULL || new_class->super()->is_newest_version(), ""); -+ if (the_class->super() != new_class->super()) { -+ // Super class changed -+ Klass* cur_klass = the_class->super(); -+ while (cur_klass != NULL) { -+ if (!new_class->is_subclass_of(cur_klass->newest_version())) { -+ RC_TRACE(0x00000001, -+ ("Removed super class %s", cur_klass->name()->as_C_string())); -+ result = result | Klass::RemoveSuperType | Klass::ModifyInstances | Klass::ModifyClass; -+ -+ if (!cur_klass->has_subtype_changed()) { -+ RC_TRACE(0x00000001, -+ ("Subtype changed of class %s", cur_klass->name()->as_C_string())); -+ cur_klass->set_subtype_changed(true); -+ } -+ } -+ -+ cur_klass = cur_klass->super(); -+ } -+ -+ cur_klass = new_class->super(); -+ while (cur_klass != NULL) { -+ if (!the_class->is_subclass_of(cur_klass->old_version())) { -+ RC_TRACE(0x00000001, -+ ("Added super class %s", cur_klass->name()->as_C_string())); -+ result = result | Klass::ModifyClass | Klass::ModifyInstances; -+ } -+ cur_klass = cur_klass->super(); -+ } -+ } -+ -+ ////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ // Check interfaces -+ -+ // Interfaces removed? -+ Array<Klass*>* old_interfaces = the_class->transitive_interfaces(); -+ for (i = 0; i<old_interfaces->length(); i++) { -+ instanceKlassHandle old_interface(old_interfaces->at(i)); -+ if (!new_class->implements_interface_any_version(old_interface())) { -+ result = result | Klass::RemoveSuperType | Klass::ModifyClass; -+ RC_TRACE(0x00000001, -+ ("Removed interface %s", old_interface->name()->as_C_string())); -+ -+ if (!old_interface->has_subtype_changed()) { -+ RC_TRACE(0x00000001, -+ ("Subtype changed of interface %s", old_interface->name()->as_C_string())); -+ old_interface->set_subtype_changed(true); -+ } -+ } -+ } -+ -+ // Interfaces added? -+ Array<Klass*>* new_interfaces = new_class->transitive_interfaces(); -+ for (i = 0; i<new_interfaces->length(); i++) { -+ if (!the_class->implements_interface_any_version(new_interfaces->at(i))) { -+ result = result | Klass::ModifyClass; -+ RC_TRACE(0x00000001, -+ ("Added interface %s", new_interfaces->at(i)->name()->as_C_string())); -+ } -+ } -+ -+ -+ // Check whether class modifiers are the same. -+ jushort old_flags = (jushort) the_class->access_flags().get_flags(); -+ jushort new_flags = (jushort) new_class->access_flags().get_flags(); -+ if (old_flags != new_flags) { -+ // TODO Can this have any effects? -+ } -+ -+ // Check if the number, names, types and order of fields declared in these classes -+ // are the same. -+ JavaFieldStream old_fs(the_class); -+ JavaFieldStream new_fs(new_class); -+ for (; !old_fs.done() && !new_fs.done(); old_fs.next(), new_fs.next()) { -+ // access -+ old_flags = old_fs.access_flags().as_short(); -+ new_flags = new_fs.access_flags().as_short(); -+ if ((old_flags ^ new_flags) & JVM_RECOGNIZED_FIELD_MODIFIERS) { -+ // TODO can this have any effect? -+ } -+ // offset -+ if (old_fs.offset() != new_fs.offset()) { -+ result = result | Klass::ModifyInstances; -+ } -+ // name and signature -+ Symbol* name_sym1 = the_class->constants()->symbol_at(old_fs.name_index()); -+ Symbol* sig_sym1 = the_class->constants()->symbol_at(old_fs.signature_index()); -+ Symbol* name_sym2 = new_class->constants()->symbol_at(new_fs.name_index()); -+ 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()) { -+ result = result | Klass::ModifyInstances; -+ } -+ -+ // 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. -+ Array<Method*>* k_old_methods(the_class->methods()); // FIXME-isd: handles??? -+ Array<Method*>* k_new_methods(new_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) { -+ Method* k_old_method; -+ Method* 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 = k_new_methods->at(ni); -+ method_was = added; -+ } else if (ni >= n_new_methods) { -+ // Old method, at the end, is deleted -+ k_old_method = k_old_methods->at(oi); -+ method_was = deleted; -+ } else { -+ // There are more methods in both the old and new lists -+ k_old_method = k_old_methods->at(oi); -+ k_new_method = k_new_methods->at(ni); -+ if (k_old_method->name() != k_new_method->name()) { -+ // Methods are sorted by method name, so a mismatch means added -+ // or deleted -+ 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++) { -+ Method* m = k_new_methods->at(nj); -+ if (k_old_method->name() != m->name()) { -+ // reached another method name so no more overloaded methods -+ method_was = deleted; -+ break; -+ } -+ if (k_old_method->signature() == m->signature()) { -+ // found a match so swap the methods -+ k_new_methods->at_put(ni, m); -+ k_new_methods->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)) { -+ // TODO 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) { -+ Method* 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); -+ RC_TRACE(0x00008000, -+ ("swapping idnum of new and old method %d / %d!", new_num, old_num); -+ swap_all_method_annotations(k_old_method->constMethod(), k_new_method->constMethod())); -+ } -+ } -+ 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 -+ result = result | Klass::ModifyClass; -+ } -+ { -+ u2 num = the_class->next_method_idnum(); -+ if (num == ConstMethod::UNSET_IDNUM) { -+ // cannot add any more methods -+ result = result | Klass::ModifyClass; -+ } -+ u2 new_num = k_new_method->method_idnum(); -+ Method* 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(k_old_method->constMethod(), k_new_method->constMethod()); -+ } -+ 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 -+ result = result | Klass::ModifyClass; -+ } -+ 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(); -+ } -+ } -+ -+ if (new_class()->size() != new_class->old_version()->size()) { -+ result |= Klass::ModifyClassSize; -+ } -+ -+ if (new_class->size_helper() != ((InstanceKlass*)(new_class->old_version()))->size_helper()) { -+ result |= Klass::ModifyInstanceSize; -+ } -+ -+ // TODO Check method bodies to be able to return NoChange? -+ return result; -+} -+ -+void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* 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; -+ } -+ -+ 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; -+ } -+ -+ 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 { -+ // New field, fill -+ fill(type2aelembytes(fd->field_type())); -+ } -+ } -+ -+ 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; -+ } -+ -+ 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 (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->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 (RC_TRACE_ENABLED(0x00000001)) { -+ RC_TRACE(0x00000001, ("Instance update information for %s:", new_version->name()->as_C_string())); -+ if (cl.does_copy_backwards()) { -+ RC_TRACE(0x00000001, ("\tDoes copy backwards!")); -+ } -+ for (int i=0; i<result.length(); i++) { -+ int curNum = result.at(i); -+ if (curNum < 0) { -+ RC_TRACE(0x00000001, ("\t%d CLEAN", curNum)); -+ } else if (curNum > 0) { -+ RC_TRACE(0x00000001, ("\t%d COPY from %d", curNum, result.at(i + 1))); -+ i++; -+ } else { -+ RC_TRACE(0x00000001, ("\tEND")); -+ } -+ } -+ } -+} -+ -+void VM_EnhancedRedefineClasses::rollback() { -+ RC_TRACE(0x00000001, ("Rolling back redefinition!")); -+ SystemDictionary::rollback_redefinition(); -+ -+ 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()->set_new_version(NULL); -+ new_class->set_old_version(NULL); -+ } -+ -+} -+ -+void VM_EnhancedRedefineClasses::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()) { -+ RC_TRACE(0x00000001, ("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()) { -+ Klass* klass = java_lang_Class::as_Klass(oop); -+ if (klass != NULL && klass->oop_is_instance()) { -+ assert(oop == InstanceKlass::cast(klass)->java_mirror(), "just checking"); -+ if (klass->new_version() != NULL) { -+ oop = InstanceKlass::cast(klass->new_version())->java_mirror(); -+ cur_oop->obj_field_put(fd->offset(), oop); -+ } -+ } -+ } -+ } -+ } -+ } -+}; -+ -+void VM_EnhancedRedefineClasses::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 ExtendedOopClosure { -+ // 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_instanceMirror()) { -+ Klass* klass = java_lang_Class::as_Klass(oop); -+ if (klass != NULL && klass->oop_is_instance()) { -+ assert(oop == InstanceKlass::cast(klass)->java_mirror(), "just checking"); -+ if (klass->new_version() != NULL) { -+ oop = InstanceKlass::cast(klass->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_EnhancedRedefineClasses::doit() { -+ -+ Thread *thread = Thread::current(); -+ -+ 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 (!MetaspaceShared::remap_shared_readonly_as_readwrite()) { -+ RC_TRACE(0x00000001, -+ ("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(), (Klass*)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: -+ -+ OopClosure *_closure; -+ bool _needs_instance_update; -+ oop _tmp_obj; -+ int _tmp_obj_size; -+ -+ public: -+ ChangePointersObjectClosure(OopClosure *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) { -+ // FIXME: 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_no_header(_closure); -+ } -+ -+ if (obj->klass()->new_version() != NULL) { -+ Klass* new_klass = obj->klass()->new_version(); -+ /* FIXME: 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(obj->klass()->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(obj->klass()->new_version()); -+ } -+ } -+ } -+ }; -+ -+ ChangePointersOopClosure<StoreNoBarrier> oopClosureNoBarrier; -+ ChangePointersOopClosure<StoreBarrier> oopClosure; -+ ChangePointersObjectClosure objectClosure(&oopClosure); -+ -+ RC_TRACE(0x00000001, ("Before updating instances")); -+ { -+ // 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); -+ } -+ RC_TRACE(0x00000001, ("After updating instances")); -+ -+ for (int i = 0; i < _new_classes->length(); i++) { -+ InstanceKlass* cur = InstanceKlass::cast(_new_classes->at(i)()); -+ InstanceKlass* old = InstanceKlass::cast(cur->old_version()); -+ -+ // Swap marks to have same hashcodes -+ markOop cur_mark = cur->prototype_header(); -+ markOop old_mark = old->prototype_header(); -+ cur->set_prototype_header(old_mark); -+ old->set_prototype_header(cur_mark); -+ -+ //swap_marks(cur, old); -+ 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); -+ -+ Klass* array_klasses = old->array_klasses(); -+ if (array_klasses != NULL) { -+ assert(cur->array_klasses() == NULL, "just checking"); -+ -+ // Transfer the array classes, otherwise we might get cast exceptions when casting array types. -+ // Also, set array klasses element klass. -+ cur->set_array_klasses(array_klasses); -+ ObjArrayKlass::cast(array_klasses)->set_element_klass(cur); -+ } -+ -+ // 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?? -+ //java_lang_Class::set_klass(old->java_mirror(), cur); // FIXME-isd: is that correct? -+ //FIXME-isd: do we need this: ??? 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); -+ } -+ } -+ -+ RC_TIMER_STOP(_timer_heap_iteration); -+ RC_TIMER_START(_timer_redefinition); -+ if (objectClosure.needs_instance_update()) { -+ // Do a full garbage collection to update the instance sizes accordingly -+ RC_TRACE(0x00000001, ("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); -+ RC_TRACE(0x00000001, ("GC done!")); -+ } -+ -+ // Unmark Klass*s as "redefining" -+ for (int i=0; i<_new_classes->length(); i++) { -+ Klass* cur_klass = _new_classes->at(i)(); -+ InstanceKlass* cur = (InstanceKlass*)cur_klass; -+ 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_metadata(); -+ -+#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_EnhancedRedefineClasses::doit_epilogue() { -+ -+ RC_TIMER_START(_timer_vm_op_epilogue); -+ -+ ResourceMark mark; -+ -+ VM_GC_Operation::doit_epilogue(); -+ RC_TRACE(0x00000001, ("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; -+ -+ RC_TRACE(0x00000001, ("Redefinition finished!")); -+ -+ RC_TIMER_STOP(_timer_vm_op_epilogue); -+} -+ -+bool VM_EnhancedRedefineClasses::is_modifiable_class(oop klass_mirror) { -+ // classes for primitives cannot be redefined -+ if (java_lang_Class::is_primitive(klass_mirror)) { -+ return false; -+ } -+ Klass* klass = java_lang_Class::as_Klass(klass_mirror); -+ // classes for arrays cannot be redefined -+ if (klass == NULL || !klass->oop_is_instance()) { -+ return false; -+ } -+ return true; -+} -+ -+#ifdef ASSERT -+ -+void VM_EnhancedRedefineClasses::verify_classes(Klass* k_oop_latest, oop initiating_loader, TRAPS) { -+ Klass* k_oop = k_oop_latest; -+ while (k_oop != NULL) { -+ -+ instanceKlassHandle k_handle(THREAD, k_oop); -+ Verifier::verify(k_handle, Verifier::ThrowException, true, THREAD); -+ k_oop = k_oop->old_version(); -+ } -+} -+ -+#endif -+ -+// 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_EnhancedRedefineClasses::unpatch_bytecode(Method* 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; -+ } -+ } -+ -+ // 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); -+ } -+ } -+ } -+ -+// 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_EnhancedRedefineClasses::adjust_cpool_cache(Klass* klass_latest, TRAPS) { -+ Klass* k = klass_latest; -+ while (k != NULL) { -+ if (k->oop_is_instance()) { -+ HandleMark hm(THREAD); -+ InstanceKlass *ik = InstanceKlass::cast(k); -+ -+ constantPoolHandle other_cp; -+ ConstantPoolCache* cp_cache; -+ other_cp = constantPoolHandle(ik->constants()); -+ -+ for (int i = 0; i < other_cp->length(); i++) { -+ if (other_cp->tag_at(i).is_klass()) { -+ Klass* klass = other_cp->klass_at(i, THREAD); -+ if (klass->new_version() != NULL) { -+ // (DCEVM) TODO: check why/if this is necessary -+ other_cp->klass_at_put(i, klass->new_version()); -+ } -+ klass = other_cp->klass_at(i, THREAD); -+ assert(klass->new_version() == NULL, "Must be new klass!"); -+ } -+ } -+ -+ cp_cache = other_cp->cache(); -+ -+ if (cp_cache != NULL) { -+ cp_cache->clear_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 = k->old_version(); -+ } -+} -+ -+void VM_EnhancedRedefineClasses::update_jmethod_ids() { -+ for (int j = 0; j < _matching_methods_length; ++j) { -+ Method* old_method = _old_methods->at(_matching_old_methods[j]); -+ jmethodID jmid = old_method->find_jmethod_id_or_null(); -+ RC_TRACE(0x00008000, ("matching method %s, jmid %d", old_method->name_and_sig_as_C_string(), jmid)); -+ if (old_method->new_version() != NULL && jmid == NULL) { -+ // (DCEVM) 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(_new_methods->at(_matching_new_methods[j])); -+ if (old_method->new_version() == NULL) { -+ methodHandle old_method_h(_old_methods->at(_matching_old_methods[j])); -+ jmethodID new_jmethod_id = Method::make_jmethod_id(old_method_h->method_holder()->class_loader_data(), old_method_h()); -+ bool result = InstanceKlass::cast(old_method_h->method_holder())->update_jmethod_id(old_method_h(), new_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); -+ } -+ Method::change_method_associated_with_jmethod_id(jmid, new_method_h()); -+ assert(Method::resolve_jmethod_id(jmid) == _new_methods->at(_matching_new_methods[j]), "should be replaced"); -+ jmethodID mid = (_new_methods->at(_matching_new_methods[j]))->jmethod_id(); -+ //assert(JNIHandles::resolve_non_null((jobject)mid) == new_method_h(), "must match!"); -+ } -+ } -+} -+ -+ -+// 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_EnhancedRedefineClasses::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_EnhancedRedefineClasses::compute_added_deleted_matching_methods() { -+ Method* old_method; -+ Method* 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 = _new_methods->at(nj); -+ _added_methods[_added_methods_length++] = nj; -+ ++nj; -+ } else if (nj >= _new_methods->length()) { -+ // Old method, at the end, is deleted -+ old_method = _old_methods->at(oj); -+ _deleted_methods[_deleted_methods_length++] = oj; -+ ++oj; -+ } else { -+ old_method = _old_methods->at(oj); -+ new_method = _new_methods->at(nj); -+ if (old_method->name() == new_method->name()) { -+ if (old_method->signature() == new_method->signature()) { -+ _matching_old_methods[_matching_methods_length] = oj;//old_method; -+ _matching_new_methods[_matching_methods_length] = nj;//new_method; -+ _matching_methods_length++; -+ ++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"); -+ RC_TRACE(0x00008000, ("Matching methods = %d / deleted methods = %d / added methods = %d", -+ _matching_methods_length, _deleted_methods_length, _added_methods_length)); -+} -+ -+ -+ -+// 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_EnhancedRedefineClasses::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()->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 -+ -+ /* FIXME -+ 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 -+ -+ // 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); -+ -+ -+ // JSR-292 support -+ -+ // Transfer method handles -+ MemberNameTable* mnt = the_old_class->member_names(); -+ the_new_class->set_member_names(mnt); -+ the_old_class->set_member_names(NULL); -+ if (mnt != NULL) { -+ for (int i = 0; i < mnt->length(); i++) { -+ oop mem_name = mnt->get_member_name(i); -+ if (mem_name != NULL) { -+ Method* method = (Method*) java_lang_invoke_MemberName::vmtarget(mem_name); -+ -+ // Replace the method with matching one from the new class -+ Method* new_method = the_new_class->find_method(method->name(), method->signature()); -+ java_lang_invoke_MemberName::set_vmtarget(mem_name, new_method); -+ } -+ } -+ } -+ -+ -+#ifdef ASSERT -+ -+// Klass* 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(); -+ -+// Klass* 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()->new_version() == the_new_class(), "Must equal"); -+ -+ for (int i=0; i<the_new_class->methods()->length(); i++) { -+ assert((the_new_class->methods()->at(i))->method_holder() == the_new_class(), "method holder must match!"); -+ } -+ -+ // FIXME: -+ //_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(), THREAD); -+ -+} -+ -+ -+void VM_EnhancedRedefineClasses::check_methods_and_mark_as_obsolete(BitMap *emcp_methods, int * emcp_method_count_p) { -+ RC_TRACE(0x00000100, ("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) { -+ Method* old_method = _old_methods->at(_matching_old_methods[j]); -+ Method* new_method = _new_methods->at(_matching_new_methods[j]); -+ Method* old_array_method; -+ -+ // Maintain an old_index into the _old_methods array by skipping -+ // deleted methods -+ while ((old_array_method = _old_methods->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); -+ -+ RC_TRACE(0x00000100, ("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()) { -+ RC_TRACE(0x00000100, ("Checking breakpoint: %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"); -+ RC_TRACE(0x00000100, ("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. -+ RC_TRACE(0x00000100, ("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) { -+ Method* old_method = _old_methods->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; -+ // 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 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"); -+ RC_TRACE(0x00000100, ("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_EnhancedRedefineClasses::increment_class_counter(Klass* klass, TRAPS) { -+ oop class_mirror = klass->java_mirror(); -+ int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1; -+ java_lang_Class::set_classRedefinedCount(class_mirror, new_count); -+ RC_TRACE(0x00000008, ("updated count for class=%s to %d", klass->external_name(), new_count)); -+} -+ -+#ifndef PRODUCT -+void VM_EnhancedRedefineClasses::check_class(Klass* k_oop, TRAPS) { -+ Klass *k = k_oop; -+ 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); -+ assert(ik->vtable()->check_no_old_or_obsolete_entries(), "old method found"); -+ ik->vtable()->verify(tty, true); -+ } -+ } -+} -+ -+#endif -+ -+static bool match_second(void* value, Pair<Klass*, Klass*> elem) { -+ return elem.second == value; -+} -+ -+jvmtiError VM_EnhancedRedefineClasses::do_topological_class_sorting( const jvmtiClassDefinition *class_defs, int class_count, TRAPS) { -+ ResourceMark mark(THREAD); -+ GrowableArray<Pair<Klass*, Klass*> > 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_Klass(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_EnhancedRedefineClasses__"); -+ ClassFileParser cfp(&st); -+ -+ -+ -+ TempNewSymbol parsed_name; -+ GrowableArray<Symbol*>* super_symbols = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Symbol*>(0, true); -+ cfp.parseClassFile(the_class->name(), -+ the_class->class_loader_data(), -+ protection_domain, -+ the_class, KlassHandle(), -+ NULL, -+ super_symbols, -+ parsed_name, -+ false, -+ THREAD); -+ -+ for (int j = 0; j < super_symbols->length(); j++) { -+ Symbol* sym = super_symbols->at(j); -+ Klass* 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)) { -+ links.append(Pair<Klass*, Klass*>(super_klass, the_class())); -+ } -+ } -+ } -+ delete super_symbols; -+ -+ assert(the_class->check_redefinition_flag(Klass::MarkedAsAffected), ""); -+ the_class->clear_redefinition_flag(Klass::MarkedAsAffected); -+ } -+ -+ 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); -+ Klass* superKlass = klass->super(); -+ if (_affected_klasses->contains(superKlass)) { -+ links.append(Pair<Klass*, Klass*>(superKlass, klass())); -+ } -+ -+ Array<Klass*>* superInterfaces = klass->local_interfaces(); -+ for (int j=0; j<superInterfaces->length(); j++) { -+ Klass* interfaceKlass = superInterfaces->at(j); -+ if (_affected_klasses->contains(interfaceKlass)) { -+ links.append(Pair<Klass*, Klass*>(interfaceKlass, klass())); -+ } -+ } -+ } -+ } -+ -+ 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 -+ Klass* oop = _affected_klasses->at(j)(); -+ int k = links.find(oop, match_second); -+ if (k == -1) break; -+ } -+ if (j == _affected_klasses->length()) { -+ return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; -+ } -+ -+ // Remove all links from this node -+ Klass* oop = _affected_klasses->at(j)(); -+ int k = 0; -+ while (k < links.length()) { -+ if (links.adr_at(k)->first == 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_EnhancedRedefineClasses 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,...) -+ Method* 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) { -+ Method* method = the_class()->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(Method* 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. -+ Method* strip_and_search_for_new_native(Method* method) { -+ ResourceMark rm; -+ char* name_str = method_name_without_prefixes(method); -+ return search_prefix_name_space(0, name_str, strlen(name_str), -+ 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++) { -+ Method* old_method = old_klass->methods()->at(old_methods[j]); -+ -+ if (old_method->is_native() && old_method->has_native_function()) { -+ Method* new_method = strip_and_search_for_new_native(old_method); -+ if (new_method != NULL) { -+ // Actually set the native function in the new method. -+ // Redefine does not send events (except CFLH), certainly not this -+ // behind the scenes re-registration. -+ new_method->set_native_function(old_method->native_function(), -+ !Method::native_bind_event_is_interesting); -+ } -+ } -+ } -+ } -+}; -+ -+// Don't lose the association between a native method and its JNI function. -+void VM_EnhancedRedefineClasses::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 -r 8a6717910608 src/share/vm/prims/jvmtiRedefineClasses2.hpp ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/src/share/vm/prims/jvmtiRedefineClasses2.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -0,0 +1,156 @@ -+/* -+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. -+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -+ * -+ * This code is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 only, as -+ * published by the Free Software Foundation. -+ * -+ * This code is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * version 2 for more details (a copy is included in the LICENSE file that -+ * accompanied this code). -+ * -+ * You should have received a copy of the GNU General Public License version -+ * 2 along with this work; if not, write to the Free Software Foundation, -+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -+ * or visit www.oracle.com if you need additional information or have any -+ * questions. -+ * -+ */ -+ -+#ifndef SHARE_VM_PRIMS_JVMTIENHANCEDREDEFINECLASSES_HPP -+#define SHARE_VM_PRIMS_JVMTIENHANCEDREDEFINECLASSES_HPP -+ -+#include "jvmtifiles/jvmtiEnv.hpp" -+#include "memory/oopFactory.hpp" -+#include "memory/resourceArea.hpp" -+#include "oops/objArrayKlass.hpp" -+#include "oops/objArrayOop.hpp" -+#include "oops/fieldStreams.hpp" -+#include "prims/jvmtiRedefineClassesTrace.hpp" -+#include "gc_implementation/shared/vmGCOperations.hpp" -+ -+// New version that allows arbitrary changes to already loaded classes. -+class VM_EnhancedRedefineClasses: public VM_GC_Operation { -+ private: -+ -+ // These static fields are needed by SystemDictionary::classes_do() -+ // facility and the adjust_cpool_cache_and_vtable() helper: -+ static Array<Method*>* _old_methods; -+ static Array<Method*>* _new_methods; -+ static int* _matching_old_methods; -+ static int* _matching_new_methods; -+ static int* _deleted_methods; -+ static int* _added_methods; -+ static int _matching_methods_length; -+ static int _deleted_methods_length; -+ static int _added_methods_length; -+ -+ static int _revision_number; -+ -+ static GrowableArray<instanceKlassHandle>* _affected_klasses; -+ -+ // The instance fields are used to pass information from -+ // doit_prologue() to doit() and doit_epilogue(). -+ jint _class_count; -+ const jvmtiClassDefinition *_class_defs; // ptr to _class_count defs -+ -+ // This operation is used by both RedefineClasses and -+ // RetransformClasses. Indicate which. -+ JvmtiClassLoadKind _class_load_kind; -+ -+ GrowableArray<instanceKlassHandle>* _new_classes; -+ jvmtiError _result; -+ int _max_redefinition_flags; -+ -+ // Performance measurement support. These timers do not cover all -+ // the work done for JVM/TI RedefineClasses() but they do cover -+ // the heavy lifting. -+ elapsedTimer _timer_total; -+ elapsedTimer _timer_prologue; -+ elapsedTimer _timer_class_linking; -+ elapsedTimer _timer_class_loading; -+ elapsedTimer _timer_prepare_redefinition; -+ elapsedTimer _timer_heap_iteration; -+ elapsedTimer _timer_redefinition; -+ elapsedTimer _timer_vm_op_epilogue; -+ -+ jvmtiError find_sorted_affected_classes( ); -+ jvmtiError find_class_bytes(instanceKlassHandle the_class, const unsigned char **class_bytes, jint *class_byte_count, jboolean *not_changed); -+ jvmtiError load_new_class_versions(TRAPS); -+ -+ // 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(); -+ -+ // Change jmethodIDs to point to the new methods -+ void update_jmethod_ids(); -+ -+ void swap_all_method_annotations(ConstMethod* old_method, ConstMethod* new_method); -+ -+ static void add_affected_klasses( Klass* obj ); -+ -+ static jvmtiError do_topological_class_sorting(const jvmtiClassDefinition *class_definitions, int class_count, TRAPS); -+ -+ // Install the redefinition of a class -+ void redefine_single_class(instanceKlassHandle the_new_class, TRAPS); -+ -+ // Increment the classRedefinedCount field in the specific instanceKlass -+ // and in all direct and indirect subclasses. -+ void increment_class_counter(Klass* klass, TRAPS); -+ -+ -+ void flush_dependent_code(instanceKlassHandle k_h, TRAPS); -+ -+ static void check_class(Klass* k_oop,/* oop initiating_loader,*/ TRAPS) PRODUCT_RETURN; -+ -+ static void adjust_cpool_cache(Klass* k_oop, TRAPS); -+ -+ static void unpatch_bytecode(Method* method); -+ -+#ifdef ASSERT -+ static void verify_classes(Klass* k_oop, oop initiating_loader, TRAPS); -+#endif -+ -+ int calculate_redefinition_flags(instanceKlassHandle new_version); -+ void calculate_instance_update_information(Klass* new_version); -+ void check_methods_and_mark_as_obsolete(BitMap *emcp_methods, int * emcp_method_count_p); -+ static void mark_as_scavengable(nmethod* nm); -+ -+ bool check_arguments(); -+ jvmtiError check_arguments_error(); -+ -+ public: -+ VM_EnhancedRedefineClasses(jint class_count, const jvmtiClassDefinition *class_defs, JvmtiClassLoadKind class_load_kind); -+ virtual ~VM_EnhancedRedefineClasses(); -+ -+ bool doit_prologue(); -+ void doit(); -+ void doit_epilogue(); -+ void rollback(); -+ -+ jvmtiError check_exception() const; -+ VMOp_Type type() const { return VMOp_RedefineClasses; } -+ bool skip_operation() const { return false; } -+ bool allow_nested_vm_operations() const { return true; } -+ jvmtiError check_error() { return _result; } -+ -+ // Modifiable test must be shared between IsModifiableClass query -+ // and redefine implementation -+ static bool is_modifiable_class(oop klass_mirror); -+ -+ // Utility methods for transfering field access flags -+ -+ static void transfer_special_access_flags(JavaFieldStream *from, JavaFieldStream *to); -+ static void transfer_special_access_flags(fieldDescriptor *from, fieldDescriptor *to); -+ -+ void transfer_old_native_function_registrations(instanceKlassHandle the_class); -+ -+ static void swap_marks(oop first, oop second); -+}; -+ -+#endif // SHARE_VM_PRIMS_JVMTIENHANCEDREDEFINECLASSES_HPP -diff -r 8a6717910608 src/share/vm/runtime/arguments.cpp ---- a/src/share/vm/runtime/arguments.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/runtime/arguments.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -59,8 +59,8 @@ - #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" - #endif // INCLUDE_ALL_GCS - --// Note: This is a special bug reporting site for the JVM --#define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp" -+// (DCEVM) The DCE VM has its own JIRA bug tracking system. -+#define DEFAULT_VENDOR_URL_BUG "https://github.com/Guidewire/DCEVM/issues" - #define DEFAULT_JAVA_LAUNCHER "generic" - - // Disable options not supported in this release, with a warning if they -@@ -1507,6 +1507,10 @@ - - void Arguments::set_ergonomics_flags() { - -+ if (AllowEnhancedClassRedefinition) { -+ // (DCEVM) enforces serial GC -+ FLAG_SET_ERGO(bool, UseSerialGC, true); -+ } - if (os::is_server_class_machine()) { - // If no other collector is requested explicitly, - // let the VM select the collector based on -@@ -1948,6 +1952,17 @@ - if (UseConcMarkSweepGC || UseParNewGC) i++; - if (UseParallelGC || UseParallelOldGC) i++; - if (UseG1GC) i++; -+ -+ if (AllowEnhancedClassRedefinition) { -+ // (DCEVM) Must use serial GC. This limitation applies because the instance size changing GC modifications -+ // are only built into the mark and compact algorithm. -+ if (!UseSerialGC && i >= 1) { -+ jio_fprintf(defaultStream::error_stream(), -+ "Must use the serial GC in the DCEVM\n"); -+ status = false; -+ } -+ } -+ - if (i > 1) { - jio_fprintf(defaultStream::error_stream(), - "Conflicting collector combinations in option list; " -diff -r 8a6717910608 src/share/vm/runtime/globals.hpp ---- a/src/share/vm/runtime/globals.hpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/runtime/globals.hpp Wed Apr 30 11:27:18 2014 -0700 -@@ -1273,6 +1273,9 @@ - product(intx, TraceRedefineClasses, 0, \ - "Trace level for JVMTI RedefineClasses") \ - \ -+ product(bool, AllowEnhancedClassRedefinition, true, \ -+ "Allow enhanced class redefinition beyond swapping method bodies")\ -+ \ - develop(bool, StressMethodComparator, false, \ - "Run the MethodComparator on all loaded methods") \ - \ -diff -r 8a6717910608 src/share/vm/runtime/reflection.cpp ---- a/src/share/vm/runtime/reflection.cpp Tue Mar 11 13:02:13 2014 -0700 -+++ b/src/share/vm/runtime/reflection.cpp Wed Apr 30 11:27:18 2014 -0700 -@@ -519,6 +519,12 @@ - AccessFlags access, - bool classloader_only, - bool protected_restriction) { -+ -+ // (DCEVM) Decide accessibility based on active version -+ if (current_class != NULL) { -+ current_class = current_class->active_version(); -+ } -+ - // 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. |