aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Dubrov <idubrov@guidewire.com>2015-07-09 23:19:55 -0700
committerIvan Dubrov <idubrov@guidewire.com>2015-07-10 10:50:54 -0700
commit3f9d18a4058fbe6958a6b7ec827af221e84f9792 (patch)
treee160fa2853c9af85b1fbcec945e7b6b32e75649b
parent4d67683d0d7a5af417efa8f0d4da7d4b34d61863 (diff)
downloaddcevm-feature/jdk7u79-support.tar.gz
dcevm-feature/jdk7u79-support.zip
Support for Java7u79feature/jdk7u79-support
-rw-r--r--build.gradle1
-rw-r--r--dcevm/src/test/java7/com/github/dcevm/test/methods/MethodHandleTest.java34
-rw-r--r--gradle.properties2
-rw-r--r--hotspot/.hg/patches/full-jdk7u79-b15-method-handles.patch328
-rw-r--r--hotspot/.hg/patches/full-jdk7u79-b15.patch (renamed from hotspot/.hg/patches/full-jdk7u79-b02.patch)4922
-rw-r--r--hotspot/.hg/patches/series5
6 files changed, 2824 insertions, 2468 deletions
diff --git a/build.gradle b/build.gradle
index de9ebce7..456ec0db 100644
--- a/build.gradle
+++ b/build.gradle
@@ -78,6 +78,7 @@ project('hotspot') {
exec {
executable 'hg'
args 'qpop', '-a'
+ ignoreExitValue = true
}
exec {
executable 'hg'
diff --git a/dcevm/src/test/java7/com/github/dcevm/test/methods/MethodHandleTest.java b/dcevm/src/test/java7/com/github/dcevm/test/methods/MethodHandleTest.java
index 1efbf0d3..53f4a256 100644
--- a/dcevm/src/test/java7/com/github/dcevm/test/methods/MethodHandleTest.java
+++ b/dcevm/src/test/java7/com/github/dcevm/test/methods/MethodHandleTest.java
@@ -46,6 +46,11 @@ public class MethodHandleTest {
// Version 0
public static class A {
+ public int field;
+ public A(int value) {
+ field = value;
+ }
+
public int method() {
return 1;
}
@@ -65,6 +70,11 @@ public class MethodHandleTest {
// Version 1
public static class A___1 {
+ public int field;
+ public A___1(int value) {
+ field = value * 10;
+ }
+
public int method() {
return 2;
}
@@ -95,7 +105,7 @@ public class MethodHandleTest {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = lookup.findVirtual(A.class, "method", MethodType.methodType(int.class));
- A a = new A();
+ A a = new A(3);
assertEquals(1, (int) handle.invokeExact(a));
__toVersion__(1);
@@ -114,7 +124,7 @@ public class MethodHandleTest {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = lookup.findVirtual(A.class, "method", MethodType.methodType(int.class));
- A a = new A();
+ A a = new A(3);
MethodHandle boundHandle = handle.bindTo(a);
assertEquals(1, (int) boundHandle.invokeExact());
@@ -145,6 +155,24 @@ public class MethodHandleTest {
}
@Test
+ public void testConstructorMethodHandleUpdated() throws Throwable {
+
+ assert __version__() == 0;
+
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle handle = lookup.findConstructor(A.class, MethodType.methodType(void.class, int.class));
+
+ assertEquals(12, ((A) handle.invoke(12)).field);
+
+ __toVersion__(1);
+
+ assertEquals(120, ((A) handle.invoke(12)).field);
+
+ __toVersion__(0);
+ assert __version__() == 0;
+ }
+
+ @Test
public void testComplexMethodHandleUpdated() throws Throwable {
assert __version__() == 0;
@@ -154,7 +182,7 @@ public class MethodHandleTest {
MethodHandle filter = lookup.findVirtual(A.class, "filter", MethodType.methodType(int.class, int.class));
MethodHandle staticFilter = lookup.findStatic(A.class, "staticFilter", MethodType.methodType(int.class, int.class));
- A a = new A();
+ A a = new A(3);
MethodHandle boundFilter = filter.bindTo(a);
handle = MethodHandles.filterReturnValue(handle, staticFilter);
handle = MethodHandles.filterReturnValue(handle, boundFilter);
diff --git a/gradle.properties b/gradle.properties
index 6d203725..d20cf3de 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -31,7 +31,7 @@ targetJre=build/jre
#hotspotTag=jdk7u55-b13
#hotspotTag=jdk7u60-b09
#hotspotTag=jdk7u71-b01
-#hotspotTag=jdk7u79-b02
+#hotspotTag=jdk7u79-b15
#hotspotTag=jdk8u31-b13
#hotspotTag=jdk8u20-b22
diff --git a/hotspot/.hg/patches/full-jdk7u79-b15-method-handles.patch b/hotspot/.hg/patches/full-jdk7u79-b15-method-handles.patch
new file mode 100644
index 00000000..41439d75
--- /dev/null
+++ b/hotspot/.hg/patches/full-jdk7u79-b15-method-handles.patch
@@ -0,0 +1,328 @@
+# HG changeset patch
+# Parent 2ffb90b422e20ff948d25b96bfb9be923c130734
+
+diff -r 2ffb90b422e2 src/share/vm/classfile/javaClasses.cpp
+--- a/src/share/vm/classfile/javaClasses.cpp Fri Jul 10 10:19:24 2015 -0700
++++ b/src/share/vm/classfile/javaClasses.cpp Fri Jul 10 10:19:37 2015 -0700
+@@ -2409,6 +2409,52 @@
+ }
+ }
+
++// Support for java_lang_invoke_DirectMethodHandle$StaticAccessor
++
++int java_lang_invoke_DirectMethodHandle_StaticAccessor::_static_offset_offset;
++
++long java_lang_invoke_DirectMethodHandle_StaticAccessor::static_offset(oop dmh) {
++ assert(_static_offset_offset != 0, "");
++ return dmh->long_field(_static_offset_offset);
++}
++
++void java_lang_invoke_DirectMethodHandle_StaticAccessor::set_static_offset(oop dmh, long static_offset) {
++ assert(_static_offset_offset != 0, "");
++ dmh->long_field_put(_static_offset_offset, static_offset);
++}
++
++
++void java_lang_invoke_DirectMethodHandle_StaticAccessor::compute_offsets() {
++ klassOop klass_oop = SystemDictionary::DirectMethodHandle_StaticAccessor_klass();
++ if (klass_oop != NULL && EnableInvokeDynamic) {
++ compute_offset(_static_offset_offset, klass_oop, vmSymbols::static_offset_name(), vmSymbols::long_signature());
++ }
++}
++
++// Support for java_lang_invoke_DirectMethodHandle$Accessor
++
++int java_lang_invoke_DirectMethodHandle_Accessor::_field_offset_offset;
++
++int java_lang_invoke_DirectMethodHandle_Accessor::field_offset(oop dmh) {
++ assert(_field_offset_offset != 0, "");
++ return dmh->int_field(_field_offset_offset);
++}
++
++void java_lang_invoke_DirectMethodHandle_Accessor::set_field_offset(oop dmh, int field_offset) {
++ assert(_field_offset_offset != 0, "");
++ dmh->int_field_put(_field_offset_offset, field_offset);
++}
++
++
++void java_lang_invoke_DirectMethodHandle_Accessor::compute_offsets() {
++ klassOop klass_oop = SystemDictionary::DirectMethodHandle_Accessor_klass();
++ if (klass_oop != NULL && EnableInvokeDynamic) {
++ compute_offset(_field_offset_offset, klass_oop, vmSymbols::field_offset_name(), vmSymbols::int_signature());
++ }
++}
++
++
++
+ // Support for java_lang_invoke_MethodHandle
+
+ int java_lang_invoke_MethodHandle::_type_offset;
+@@ -3028,6 +3074,8 @@
+ if (EnableInvokeDynamic) {
+ java_lang_invoke_MethodHandle::compute_offsets();
+ java_lang_invoke_DirectMethodHandle::compute_offsets();
++ java_lang_invoke_DirectMethodHandle_StaticAccessor::compute_offsets();
++ java_lang_invoke_DirectMethodHandle_Accessor::compute_offsets();
+ java_lang_invoke_MemberName::compute_offsets();
+ java_lang_invoke_LambdaForm::compute_offsets();
+ java_lang_invoke_MethodType::compute_offsets();
+diff -r 2ffb90b422e2 src/share/vm/classfile/javaClasses.hpp
+--- a/src/share/vm/classfile/javaClasses.hpp Fri Jul 10 10:19:24 2015 -0700
++++ b/src/share/vm/classfile/javaClasses.hpp Fri Jul 10 10:19:37 2015 -0700
+@@ -940,6 +940,54 @@
+ static int member_offset_in_bytes() { return _member_offset; }
+ };
+
++// Interface to java.lang.invoke.DirectMethodHandle$StaticAccessor objects
++
++class java_lang_invoke_DirectMethodHandle_StaticAccessor: AllStatic {
++ friend class JavaClasses;
++
++ private:
++ static int _static_offset_offset; // offset to static field
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static long static_offset(oop dmh);
++ static void set_static_offset(oop dmh, long value);
++
++ // Testers
++ static bool is_subclass(klassOop klass) {
++ return Klass::cast(klass)->is_subclass_of(SystemDictionary::DirectMethodHandle_StaticAccessor_klass());
++ }
++ static bool is_instance(oop obj) {
++ return obj != NULL && is_subclass(obj->klass());
++ }
++};
++
++// Interface to java.lang.invoke.DirectMethodHandle$Accessor objects
++
++class java_lang_invoke_DirectMethodHandle_Accessor: AllStatic {
++ friend class JavaClasses;
++
++ private:
++ static int _field_offset_offset; // offset to field
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static int field_offset(oop dmh);
++ static void set_field_offset(oop dmh, int value);
++
++ // Testers
++ static bool is_subclass(klassOop klass) {
++ return Klass::cast(klass)->is_subclass_of(SystemDictionary::DirectMethodHandle_Accessor_klass());
++ }
++ static bool is_instance(oop obj) {
++ return obj != NULL && is_subclass(obj->klass());
++ }
++};
++
+ // Interface to java.lang.invoke.LambdaForm objects
+ // (These are a private interface for managing adapter code generation.)
+
+diff -r 2ffb90b422e2 src/share/vm/classfile/systemDictionary.hpp
+--- a/src/share/vm/classfile/systemDictionary.hpp Fri Jul 10 10:19:24 2015 -0700
++++ b/src/share/vm/classfile/systemDictionary.hpp Fri Jul 10 10:19:37 2015 -0700
+@@ -148,6 +148,8 @@
+ do_klass(reflect_UnsafeStaticFieldAccessorImpl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15 ) \
+ \
+ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
++ do_klass(DirectMethodHandle_StaticAccessor_klass, java_lang_invoke_DirectMethodHandle_StaticAccessor, Opt ) \
++ do_klass(DirectMethodHandle_Accessor_klass, java_lang_invoke_DirectMethodHandle_Accessor, Opt ) \
+ do_klass(MethodHandle_klass, java_lang_invoke_MethodHandle, Pre_JSR292 ) \
+ do_klass(MemberName_klass, java_lang_invoke_MemberName, Pre_JSR292 ) \
+ do_klass(MethodHandleNatives_klass, java_lang_invoke_MethodHandleNatives, Pre_JSR292 ) \
+diff -r 2ffb90b422e2 src/share/vm/classfile/vmSymbols.hpp
+--- a/src/share/vm/classfile/vmSymbols.hpp Fri Jul 10 10:19:24 2015 -0700
++++ b/src/share/vm/classfile/vmSymbols.hpp Fri Jul 10 10:19:37 2015 -0700
+@@ -248,6 +248,8 @@
+ /* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
+ template(java_lang_invoke_CallSite, "java/lang/invoke/CallSite") \
+ template(java_lang_invoke_ConstantCallSite, "java/lang/invoke/ConstantCallSite") \
++ template(java_lang_invoke_DirectMethodHandle_StaticAccessor, "java/lang/invoke/DirectMethodHandle$StaticAccessor") \
++ template(java_lang_invoke_DirectMethodHandle_Accessor, "java/lang/invoke/DirectMethodHandle$Accessor") \
+ template(java_lang_invoke_DirectMethodHandle, "java/lang/invoke/DirectMethodHandle") \
+ template(java_lang_invoke_MutableCallSite, "java/lang/invoke/MutableCallSite") \
+ template(java_lang_invoke_VolatileCallSite, "java/lang/invoke/VolatileCallSite") \
+@@ -485,6 +487,10 @@
+ template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \
+ template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \
+ template(int_String_signature, "(I)Ljava/lang/String;") \
++ template(static_offset_name, "staticOffset") \
++ template(static_base_name, "staticBase") \
++ template(field_offset_name, "fieldOffset") \
++ template(field_type_name, "fieldType") \
+ /* signature symbols needed by intrinsics */ \
+ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \
+ \
+diff -r 2ffb90b422e2 src/share/vm/prims/jvmtiRedefineClasses.cpp
+--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Jul 10 10:19:24 2015 -0700
++++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Jul 10 10:19:37 2015 -0700
+@@ -2110,6 +2110,120 @@
+
+ }
+
++// import java_lang_invoke_MemberName.*
++enum {
++ REFERENCE_KIND_SHIFT = java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT,
++ REFERENCE_KIND_MASK = java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK,
++};
++
++static oop field_name_or_null(Symbol* s) {
++ if (s == NULL) return NULL;
++ return StringTable::lookup(s);
++}
++
++static oop object_java_mirror() {
++ return Klass::cast(SystemDictionary::Object_klass())->java_mirror();
++}
++
++static oop field_signature_type_or_null(Symbol* s) {
++ if (s == NULL) return NULL;
++ BasicType bt = FieldType::basic_type(s);
++ if (is_java_primitive(bt)) {
++ assert(s->utf8_length() == 1, "");
++ return java_lang_Class::primitive_mirror(bt);
++ }
++ // Here are some more short cuts for common types.
++ // They are optional, since reference types can be resolved lazily.
++ if (bt == T_OBJECT) {
++ if (s == vmSymbols::object_signature()) {
++ return object_java_mirror();
++ } else if (s == vmSymbols::class_signature()) {
++ return Klass::cast(SystemDictionary::Class_klass())->java_mirror();
++ } else if (s == vmSymbols::string_signature()) {
++ return Klass::cast(SystemDictionary::String_klass())->java_mirror();
++ }
++ }
++ return NULL;
++}
++
++bool update_member_name(oop obj) {
++ int flags = java_lang_invoke_MemberName::flags(obj);
++ int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
++ if (MethodHandles::ref_kind_is_method(ref_kind)) {
++ methodOop m = (methodOop) java_lang_invoke_MemberName::vmtarget(obj);
++ if (m != NULL && !instanceKlass::cast(m->method_holder())->is_newest_version()) {
++ // Let's try to re-resolve method
++ KlassHandle newest = instanceKlass::cast(m->method_holder())->newest_version();
++ methodOop new_method = instanceKlass::cast(newest())->find_method(m->name(), m->signature());
++
++ // Note: we might set NULL at this point, which should force AbstractMethodError at runtime
++ bool do_dispatch = (ref_kind != JVM_REF_invokeSpecial);
++ MethodHandles::init_method_MemberName(obj, new_method, do_dispatch, newest);
++ }
++ } else if (MethodHandles::ref_kind_is_field(ref_kind)) {
++ klassOop k = (klassOop) java_lang_invoke_MemberName::vmtarget(obj);
++ if (k == NULL) {
++ return false; // Was cleared before, this MemberName is invalid.
++ }
++
++ if (k != NULL && !Klass::cast(k)->is_newest_version()) {
++ // Let's try to re-resolve field
++ fieldDescriptor fd;
++ int offset = java_lang_invoke_MemberName::vmindex(obj);
++ bool is_static = MethodHandles::ref_kind_is_static(ref_kind);
++ instanceKlass *ik = instanceKlass::cast(k);
++ if (ik->find_local_field_from_offset(offset, is_static, &fd)) {
++ KlassHandle newest = Klass::cast(k)->newest_version();
++ fieldDescriptor fd_new;
++ if (instanceKlass::cast(newest())->find_local_field(fd.name(), fd.signature(), &fd_new)) {
++ bool is_setter = MethodHandles::ref_kind_is_setter(ref_kind);
++ oop type = field_signature_type_or_null(fd_new.signature());
++ oop name = field_name_or_null(fd_new.name());
++ MethodHandles::init_field_MemberName(obj, newest, fd_new.access_flags(), type, name, fd_new.offset(), is_setter);
++ } else {
++ // Matching field is not found in new version, not much we can do here.
++ // JVM will crash once faulty MH is invoked.
++ // However, to avoid that all DMH's using this faulty MH are cleared (set to NULL)
++ // Eventually, we probably want to replace them with something more meaningful,
++ // like instance throwing NoSuchFieldError or DMH that will resort to dynamic
++ // field resolution (with possibility of type conversion)
++ java_lang_invoke_MemberName::set_vmtarget(obj, NULL);
++ java_lang_invoke_MemberName::set_vmindex(obj, 0);
++ return false;
++ }
++ }
++ }
++ }
++ return true;
++}
++
++bool update_direct_method_handle(oop obj) {
++ // Always update member name first.
++ oop mem_name = java_lang_invoke_DirectMethodHandle::member(obj);
++ if (!update_member_name(mem_name)) {
++ return false;
++ }
++
++ // Here we rely on DirectMethodHandle implementation.
++ // The current implementation caches field offset in $StaticAccessor/$Accessor
++ int flags = java_lang_invoke_MemberName::flags(mem_name);
++ int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
++ if (MethodHandles::ref_kind_is_field(ref_kind)) {
++ // Note: we don't care about staticBase field (which is java.lang.Class)
++ // It should be processed during normal object update.
++ // Update offset in StaticAccessor
++ int offset = java_lang_invoke_MemberName::vmindex(mem_name);
++ if (offset != 0) { // index of 0 means that field no longer exist
++ if (java_lang_invoke_DirectMethodHandle_StaticAccessor::is_instance(obj)) {
++ java_lang_invoke_DirectMethodHandle_StaticAccessor::set_static_offset(obj, offset);
++ } else if (java_lang_invoke_DirectMethodHandle_Accessor::is_instance(obj)) {
++ java_lang_invoke_DirectMethodHandle_Accessor::set_field_offset(obj, offset);
++ }
++ }
++ }
++ return true;
++}
++
+ 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)) {
+@@ -2148,6 +2262,18 @@
+ }
+ }
+ }
++ } else {
++ // JSR 292 support, uptade java.lang.invoke.MemberName instances
++ if (java_lang_invoke_MemberName::is_instance(obj)) {
++ update_member_name(obj);
++ } else if (java_lang_invoke_DirectMethodHandle::is_instance(obj)) {
++ if (!update_direct_method_handle(obj)) {
++ // DMH is no longer valid, replace it with null reference.
++ // See note above. We probably want to replace this with something more meaningful.
++ oopDesc::encode_store_heap_oop_not_null(p, NULL);
++ //S::oop_store(p, NULL);
++ }
++ }
+ }
+ }
+ }
+@@ -2822,6 +2948,11 @@
+ // TODO:
+ transfer_old_native_function_registrations(the_old_class);
+
++ // Swap method handles
++ MemberNameTable* mnt = the_old_class->member_names();
++ assert(the_new_class->member_names() == NULL, "");
++ the_new_class->set_member_names(mnt);
++ the_old_class->set_member_names(NULL);
+
+ #ifdef ASSERT
+
+diff -r 2ffb90b422e2 src/share/vm/runtime/mutexLocker.cpp
+--- a/src/share/vm/runtime/mutexLocker.cpp Fri Jul 10 10:19:24 2015 -0700
++++ b/src/share/vm/runtime/mutexLocker.cpp Fri Jul 10 10:19:37 2015 -0700
+@@ -267,7 +267,7 @@
+ def(Heap_lock , Monitor, nonleaf+1, false);
+ def(JfieldIdCreation_lock , Mutex , nonleaf+1, true ); // jfieldID, Used in VM_Operation
+ def(JNICachedItableIndex_lock , Mutex , nonleaf+1, false); // Used to cache an itable index during JNI invoke
+- def(MemberNameTable_lock , Mutex , nonleaf+1, false); // Used to protect MemberNameTable
++ def(MemberNameTable_lock , Mutex , nonleaf+1, true); // Used to protect MemberNameTable
+
+ def(CompiledIC_lock , Mutex , nonleaf+2, false); // locks VtableStubs_lock, InlineCacheBuffer_lock
+ def(CompileTaskAlloc_lock , Mutex , nonleaf+2, true );
diff --git a/hotspot/.hg/patches/full-jdk7u79-b02.patch b/hotspot/.hg/patches/full-jdk7u79-b15.patch
index 8b82eea3..19ff13ed 100644
--- a/hotspot/.hg/patches/full-jdk7u79-b02.patch
+++ b/hotspot/.hg/patches/full-jdk7u79-b15.patch
@@ -1,7 +1,9 @@
-diff --git a/make/bsd/makefiles/gcc.make b/make/bsd/makefiles/gcc.make
-index 3de1dea..8bf7f94 100644
---- a/make/bsd/makefiles/gcc.make
-+++ b/make/bsd/makefiles/gcc.make
+# HG changeset patch
+# Parent 882f6c762ac5352a0d94efcea46c8f9a917ceb08
+
+diff -r 882f6c762ac5 make/bsd/makefiles/gcc.make
+--- a/make/bsd/makefiles/gcc.make Thu Jul 09 23:10:04 2015 -0700
++++ b/make/bsd/makefiles/gcc.make Thu Jul 09 23:18:17 2015 -0700
@@ -117,7 +117,10 @@
CFLAGS += -fno-rtti
CFLAGS += -fno-exceptions
@@ -14,10 +16,9 @@ index 3de1dea..8bf7f94 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/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
-+++ b/src/cpu/x86/vm/templateTable_x86_32.cpp
+diff -r 882f6c762ac5 src/cpu/x86/vm/templateTable_x86_32.cpp
+--- a/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -2109,6 +2109,22 @@
// resolve first time through
address entry;
@@ -173,10 +174,9 @@ index fc19edc..d2cddd3 100644
// Get receiver klass into rdx - also a null check
__ restore_locals(); // restore rdi
__ null_check(rcx, oopDesc::klass_offset_in_bytes());
-diff --git a/src/cpu/x86/vm/templateTable_x86_64.cpp b/src/cpu/x86/vm/templateTable_x86_64.cpp
-index 932ee97..67bb710 100644
---- a/src/cpu/x86/vm/templateTable_x86_64.cpp
-+++ b/src/cpu/x86/vm/templateTable_x86_64.cpp
+diff -r 882f6c762ac5 src/cpu/x86/vm/templateTable_x86_64.cpp
+--- a/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -2151,6 +2151,22 @@
// resolve first time through
address entry;
@@ -337,10 +337,9 @@ index 932ee97..67bb710 100644
// Get receiver klass into rdx - also a null check
__ restore_locals(); // restore r14
__ null_check(rcx, oopDesc::klass_offset_in_bytes());
-diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp
-index 9a8ca61..196ab25 100644
---- a/src/share/vm/c1/c1_Compilation.hpp
-+++ b/src/share/vm/c1/c1_Compilation.hpp
+diff -r 882f6c762ac5 src/share/vm/c1/c1_Compilation.hpp
+--- a/src/share/vm/c1/c1_Compilation.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/c1/c1_Compilation.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -242,8 +242,8 @@
#define BAILOUT(msg) { bailout(msg); return; }
#define BAILOUT_(msg, res) { bailout(msg); return res; }
@@ -352,10 +351,9 @@ index 9a8ca61..196ab25 100644
class InstructionMark: public StackObj {
-diff --git a/src/share/vm/ci/ciEnv.cpp b/src/share/vm/ci/ciEnv.cpp
-index e20db5d..57f37db 100644
---- a/src/share/vm/ci/ciEnv.cpp
-+++ b/src/share/vm/ci/ciEnv.cpp
+diff -r 882f6c762ac5 src/share/vm/ci/ciEnv.cpp
+--- a/src/share/vm/ci/ciEnv.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/ci/ciEnv.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -1172,3 +1172,11 @@
// If memory is low, we stop compiling methods.
record_method_not_compilable("out of memory");
@@ -368,10 +366,9 @@ index e20db5d..57f37db 100644
+ _factory->cleanup_after_redefinition();
+ }
+}
-diff --git a/src/share/vm/ci/ciEnv.hpp b/src/share/vm/ci/ciEnv.hpp
-index 103e532..abe2e37 100644
---- a/src/share/vm/ci/ciEnv.hpp
-+++ b/src/share/vm/ci/ciEnv.hpp
+diff -r 882f6c762ac5 src/share/vm/ci/ciEnv.hpp
+--- a/src/share/vm/ci/ciEnv.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/ci/ciEnv.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -417,6 +417,8 @@
void record_failure(const char* reason);
void record_method_not_compilable(const char* reason, bool all_tiers = true);
@@ -381,10 +378,9 @@ index 103e532..abe2e37 100644
};
#endif // SHARE_VM_CI_CIENV_HPP
-diff --git a/src/share/vm/ci/ciObjectFactory.cpp b/src/share/vm/ci/ciObjectFactory.cpp
-index e0ab96b..36efef4 100644
---- a/src/share/vm/ci/ciObjectFactory.cpp
-+++ b/src/share/vm/ci/ciObjectFactory.cpp
+diff -r 882f6c762ac5 src/share/vm/ci/ciObjectFactory.cpp
+--- a/src/share/vm/ci/ciObjectFactory.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/ci/ciObjectFactory.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -296,6 +296,11 @@
// into the table. We need to recompute our index.
index = find(keyHandle(), _ci_objects);
@@ -448,10 +444,9 @@ index e0ab96b..36efef4 100644
+void ciObjectFactory::cleanup_after_redefinition() {
+ 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
+diff -r 882f6c762ac5 src/share/vm/ci/ciObjectFactory.hpp
+--- a/src/share/vm/ci/ciObjectFactory.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/ci/ciObjectFactory.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -38,6 +38,7 @@
class ciObjectFactory : public ResourceObj {
friend class VMStructs;
@@ -472,10 +467,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 505bad1..2912a66 100644
---- a/src/share/vm/classfile/classFileParser.cpp
-+++ b/src/share/vm/classfile/classFileParser.cpp
+diff -r 882f6c762ac5 src/share/vm/classfile/classFileParser.cpp
+--- a/src/share/vm/classfile/classFileParser.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/classFileParser.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -795,6 +795,7 @@
Handle class_loader,
Handle protection_domain,
@@ -557,15 +551,15 @@ index 505bad1..2912a66 100644
// Fill in code attribute information
m->set_max_stack(max_stack);
m->set_max_locals(max_locals);
-@@ -2228,6 +2267,8 @@
- * sure that the oops can pass verification when this field is set.
+@@ -2229,6 +2268,8 @@
*/
m->constMethod()->set_stackmap_data(stackmap_data());
-+
-+ m->constMethod()->set_code_section_table(code_section_table());
++ m->constMethod()->set_code_section_table(code_section_table());
++
// Copy byte codes
m->set_code(code_start);
+
@@ -2825,6 +2866,15 @@
"Invalid Deprecated classfile attribute length %u in class file %s",
attribute_length, CHECK);
@@ -803,17 +797,17 @@ index 505bad1..2912a66 100644
// reinitialize modifiers, using the InnerClasses attribute
int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle));
-@@ -3748,6 +3948,10 @@
-
+@@ -3749,6 +3949,10 @@
// Allocate mirror and initialize static fields
java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle));
-+
+
+ if (rt == REF_OTHER) {
+ instanceRefKlass::update_nonstatic_oop_maps(ik);
+ }
-
++
ClassLoadingService::notify_class_loaded(instanceKlass::cast(this_klass()),
false /* not shared class */);
+
@@ -3891,7 +4095,7 @@
}
@@ -843,10 +837,9 @@ index 505bad1..2912a66 100644
k->set_is_cloneable();
}
}
-diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp
-index a95a784..ac217fc 100644
---- a/src/share/vm/classfile/classFileParser.hpp
-+++ b/src/share/vm/classfile/classFileParser.hpp
+diff -r 882f6c762ac5 src/share/vm/classfile/classFileParser.hpp
+--- a/src/share/vm/classfile/classFileParser.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/classFileParser.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -64,6 +64,9 @@
int _sde_length;
typeArrayHandle _inner_classes;
@@ -923,10 +916,9 @@ index a95a784..ac217fc 100644
// Verifier checks
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 a2e61a4..450e19f 100644
---- a/src/share/vm/classfile/classLoader.cpp
-+++ b/src/share/vm/classfile/classLoader.cpp
+diff -r 882f6c762ac5 src/share/vm/classfile/classLoader.cpp
+--- a/src/share/vm/classfile/classLoader.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/classLoader.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -915,6 +915,7 @@
instanceKlassHandle result = parser.parseClassFile(h_name,
class_loader,
@@ -935,10 +927,9 @@ index a2e61a4..450e19f 100644
parsed_name,
false,
CHECK_(h));
-diff --git a/src/share/vm/classfile/dictionary.cpp b/src/share/vm/classfile/dictionary.cpp
-index 78e76cc..ee21f3a 100644
---- a/src/share/vm/classfile/dictionary.cpp
-+++ b/src/share/vm/classfile/dictionary.cpp
+diff -r 882f6c762ac5 src/share/vm/classfile/dictionary.cpp
+--- a/src/share/vm/classfile/dictionary.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/dictionary.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -326,6 +326,21 @@
}
}
@@ -1037,10 +1028,9 @@ index 78e76cc..ee21f3a 100644
}
-diff --git a/src/share/vm/classfile/dictionary.hpp b/src/share/vm/classfile/dictionary.hpp
-index bd33760..186d0eb 100644
---- a/src/share/vm/classfile/dictionary.hpp
-+++ b/src/share/vm/classfile/dictionary.hpp
+diff -r 882f6c762ac5 src/share/vm/classfile/dictionary.hpp
+--- a/src/share/vm/classfile/dictionary.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/dictionary.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -73,6 +73,10 @@
void add_klass(Symbol* class_name, Handle class_loader,KlassHandle obj);
@@ -1068,10 +1058,9 @@ index bd33760..186d0eb 100644
klassOop find(int index, unsigned int hash, Symbol* name,
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 7dd5f1b..9c7d8eb 100644
---- a/src/share/vm/classfile/javaClasses.cpp
-+++ b/src/share/vm/classfile/javaClasses.cpp
+diff -r 882f6c762ac5 src/share/vm/classfile/javaClasses.cpp
+--- a/src/share/vm/classfile/javaClasses.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/javaClasses.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -1798,7 +1798,7 @@
klassOop klass = SystemDictionary::reflect_Method_klass();
// This class is eagerly initialized during VM initialization, since we keep a refence
@@ -1081,10 +1070,9 @@ index 7dd5f1b..9c7d8eb 100644
return instanceKlass::cast(klass)->allocate_instance_handle(CHECK_NH);
}
-diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
-index 36d1cec..a6de98e 100644
---- a/src/share/vm/classfile/javaClasses.hpp
-+++ b/src/share/vm/classfile/javaClasses.hpp
+diff -r 882f6c762ac5 src/share/vm/classfile/javaClasses.hpp
+--- a/src/share/vm/classfile/javaClasses.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/javaClasses.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -213,7 +213,6 @@
class java_lang_Class : AllStatic {
@@ -1093,10 +1081,9 @@ index 36d1cec..a6de98e 100644
private:
// 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 8650cd9..965cce2 100644
---- a/src/share/vm/classfile/loaderConstraints.cpp
-+++ b/src/share/vm/classfile/loaderConstraints.cpp
+diff -r 882f6c762ac5 src/share/vm/classfile/loaderConstraints.cpp
+--- a/src/share/vm/classfile/loaderConstraints.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/loaderConstraints.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -449,7 +449,7 @@
if (k != NULL) {
// We found the class in the system dictionary, so we should
@@ -1106,10 +1093,9 @@ index 8650cd9..965cce2 100644
} 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/loaderConstraints.hpp b/src/share/vm/classfile/loaderConstraints.hpp
-index d01b2c4..1ad80f7 100644
---- a/src/share/vm/classfile/loaderConstraints.hpp
-+++ b/src/share/vm/classfile/loaderConstraints.hpp
+diff -r 882f6c762ac5 src/share/vm/classfile/loaderConstraints.hpp
+--- a/src/share/vm/classfile/loaderConstraints.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/loaderConstraints.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -106,7 +106,7 @@
klassOop klass() { return literal(); }
@@ -1119,10 +1105,9 @@ index d01b2c4..1ad80f7 100644
LoaderConstraintEntry* next() {
return (LoaderConstraintEntry*)HashtableEntry<klassOop, mtClass>::next();
-diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfile/systemDictionary.cpp
-index 2fa221b..8e45161 100644
---- a/src/share/vm/classfile/systemDictionary.cpp
-+++ b/src/share/vm/classfile/systemDictionary.cpp
+diff -r 882f6c762ac5 src/share/vm/classfile/systemDictionary.cpp
+--- a/src/share/vm/classfile/systemDictionary.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/systemDictionary.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -157,6 +157,7 @@
// can return a null klass
klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD);
@@ -1179,7 +1164,7 @@ index 2fa221b..8e45161 100644
const char* pkg = "java/";
if (!HAS_PENDING_EXCEPTION &&
-@@ -1087,11 +1102,16 @@
+@@ -1087,13 +1102,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
@@ -1191,13 +1176,15 @@ index 2fa221b..8e45161 100644
- define_instance_class(k, THREAD);
+ define_instance_class(k, old_class, THREAD);
}
-+ }
-+
-+ if (redefine_classes_locked) {
-+ Thread::current()->redefine_classes_mutex()->unlock();
}
++ if (redefine_classes_locked) {
++ Thread::current()->redefine_classes_mutex()->unlock();
++ }
++
// If parsing the class file or define_instance_class failed, we
+ // need to remove the placeholder added on our behalf. But we
+ // must make sure parsed_name is valid first (it won't be if we had
@@ -1122,7 +1142,7 @@
MutexLocker mu(SystemDictionary_lock, THREAD);
@@ -1281,12 +1268,24 @@ index 2fa221b..8e45161 100644
// ----------------------------------------------------------------------------
// GC support
-@@ -1702,6 +1745,24 @@
+@@ -1702,7 +1745,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]);
+ }
+@@ -1716,6 +1760,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]);
+ }
@@ -1300,24 +1299,21 @@ index 2fa221b..8e45161 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]);
-@@ -1732,6 +1793,11 @@
- // Don't iterate over placeholders
- 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.
+@@ -1734,6 +1795,11 @@
dictionary()->classes_do(f);
-+}
-+
+ }
+
+// (tw) Iterate over all classes in the dictionary.
+void SystemDictionary::classes_do(ObjectClosure *closure) {
+ dictionary()->classes_do(closure);
- }
-
++}
++
// Added for initialize_itable_for_klass
+ // Just the classes from defining class loaders
+ // Don't iterate over placeholders
@@ -1870,7 +1936,9 @@
// Preload ref klasses and set reference types
@@ -1342,10 +1338,9 @@ index 2fa221b..8e45161 100644
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
-index 85474c5..2dabd95 100644
---- a/src/share/vm/classfile/systemDictionary.hpp
-+++ b/src/share/vm/classfile/systemDictionary.hpp
+diff -r 882f6c762ac5 src/share/vm/classfile/systemDictionary.hpp
+--- a/src/share/vm/classfile/systemDictionary.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/systemDictionary.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -270,7 +270,7 @@
// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
static klassOop resolve_from_stream(Symbol* class_name, Handle class_loader,
@@ -1364,15 +1359,15 @@ index 85474c5..2dabd95 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
-@@ -416,6 +418,8 @@
- int limit = (int)end_id + 1;
+@@ -417,6 +419,8 @@
initialize_wk_klasses_until((WKID) limit, start_id, THREAD);
}
-+
-+ static void rollback_redefinition();
++ static void rollback_redefinition();
++
public:
#define WK_KLASS_DECLARE(name, symbol, option) \
+ static klassOop name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); }
@@ -598,11 +602,11 @@
// after waiting, but before reentering SystemDictionary_lock
// to preserve lock order semantics.
@@ -1405,10 +1400,9 @@ index 85474c5..2dabd95 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 49c4b2c..74d7614 100644
---- a/src/share/vm/classfile/verifier.cpp
-+++ b/src/share/vm/classfile/verifier.cpp
+diff -r 882f6c762ac5 src/share/vm/classfile/verifier.cpp
+--- a/src/share/vm/classfile/verifier.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/verifier.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -106,7 +106,7 @@
return !need_verify;
}
@@ -1493,10 +1487,9 @@ index 49c4b2c..74d7614 100644
Symbol* ref_class_name =
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 92c4fd2..5e8e0da 100644
---- a/src/share/vm/classfile/verifier.hpp
-+++ b/src/share/vm/classfile/verifier.hpp
+diff -r 882f6c762ac5 src/share/vm/classfile/verifier.hpp
+--- a/src/share/vm/classfile/verifier.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/verifier.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -48,7 +48,7 @@
* Otherwise, no exception is thrown and the return indicates the
* error.
@@ -1525,10 +1518,9 @@ index 92c4fd2..5e8e0da 100644
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/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
-index 51ceb15..7ef1e1f 100644
---- a/src/share/vm/classfile/vmSymbols.hpp
-+++ b/src/share/vm/classfile/vmSymbols.hpp
+diff -r 882f6c762ac5 src/share/vm/classfile/vmSymbols.hpp
+--- a/src/share/vm/classfile/vmSymbols.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/classfile/vmSymbols.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -139,6 +139,10 @@
template(tag_annotation_default, "AnnotationDefault") \
template(tag_enclosing_method, "EnclosingMethod") \
@@ -1551,10 +1543,9 @@ index 51ceb15..7ef1e1f 100644
/* non-intrinsic name/signature pairs: */ \
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 3e8a65a..fe96a94 100644
---- a/src/share/vm/compiler/compileBroker.cpp
-+++ b/src/share/vm/compiler/compileBroker.cpp
+diff -r 882f6c762ac5 src/share/vm/compiler/compileBroker.cpp
+--- a/src/share/vm/compiler/compileBroker.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/compiler/compileBroker.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -1181,6 +1181,14 @@
int comp_level,
methodHandle hot_method, int hot_count,
@@ -1611,10 +1602,9 @@ index 3e8a65a..fe96a94 100644
+ }
+ }
+}
-diff --git a/src/share/vm/compiler/compileBroker.hpp b/src/share/vm/compiler/compileBroker.hpp
-index 29f2b22..37989d1 100644
---- a/src/share/vm/compiler/compileBroker.hpp
-+++ b/src/share/vm/compiler/compileBroker.hpp
+diff -r 882f6c762ac5 src/share/vm/compiler/compileBroker.hpp
+--- a/src/share/vm/compiler/compileBroker.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/compiler/compileBroker.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -408,6 +408,7 @@
static void print_compiler_threads_on(outputStream* st);
@@ -1623,10 +1613,9 @@ index 29f2b22..37989d1 100644
static int get_total_compile_count() { return _total_compile_count; }
static int get_total_bailout_count() { return _total_bailout_count; }
static int get_total_invalidated_count() { return _total_invalidated_count; }
-diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp
-index a3abd66..b45f9e1 100644
---- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp
-+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp
+diff -r 882f6c762ac5 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp
+--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -162,6 +162,13 @@
}
}
@@ -1641,10 +1630,9 @@ index a3abd66..b45f9e1 100644
// Like CompactibleSpace forward() but always calls cross_threshold() to
// update the block offset table. Removed initialize_threshold call because
// CFLS does not use a block offset array for contiguous spaces.
-diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp
-index 24509b6..6670b73 100644
---- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp
-+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp
+diff -r 882f6c762ac5 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp
+--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -149,6 +149,7 @@
// Support for compacting cms
@@ -1653,10 +1641,9 @@ index 24509b6..6670b73 100644
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
-index 29841d8..a13a35d 100644
---- a/src/share/vm/gc_implementation/shared/markSweep.cpp
-+++ b/src/share/vm/gc_implementation/shared/markSweep.cpp
+diff -r 882f6c762ac5 src/share/vm/gc_implementation/shared/markSweep.cpp
+--- a/src/share/vm/gc_implementation/shared/markSweep.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/gc_implementation/shared/markSweep.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -32,6 +32,8 @@
#include "oops/objArrayKlass.inline.hpp"
#include "oops/oop.inline.hpp"
@@ -1753,22 +1740,22 @@ index 29841d8..a13a35d 100644
+ FREE_RESOURCE_ARRAY(HeapWord, tmp_obj, size);
+ }
+}
-diff --git a/src/share/vm/gc_implementation/shared/markSweep.hpp b/src/share/vm/gc_implementation/shared/markSweep.hpp
-index eb8252c..b96a677 100644
---- a/src/share/vm/gc_implementation/shared/markSweep.hpp
-+++ b/src/share/vm/gc_implementation/shared/markSweep.hpp
-@@ -117,7 +117,11 @@
+diff -r 882f6c762ac5 src/share/vm/gc_implementation/shared/markSweep.hpp
+--- a/src/share/vm/gc_implementation/shared/markSweep.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/gc_implementation/shared/markSweep.hpp Thu Jul 09 23:18:17 2015 -0700
+@@ -117,8 +117,12 @@
friend class AdjustPointerClosure;
friend class KeepAliveClosure;
friend class VM_MarkSweep;
+ friend class GenMarkSweep;
friend void marksweep_init();
-+
+
+public:
+ static GrowableArray<oop>* _rescued_oops;
-
++
//
// Vars
+ //
@@ -208,6 +212,8 @@
template <class T> static inline void mark_and_push(T* p);
static inline void push_objarray(oop obj, size_t index);
@@ -1778,10 +1765,9 @@ index eb8252c..b96a677 100644
static void follow_stack(); // Empty marking stack.
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 1a1af1b..94972f0 100644
---- a/src/share/vm/interpreter/interpreterRuntime.cpp
-+++ b/src/share/vm/interpreter/interpreterRuntime.cpp
+diff -r 882f6c762ac5 src/share/vm/interpreter/interpreterRuntime.cpp
+--- a/src/share/vm/interpreter/interpreterRuntime.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/interpreter/interpreterRuntime.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -402,7 +402,7 @@
assert(h_exception.not_null(), "NULL exceptions should be handled by athrow");
assert(h_exception->is_oop(), "just checking");
@@ -1885,10 +1871,9 @@ index 1a1af1b..94972f0 100644
// It is very unlikely that method is redefined more than 100 times
// 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 6d5f13a..50fa219 100644
---- a/src/share/vm/interpreter/interpreterRuntime.hpp
-+++ b/src/share/vm/interpreter/interpreterRuntime.hpp
+diff -r 882f6c762ac5 src/share/vm/interpreter/interpreterRuntime.hpp
+--- a/src/share/vm/interpreter/interpreterRuntime.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/interpreter/interpreterRuntime.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -141,6 +141,9 @@
static void post_method_entry(JavaThread *thread);
static void post_method_exit (JavaThread *thread);
@@ -1899,10 +1884,9 @@ index 6d5f13a..50fa219 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 1676add..ccd5241 100644
---- a/src/share/vm/interpreter/linkResolver.cpp
-+++ b/src/share/vm/interpreter/linkResolver.cpp
+diff -r 882f6c762ac5 src/share/vm/interpreter/linkResolver.cpp
+--- a/src/share/vm/interpreter/linkResolver.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/interpreter/linkResolver.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -153,8 +153,8 @@
// Klass resolution
@@ -2224,10 +2208,9 @@ index 1676add..ccd5241 100644
// check if method exists
if (selected_method.is_null()) {
ResourceMark rm(THREAD);
-diff --git a/src/share/vm/interpreter/linkResolver.hpp b/src/share/vm/interpreter/linkResolver.hpp
-index dfd74f9..cf6e44a 100644
---- a/src/share/vm/interpreter/linkResolver.hpp
-+++ b/src/share/vm/interpreter/linkResolver.hpp
+diff -r 882f6c762ac5 src/share/vm/interpreter/linkResolver.hpp
+--- a/src/share/vm/interpreter/linkResolver.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/interpreter/linkResolver.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -110,7 +110,11 @@
// It does all necessary link-time checks & throws exceptions if necessary.
@@ -2250,10 +2233,9 @@ index dfd74f9..cf6e44a 100644
static void runtime_resolve_interface_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS);
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 17e9f26..e77500f 100644
---- a/src/share/vm/interpreter/templateTable.hpp
-+++ b/src/share/vm/interpreter/templateTable.hpp
+diff -r 882f6c762ac5 src/share/vm/interpreter/templateTable.hpp
+--- a/src/share/vm/interpreter/templateTable.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/interpreter/templateTable.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -329,8 +329,8 @@
static void shouldnotreachhere();
@@ -2265,10 +2247,9 @@ index 17e9f26..e77500f 100644
static void jvmti_post_fast_field_mod();
// debugging of TemplateGenerator
-diff --git a/src/share/vm/memory/genMarkSweep.cpp b/src/share/vm/memory/genMarkSweep.cpp
-index 76e18d8..6af7c14 100644
---- a/src/share/vm/memory/genMarkSweep.cpp
-+++ b/src/share/vm/memory/genMarkSweep.cpp
+diff -r 882f6c762ac5 src/share/vm/memory/genMarkSweep.cpp
+--- a/src/share/vm/memory/genMarkSweep.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/memory/genMarkSweep.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -421,6 +421,7 @@
// in the same order in phase2, phase3 and phase4. We don't quite do that
// here (perm_gen first rather than last), so we tell the validate code
@@ -2292,10 +2273,9 @@ index 76e18d8..6af7c14 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
+diff -r 882f6c762ac5 src/share/vm/memory/permGen.cpp
+--- a/src/share/vm/memory/permGen.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/memory/permGen.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -57,7 +57,12 @@
for (;;) {
@@ -2310,10 +2290,9 @@ index 350f583..59faad1 100644
if ((obj = gen->allocate(size, false)) != NULL) {
return obj;
}
-diff --git a/src/share/vm/memory/space.cpp b/src/share/vm/memory/space.cpp
-index f97bc34..9b20d08 100644
---- a/src/share/vm/memory/space.cpp
-+++ b/src/share/vm/memory/space.cpp
+diff -r 882f6c762ac5 src/share/vm/memory/space.cpp
+--- a/src/share/vm/memory/space.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/memory/space.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -378,6 +378,31 @@
_compaction_top = bottom();
}
@@ -2881,10 +2860,9 @@ index f97bc34..9b20d08 100644
}
void Space::print_short() const { print_short_on(tty); }
-diff --git a/src/share/vm/memory/space.hpp b/src/share/vm/memory/space.hpp
-index ef2f2c6..b54d470 100644
---- a/src/share/vm/memory/space.hpp
-+++ b/src/share/vm/memory/space.hpp
+diff -r 882f6c762ac5 src/share/vm/memory/space.hpp
+--- a/src/share/vm/memory/space.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/memory/space.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -445,6 +445,9 @@
// indicates when the next such action should be taken.
virtual void prepare_for_compaction(CompactPoint* cp);
@@ -2906,10 +2884,9 @@ index ef2f2c6..b54d470 100644
// Return a size with adjusments as required of the space.
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 4030d9d..da9a186 100644
---- a/src/share/vm/memory/universe.cpp
-+++ b/src/share/vm/memory/universe.cpp
+diff -r 882f6c762ac5 src/share/vm/memory/universe.cpp
+--- a/src/share/vm/memory/universe.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/memory/universe.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -100,6 +100,8 @@
#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp"
#endif
@@ -2958,10 +2935,9 @@ index 4030d9d..da9a186 100644
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
-index 50fcb62..afb6b33 100644
---- a/src/share/vm/memory/universe.hpp
-+++ b/src/share/vm/memory/universe.hpp
+diff -r 882f6c762ac5 src/share/vm/memory/universe.hpp
+--- a/src/share/vm/memory/universe.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/memory/universe.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -127,6 +127,8 @@
friend class SystemDictionary;
friend class VMStructs;
@@ -3007,10 +2983,9 @@ index 50fcb62..afb6b33 100644
static void verify(VerifyOption option, const char* prefix, bool silent = VerifySilently);
static void verify(const char* prefix, bool silent = VerifySilently) {
verify(VerifyOption_Default, prefix, silent);
-diff --git a/src/share/vm/oops/arrayKlass.cpp b/src/share/vm/oops/arrayKlass.cpp
-index 16142b8..921e546 100644
---- a/src/share/vm/oops/arrayKlass.cpp
-+++ b/src/share/vm/oops/arrayKlass.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/arrayKlass.cpp
+--- a/src/share/vm/oops/arrayKlass.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/arrayKlass.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -136,9 +136,9 @@
bool arrayKlass::compute_is_subtype_of(klassOop k) {
@@ -3024,10 +2999,9 @@ index 16142b8..921e546 100644
}
-diff --git a/src/share/vm/oops/constMethodKlass.cpp b/src/share/vm/oops/constMethodKlass.cpp
-index e74811f..be3fe7d 100644
---- a/src/share/vm/oops/constMethodKlass.cpp
-+++ b/src/share/vm/oops/constMethodKlass.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/constMethodKlass.cpp
+--- a/src/share/vm/oops/constMethodKlass.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/constMethodKlass.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -102,6 +102,7 @@
constMethodOop cm = constMethodOop(obj);
MarkSweep::mark_and_push(cm->adr_constants());
@@ -3069,10 +3043,9 @@ index e74811f..be3fe7d 100644
// Get size before changing pointers.
// 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 549192b..5cea5c4 100644
---- a/src/share/vm/oops/constMethodOop.hpp
-+++ b/src/share/vm/oops/constMethodOop.hpp
+diff -r 882f6c762ac5 src/share/vm/oops/constMethodOop.hpp
+--- a/src/share/vm/oops/constMethodOop.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/constMethodOop.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -129,7 +129,7 @@
public:
@@ -3082,21 +3055,20 @@ index 549192b..5cea5c4 100644
private:
//
-@@ -140,6 +140,9 @@
-
+@@ -141,6 +141,9 @@
// Raw stackmap data for the method
typeArrayOop _stackmap_data;
-+
+
+ // (tw) Table mapping code sections for method forward points.
+ typeArrayOop _code_section_table;
-
++
//
// End of the oop block.
-@@ -194,6 +197,28 @@
- oop_store_without_check((oop*)&_stackmap_data, (oop)sd);
+ //
+@@ -195,6 +198,28 @@
}
bool has_stackmap_table() const { return _stackmap_data != NULL; }
-+
+
+ // code section table
+ typeArrayOop code_section_table() const { return _code_section_table; }
+ void set_code_section_table(typeArrayOop e) { oop_store_without_check((oop*) &_code_section_table, (oop) e); }
@@ -3118,9 +3090,10 @@ index 549192b..5cea5c4 100644
+ int code_section_length_at(int index) const {
+ return _code_section_table->short_at(index * ValuesPerCodeSectionEntry + 2);
+ }
-
++
void init_fingerprint() {
const uint64_t initval = CONST64(0x8000000000000000);
+ _fingerprint = initval;
@@ -301,6 +326,7 @@
// Garbage collection support
oop* adr_constants() const { return (oop*)&_constants; }
@@ -3129,10 +3102,9 @@ index 549192b..5cea5c4 100644
bool is_conc_safe() { return _is_conc_safe; }
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 ad62921..f39f202 100644
---- a/src/share/vm/oops/cpCacheOop.cpp
-+++ b/src/share/vm/oops/cpCacheOop.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/cpCacheOop.cpp
+--- a/src/share/vm/oops/cpCacheOop.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/cpCacheOop.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -37,9 +37,15 @@
// Implememtation of ConstantPoolCacheEntry
@@ -3232,7 +3204,7 @@ index ad62921..f39f202 100644
return true;
}
-@@ -548,82 +546,25 @@
+@@ -548,84 +546,27 @@
return false;
}
@@ -3271,8 +3243,8 @@ index ad62921..f39f202 100644
}
return false;
--}
--
+ }
+
-// a constant pool cache entry should never contain old or obsolete methods
-bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() {
- if (is_vfinal()) {
@@ -3322,9 +3294,11 @@ index ad62921..f39f202 100644
-
- // the method is in the interesting class so the entry is interesting
- return true;
- }
-
+-}
+-
void ConstantPoolCacheEntry::print(outputStream* st, int index) const {
+ // print separator
+ if (index == 0) st->print_cr(" -------------");
@@ -663,60 +604,18 @@
}
}
@@ -3370,7 +3344,7 @@ index ad62921..f39f202 100644
+ // (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());
-+ } else if(entry_at(i)->is_method_entry()) {
++ } else if(entry_at(i)->is_method_entry() && !entry_at(i)->is_secondary_entry()) {
+ entry_at(i)->adjust_method_entry(NULL, NULL);
}
}
@@ -3394,10 +3368,9 @@ index ad62921..f39f202 100644
- }
- }
-}
-diff --git a/src/share/vm/oops/cpCacheOop.hpp b/src/share/vm/oops/cpCacheOop.hpp
-index b9107cd..653ab13 100644
---- a/src/share/vm/oops/cpCacheOop.hpp
-+++ b/src/share/vm/oops/cpCacheOop.hpp
+diff -r 882f6c762ac5 src/share/vm/oops/cpCacheOop.hpp
+--- a/src/share/vm/oops/cpCacheOop.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/cpCacheOop.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -136,7 +136,8 @@
void set_bytecode_2(Bytecodes::Code code);
void set_f1(oop f1) {
@@ -3416,15 +3389,15 @@ index b9107cd..653ab13 100644
is_vfinal_shift = 20,
is_volatile_shift = 21,
is_final_shift = 22,
-@@ -206,6 +208,8 @@
- // Initialization
+@@ -207,6 +209,8 @@
void initialize_entry(int original_index); // initialize primary entry
void initialize_secondary_entry(int main_index); // initialize secondary entry
-+
-+ void copy_from(ConstantPoolCacheEntry *other);
++ void copy_from(ConstantPoolCacheEntry *other);
++
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
@@ -368,10 +372,7 @@
// trace_name_printed is set to true if the current call has
// printed the klass name so that other routines in the adjust_*
@@ -3457,10 +3430,9 @@ index b9107cd..653ab13 100644
};
#endif // SHARE_VM_OOPS_CPCACHEOOP_HPP
-diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp
-index a775b02..749458f 100644
---- a/src/share/vm/oops/instanceKlass.cpp
-+++ b/src/share/vm/oops/instanceKlass.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/instanceKlass.cpp
+--- a/src/share/vm/oops/instanceKlass.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/instanceKlass.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -250,12 +250,118 @@
}
@@ -3834,10 +3806,9 @@ index a775b02..749458f 100644
st->cr();
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 bb613b0..71f0083 100644
---- a/src/share/vm/oops/instanceKlass.hpp
-+++ b/src/share/vm/oops/instanceKlass.hpp
+diff -r 882f6c762ac5 src/share/vm/oops/instanceKlass.hpp
+--- a/src/share/vm/oops/instanceKlass.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/instanceKlass.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -102,6 +102,22 @@
virtual void do_field(fieldDescriptor* fd) = 0;
};
@@ -3910,10 +3881,9 @@ index bb613b0..71f0083 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 8e7dc12..63d6dc4 100644
---- a/src/share/vm/oops/instanceKlassKlass.cpp
-+++ b/src/share/vm/oops/instanceKlassKlass.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/instanceKlassKlass.cpp
+--- a/src/share/vm/oops/instanceKlassKlass.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/instanceKlassKlass.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -480,6 +480,28 @@
instanceKlass* ik = instanceKlass::cast(klassOop(obj));
klassKlass::oop_print_on(obj, st);
@@ -3952,10 +3922,9 @@ index 8e7dc12..63d6dc4 100644
sib = sib->next_sibling();
}
-diff --git a/src/share/vm/oops/instanceRefKlass.cpp b/src/share/vm/oops/instanceRefKlass.cpp
-index 7db4f03..1171487 100644
---- a/src/share/vm/oops/instanceRefKlass.cpp
-+++ b/src/share/vm/oops/instanceRefKlass.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/instanceRefKlass.cpp
+--- a/src/share/vm/oops/instanceRefKlass.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/instanceRefKlass.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -455,10 +455,13 @@
instanceKlass* ik = instanceKlass::cast(k);
@@ -3974,10 +3943,9 @@ index 7db4f03..1171487 100644
assert(ik->nonstatic_oop_map_count() == 1, "just checking");
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 ff33181..28537e2 100644
---- a/src/share/vm/oops/klass.cpp
-+++ b/src/share/vm/oops/klass.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/klass.cpp
+--- a/src/share/vm/oops/klass.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/klass.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -55,6 +55,26 @@
return false;
}
@@ -4031,10 +3999,9 @@ index ff33181..28537e2 100644
assert(super() == NULL || super() == SystemDictionary::Object_klass(),
"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 a449e87..52364ba 100644
---- a/src/share/vm/oops/klass.hpp
-+++ b/src/share/vm/oops/klass.hpp
+diff -r 882f6c762ac5 src/share/vm/oops/klass.hpp
+--- a/src/share/vm/oops/klass.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/klass.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -171,6 +171,7 @@
void* operator new(size_t ignored, KlassHandle& klass, int size, TRAPS);
};
@@ -4094,11 +4061,10 @@ index a449e87..52364ba 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 @@
-
+@@ -254,6 +292,19 @@
jint _modifier_flags; // Processed access flags, for use by Class.getModifiers.
AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here.
-+
+
+ // (tw) Non-oop 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
@@ -4111,14 +4077,14 @@ index a449e87..52364ba 100644
+ char _field_redefinition_policy;
+ char _static_field_redefinition_policy;
+ bool _is_redefining;
-
++
#ifndef PRODUCT
int _verify_count; // to avoid redundant verifies
-@@ -301,6 +352,99 @@
-
+ #endif
+@@ -302,6 +353,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); }
-+
+
+ // BEGIN class redefinition utilities
+
+ // double links between new and old version of a class
@@ -4211,9 +4177,10 @@ index a449e87..52364ba 100644
+ }
+
+ // END class redefinition utilities
-
++
objArrayOop secondary_supers() const { return _secondary_supers; }
void set_secondary_supers(objArrayOop k) { oop_store_without_check((oop*) &_secondary_supers, (oop) k); }
+
@@ -362,6 +506,8 @@
void set_next_sibling(klassOop s);
@@ -4240,10 +4207,9 @@ index a449e87..52364ba 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
+diff -r 882f6c762ac5 src/share/vm/oops/klassKlass.cpp
+--- a/src/share/vm/oops/klassKlass.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/klassKlass.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -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
@@ -4300,10 +4266,9 @@ index 06809d5..9c08f32 100644
for (juint i = 0; i < Klass::primary_super_limit(); i++)
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
+diff -r 882f6c762ac5 src/share/vm/oops/klassOop.hpp
+--- a/src/share/vm/oops/klassOop.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/klassOop.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -41,8 +41,10 @@
// returns the Klass part containing dispatching behavior
Klass* klass_part() const { return (Klass*)((address)this + sizeof(klassOopDesc)); }
@@ -4316,10 +4281,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 ff22444..8d39611 100644
---- a/src/share/vm/oops/klassVtable.cpp
-+++ b/src/share/vm/oops/klassVtable.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/klassVtable.cpp
+--- a/src/share/vm/oops/klassVtable.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/klassVtable.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -97,7 +97,8 @@
vtable_length = Universe::base_vtable_size();
}
@@ -4342,12 +4306,10 @@ index ff22444..8d39611 100644
}
int klassVtable::index_of(methodOop m, int len) const {
-@@ -676,20 +677,6 @@
- }
- }
+@@ -678,20 +679,6 @@
return true;
--}
--
+ }
+
-void klassVtable::dump_vtable() {
- tty->print_cr("vtable dump --");
- for (int i = 0; i < length(); i++) {
@@ -4360,9 +4322,11 @@ index ff22444..8d39611 100644
- tty->cr();
- }
- }
- }
-
+-}
+-
// CDS/RedefineClasses support - clear vtables so they can be reinitialized
+ void klassVtable::clear_vtable() {
+ for (int i = 0; i < _length; i++) table()[i].clear();
@@ -1262,6 +1249,7 @@
void klassVtable::verify_against(outputStream* st, klassVtable* vt, int index) {
@@ -4438,10 +4402,9 @@ index ff22444..8d39611 100644
int klassItable::_total_classes; // Total no. of classes with itables
long klassItable::_total_size; // Total no. of bytes used for itables
-diff --git a/src/share/vm/oops/klassVtable.hpp b/src/share/vm/oops/klassVtable.hpp
-index 405b0c7..0c8d2f7 100644
---- a/src/share/vm/oops/klassVtable.hpp
-+++ b/src/share/vm/oops/klassVtable.hpp
+diff -r 882f6c762ac5 src/share/vm/oops/klassVtable.hpp
+--- a/src/share/vm/oops/klassVtable.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/klassVtable.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -100,6 +100,7 @@
int methods_length, bool * trace_name_printed);
bool check_no_old_or_obsolete_entries();
@@ -4450,10 +4413,9 @@ index 405b0c7..0c8d2f7 100644
// Garbage collection
void oop_follow_contents();
-diff --git a/src/share/vm/oops/methodKlass.cpp b/src/share/vm/oops/methodKlass.cpp
-index 75d0b09..f1b7d2f 100644
---- a/src/share/vm/oops/methodKlass.cpp
-+++ b/src/share/vm/oops/methodKlass.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/methodKlass.cpp
+--- a/src/share/vm/oops/methodKlass.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/methodKlass.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -93,6 +93,10 @@
m->set_adapter_entry(NULL);
m->clear_code(); // from_c/from_i get set to c2i/i2i
@@ -4548,10 +4510,9 @@ index 75d0b09..f1b7d2f 100644
st->print (" - constants: "INTPTR_FORMAT" ", (address)m->constants());
m->constants()->print_value_on(st); st->cr();
st->print (" - access: 0x%x ", m->access_flags().as_int()); m->access_flags().print_on(st); st->cr();
-diff --git a/src/share/vm/oops/methodOop.cpp b/src/share/vm/oops/methodOop.cpp
-index 4f59d3a..5cdf147 100644
---- a/src/share/vm/oops/methodOop.cpp
-+++ b/src/share/vm/oops/methodOop.cpp
+diff -r 882f6c762ac5 src/share/vm/oops/methodOop.cpp
+--- a/src/share/vm/oops/methodOop.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/methodOop.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -328,6 +328,70 @@
}
@@ -4633,10 +4594,9 @@ index 4f59d3a..5cdf147 100644
newm->constMethod()->set_code_size(new_code_length);
newm->constMethod()->set_constMethod_size(new_const_method_size);
newm->set_method_size(new_method_size);
-diff --git a/src/share/vm/oops/methodOop.hpp b/src/share/vm/oops/methodOop.hpp
-index 486e106..11e52bb 100644
---- a/src/share/vm/oops/methodOop.hpp
-+++ b/src/share/vm/oops/methodOop.hpp
+diff -r 882f6c762ac5 src/share/vm/oops/methodOop.hpp
+--- a/src/share/vm/oops/methodOop.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/methodOop.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -114,6 +114,11 @@
AccessFlags _access_flags; // Access flags
int _vtable_index; // vtable index of this method (see VtableIndexFlag)
@@ -4649,11 +4609,10 @@ index 486e106..11e52bb 100644
#ifdef CC_INTERP
int _result_index; // C++ interpreter needs for converting results to/from stack
#endif
-@@ -174,6 +179,32 @@
- Symbol* name() const { return constants()->symbol_at(name_index()); }
+@@ -175,6 +180,32 @@
int name_index() const { return constMethod()->name_index(); }
void set_name_index(int index) { constMethod()->set_name_index(index); }
-+
+
+ methodOop forward_method() const {return _forward_method; }
+ void set_forward_method(methodOop m) { _forward_method = m; }
+ bool has_forward_method() const { return forward_method() != NULL; }
@@ -4679,9 +4638,10 @@ index 486e106..11e52bb 100644
+ return old_version()->oldest_version();
+ }
+ }
-
++
// signature
Symbol* signature() const { return constants()->symbol_at(signature_index()); }
+ int signature_index() const { return constMethod()->signature_index(); }
@@ -670,6 +701,10 @@
// Inline cache support
void cleanup_inline_caches();
@@ -4703,10 +4663,9 @@ index 486e106..11e52bb 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 5982c88..4873fca 100644
---- a/src/share/vm/oops/oop.hpp
-+++ b/src/share/vm/oops/oop.hpp
+diff -r 882f6c762ac5 src/share/vm/oops/oop.hpp
+--- a/src/share/vm/oops/oop.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/oop.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -95,6 +95,7 @@
narrowOop* compressed_klass_addr();
@@ -4723,10 +4682,9 @@ index 5982c88..4873fca 100644
bool is_thread() const;
bool is_method() const;
bool is_constMethod() const;
-diff --git a/src/share/vm/oops/oop.inline.hpp b/src/share/vm/oops/oop.inline.hpp
-index f4eb2f7..0acb346 100644
---- a/src/share/vm/oops/oop.inline.hpp
-+++ b/src/share/vm/oops/oop.inline.hpp
+diff -r 882f6c762ac5 src/share/vm/oops/oop.inline.hpp
+--- a/src/share/vm/oops/oop.inline.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/oops/oop.inline.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -123,6 +123,14 @@
}
}
@@ -4750,10 +4708,9 @@ index f4eb2f7..0acb346 100644
inline bool oopDesc::is_thread() const { return blueprint()->oop_is_thread(); }
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 50e1263..701ed74 100644
---- a/src/share/vm/prims/jni.cpp
-+++ b/src/share/vm/prims/jni.cpp
+diff -r 882f6c762ac5 src/share/vm/prims/jni.cpp
+--- a/src/share/vm/prims/jni.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/jni.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -406,7 +406,7 @@
}
}
@@ -4763,10 +4720,9 @@ index 50e1263..701ed74 100644
CHECK_NULL);
if (TraceClassResolution && k != NULL) {
-diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
-index ccd09f6..ef3f024 100644
---- a/src/share/vm/prims/jvm.cpp
-+++ b/src/share/vm/prims/jvm.cpp
+diff -r 882f6c762ac5 src/share/vm/prims/jvm.cpp
+--- a/src/share/vm/prims/jvm.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/jvm.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -932,7 +932,7 @@
Handle protection_domain (THREAD, JNIHandles::resolve(pd));
klassOop k = SystemDictionary::resolve_from_stream(class_name, class_loader,
@@ -4776,10 +4732,9 @@ index ccd09f6..ef3f024 100644
CHECK_NULL);
if (TraceClassResolution && k != NULL) {
-diff --git a/src/share/vm/prims/jvmtiEnv.cpp b/src/share/vm/prims/jvmtiEnv.cpp
-index 4ac6b82..30b8e84 100644
---- a/src/share/vm/prims/jvmtiEnv.cpp
-+++ b/src/share/vm/prims/jvmtiEnv.cpp
+diff -r 882f6c762ac5 src/share/vm/prims/jvmtiEnv.cpp
+--- a/src/share/vm/prims/jvmtiEnv.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/jvmtiEnv.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -290,7 +290,10 @@
class_definitions[index].klass = jcls;
}
@@ -4807,10 +4762,9 @@ index 4ac6b82..30b8e84 100644
return (op.check_error());
} /* end RedefineClasses */
-diff --git a/src/share/vm/prims/jvmtiExport.cpp b/src/share/vm/prims/jvmtiExport.cpp
-index ec8ede3..2bd5983 100644
---- a/src/share/vm/prims/jvmtiExport.cpp
-+++ b/src/share/vm/prims/jvmtiExport.cpp
+diff -r 882f6c762ac5 src/share/vm/prims/jvmtiExport.cpp
+--- a/src/share/vm/prims/jvmtiExport.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/jvmtiExport.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -2296,7 +2296,7 @@
// iterate over any code blob descriptors collected and post a
// DYNAMIC_CODE_GENERATED event to the profiler.
@@ -4820,10 +4774,9 @@ index ec8ede3..2bd5983 100644
// iterate over any code blob descriptors that we collected
if (_code_blobs != NULL) {
for (int i=0; i<_code_blobs->length(); i++) {
-diff --git a/src/share/vm/prims/jvmtiImpl.cpp b/src/share/vm/prims/jvmtiImpl.cpp
-index d3fa140..f4f8b57 100644
---- a/src/share/vm/prims/jvmtiImpl.cpp
-+++ b/src/share/vm/prims/jvmtiImpl.cpp
+diff -r 882f6c762ac5 src/share/vm/prims/jvmtiImpl.cpp
+--- a/src/share/vm/prims/jvmtiImpl.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/jvmtiImpl.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -286,6 +286,8 @@
void JvmtiBreakpoint::each_method_version_do(method_action meth_act) {
((methodOopDesc*)_method->*meth_act)(_bci);
@@ -4833,10 +4786,9 @@ index d3fa140..f4f8b57 100644
// add/remove breakpoint to/from versions of the method that
// 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 606be1c..ef4f380 100644
---- a/src/share/vm/prims/jvmtiRedefineClasses.cpp
-+++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp
+diff -r 882f6c762ac5 src/share/vm/prims/jvmtiRedefineClasses.cpp
+--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
@@ -4848,10 +4800,10 @@ index 606be1c..ef4f380 100644
#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"
@@ -4878,12 +4830,13 @@ index 606be1c..ef4f380 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);
@@ -4895,19 +4848,12 @@ index 606be1c..ef4f380 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);
+ Threads::set_wait_at_instrumentation_entry(false);
+ ml.notify_all();
- }
-- if (_class_defs == NULL) {
-- _res = JVMTI_ERROR_NULL_POINTER;
-- return false;
++ }
+
+ unlock_threads();
+ RC_TIMER_STOP(_timer_total);
@@ -4923,19 +4869,7 @@ index 606be1c..ef4f380 100644
+ tty->print_cr("Timing Epilogue: %d", _timer_vm_op_epilogue.milliseconds());
+ tty->print_cr("------------------------------------------------------------------");
+ tty->print_cr("Total Time: %d", _timer_total.milliseconds());
- }
-- 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;
++ }
+}
+
+// Searches for all affected classes and performs a sorting such that a supertype is always before a subtype.
@@ -4961,12 +4895,9 @@ index 606be1c..ef4f380 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);
@@ -5037,7 +4968,9 @@ index 606be1c..ef4f380 100644
+}
+
+// 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));
@@ -5047,16 +4980,13 @@ index 606be1c..ef4f380 100644
+
+ 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.
-- _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;
+ }
+- 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.
+ _new_classes = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<instanceKlassHandle>(5, true);
+ _result = load_new_class_versions(Thread::current());
+
@@ -5068,20 +4998,108 @@ index 606be1c..ef4f380 100644
+ RC_TIMER_STOP(_timer_prologue);
return false;
}
-
-- RC_TIMER_STOP(_timer_vm_op_prologue);
++
+ RC_TRACE(0x00000001, ("nearly finished"));
+ VM_GC_Operation::doit_prologue();
+ RC_TIMER_STOP(_timer_prologue);
+ RC_TRACE(0x00000001, ("doit_prologue finished!"));
- return true;
- }
-
--void VM_RedefineClasses::doit() {
-- Thread *thread = Thread::current();
++ return true;
++}
++
+// Checks basic properties of the arguments of the redefinition command.
+bool VM_RedefineClasses::check_arguments() {
++
++ 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++) {
+- 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);
++ }
++
++ return true;
++}
++
++jvmtiError VM_RedefineClasses::check_exception() const {
++ Thread* THREAD = Thread::current();
++ if (HAS_PENDING_EXCEPTION) {
++
++ Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
++ RC_TRACE(0x00000001, ("parse_stream exception: '%s'",
++ ex_name->as_C_string()));
++ 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()) {
++ 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;
+ }
+ }
+
+- // 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;
++}
++
++// Loads all new class versions and stores the instanceKlass handles in an array.
++jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {
++
++ ResourceMark rm(THREAD);
++
++ RC_TRACE(0x00000001, ("==================================================================="));
++ RC_TRACE(0x00000001, ("load new class versions (%d)",
++ _class_count));
++
++ // Retrieve an array of all classes that need to be redefined
++ GrowableArray<instanceKlassHandle> all_affected_klasses;
++ jvmtiError err = find_sorted_affected_classes(&all_affected_klasses);
++ if (err != JVMTI_ERROR_NONE) {
++ 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
@@ -5092,20 +5110,43 @@ index 606be1c..ef4f380 100644
- ("failed to remap shared readonly space to readwrite, private"));
- _res = JVMTI_ERROR_INTERNAL;
- return;
-- }
++
++ JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current());
++
++ _max_redefinition_flags = Klass::NoRedefinition;
++ jvmtiError result = JVMTI_ERROR_NONE;
++
++ for (int i=0; i<all_affected_klasses.length(); i++) {
++ RC_TRACE(0x00000002, ("Processing affected class %d of %d",
++ i+1, all_affected_klasses.length()));
++
++ instanceKlassHandle the_class = all_affected_klasses.at(i);
++ RC_TRACE(0x00000002, ("name=%s",
++ the_class->name()->as_C_string()));
++
++ 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, &not_changed)) != JVMTI_ERROR_NONE) {
++ RC_TRACE(0x00000001, ("Error finding class bytes: %d",
++ (int)error));
++ result = error;
++ 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++) {
- redefine_single_class(_class_defs[i].klass, _scratch_classes[i], thread);
-+ 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);
- }
+- }
- // 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();
@@ -5114,7 +5155,82 @@ index 606be1c..ef4f380 100644
-// always called for non-product bits.
-#ifdef PRODUCT
- if (RC_TRACE_ENABLED(0x00004000)) {
--#endif
++ 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_TRACE(0x00000002, ("Before resolving from stream"));
++
++ 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());
++ Symbol* the_class_sym = the_class->name();
++ ClassFileStream st((u1*) class_bytes, class_byte_count, (char *)"__VM_RedefineClasses__");
++ instanceKlassHandle new_class(THREAD, SystemDictionary::resolve_from_stream(the_class_sym,
++ the_class_loader,
++ protection_domain,
++ &st,
++ true,
++ the_class,
++ THREAD));
++
++ not_changed = false;
++
++ RC_TIMER_STOP(_timer_class_loading);
++ RC_TIMER_START(_timer_prologue);
++
++ RC_TRACE(0x00000002, ("After resolving class from stream!"));
++ // Clear class_being_redefined just to be sure.
++ state->clear_class_being_redefined();
++
++ result = check_exception();
++ if (result != JVMTI_ERROR_NONE) break;
++
++#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, "");
++
++
++ objArrayOop k_interfaces = new_class->local_interfaces();
++ for (int j=0; j<k_interfaces->length(); j++) {
++ assert(((klassOop)k_interfaces->obj_at(j))->klass_part()->is_newest_version(), "just checking");
++ }
++
++ if (!THREAD->is_Compiler_thread()) {
++
++ RC_TRACE(0x00000002, ("name=%s loader="INTPTR_FORMAT" protection_domain="INTPTR_FORMAT" ",
++ the_class->name()->as_C_string(),
++ (address)(the_class->class_loader()),
++ (address)(the_class->protection_domain())));
++ // If we are on the compiler thread, we must not try to resolve a class.
++ klassOop 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()->klass_part()->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
- RC_TRACE_WITH_THREAD(0x00004000, thread, ("calling check_class"));
- SystemDictionary::classes_do(check_class, thread);
-#ifdef PRODUCT
@@ -5153,9 +5269,9 @@ index 606be1c..ef4f380 100644
- if (the_class_oop == NULL || !Klass::cast(the_class_oop)->oop_is_instance()) {
- return false;
- }
- return true;
- }
-
+- 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
@@ -5170,21 +5286,10 @@ index 606be1c..ef4f380 100644
-void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp,
- int scratch_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p,
- TRAPS) {
-+jvmtiError VM_RedefineClasses::check_exception() const {
-+ Thread* THREAD = Thread::current();
-+ if (HAS_PENDING_EXCEPTION) {
-
+-
- // append is different depending on entry tag type
- switch (scratch_cp->tag_at(scratch_i).value()) {
-+ Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
-+ RC_TRACE(0x00000001, ("parse_stream exception: '%s'",
-+ ex_name->as_C_string()));
-+ if (TraceRedefineClasses >= 1) {
-+ java_lang_Throwable::print(PENDING_EXCEPTION, tty);
-+ tty->print_cr("");
-+ }
-+ CLEAR_PENDING_EXCEPTION;
-
+-
- // 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
@@ -5205,7 +5310,14 @@ index 606be1c..ef4f380 100644
- // 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(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()));
+ }
- (*merge_cp_length_p)++;
- } break;
-
@@ -5317,25 +5429,124 @@ index 606be1c..ef4f380 100644
- break;
- default:
- guarantee(false, "bad switch");
-- break;
-- }
++ }
++
++ // 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 if (AllowAdvancedClassRedefinition) {
++ redefinition_flags = calculate_redefinition_flags(new_class);
++ } else {
++ jvmtiError allowed = check_redefinition_allowed(new_class);
++ if (allowed != JVMTI_ERROR_NONE) {
++ RC_TRACE(0x00000001, ("Error redefinition not allowed!"));
++ result = allowed;
+ 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));
-- }
++ redefinition_flags = Klass::ModifyClass;
++ }
++
++ if (new_class->super() != NULL) {
++ redefinition_flags = redefinition_flags | new_class->super()->klass_part()->redefinition_flags();
++ }
++
++ for (int j=0; j<new_class->local_interfaces()->length(); j++) {
++ redefinition_flags = redefinition_flags | ((klassOop)new_class->local_interfaces()->obj_at(j))->klass_part()->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 {
++ assert(new_class->layout_helper() >> 1 == new_class->old_version()->klass_part()->layout_helper() >> 1, "must be equal");
++ assert(new_class->fields()->length() == ((instanceKlass*)new_class->old_version()->klass_part())->fields()->length(), "must be equal");
++
++ fieldDescriptor fd_new;
++ fieldDescriptor fd_old;
++ for (JavaFieldStream fs(new_class); !fs.done(); fs.next()) {
++ fd_new.initialize(new_class(), fs.index());
++ fd_old.initialize(new_class->old_version(), fs.index());
++ transfer_special_access_flags(&fd_old, &fd_new);
+ }
- 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 (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()));
+ }
-
- 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);
-- }
++ }
++
++#ifdef ASSERT
++ assert(new_class->super() == NULL || new_class->super()->klass_part()->new_version() == NULL, "Super klass must be newest version!");
++
++ the_class->vtable()->verify(tty);
++ new_class->vtable()->verify(tty);
++#endif
++
++ RC_TRACE(0x00000002, ("Verification done!"));
++
++ if (i == all_affected_klasses.length() - 1) {
++
++ // This was the last class processed => check if additional classes have been loaded in the meantime
++
++ RC_TIMER_STOP(_timer_prologue);
++ lock_threads();
++ RC_TIMER_START(_timer_prologue);
++
++ for (int j=0; j<all_affected_klasses.length(); j++) {
++
++ klassOop initial_klass = all_affected_klasses.at(j)();
++ Klass *initial_subklass = initial_klass->klass_part()->subklass();
++ Klass *cur_klass = initial_subklass;
++ while(cur_klass != NULL) {
++
++ if(cur_klass->oop_is_instance() && cur_klass->is_newest_version()) {
++ instanceKlassHandle handle(THREAD, cur_klass->as_klassOop());
++ if (!all_affected_klasses.contains(handle)) {
++
++ int k = i + 1;
++ for (; k<all_affected_klasses.length(); k++) {
++ if (all_affected_klasses.at(k)->is_subtype_of(cur_klass->as_klassOop())) {
++ break;
++ }
++ }
++ all_affected_klasses.insert_before(k, handle);
++ RC_TRACE(0x00000002, ("Adding newly loaded class to affected classes: %s",
++ cur_klass->name()->as_C_string()));
++ }
++ }
++
++ cur_klass = cur_klass->next_sibling();
++ }
+ }
- (*merge_cp_length_p)++;
- } break;
-
@@ -5453,29 +5664,16 @@ index 606be1c..ef4f380 100644
- // Found a matching entry somewhere else in *merge_cp_p so just need a mapping entry.
- new_ref_i = found_i;
- map_index(scratch_cp, ref_i, found_i);
-+ 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 {
+- } else {
- // no match found so we have to append this entry to *merge_cp_p
- append_entry(scratch_cp, 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_ref_i = *merge_cp_length_p - 1;
-+ // Just in case more exceptions can be thrown..
-+ return JVMTI_ERROR_FAILS_VERIFICATION;
- }
- }
-
+- }
+- }
+-
- return new_ref_i;
-} // end find_or_append_indirect_entry()
-
@@ -5569,9 +5767,16 @@ index 606be1c..ef4f380 100644
- RC_TRACE_WITH_THREAD(0x00040000, THREAD,
- ("operands_index_map[%d]: old=%d new=%d", count, i, value));
- count++;
-- }
-- }
-- }
++
++ int new_count = all_affected_klasses.length() - 1 - i;
++ if (new_count != 0) {
++
++ unlock_threads();
++ RC_TRACE(0x00000001, ("Found new number of affected classes: %d",
++ new_count));
+ }
+ }
+ }
- // Clean-up
- _operands_index_map_p = NULL;
- _operands_cur_length = 0;
@@ -5593,257 +5798,6 @@ index 606be1c..ef4f380 100644
- 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);
-+ return JVMTI_ERROR_NONE;
- }
-
-+// Loads all new class versions and stores the instanceKlass handles in an array.
-+jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {
-
--jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
-- instanceKlassHandle the_class,
-- instanceKlassHandle scratch_class) {
-+ ResourceMark rm(THREAD);
-+
-+ RC_TRACE(0x00000001, ("==================================================================="));
-+ RC_TRACE(0x00000001, ("load new class versions (%d)",
-+ _class_count));
-+
-+ // Retrieve an array of all classes that need to be redefined
-+ GrowableArray<instanceKlassHandle> all_affected_klasses;
-+ jvmtiError err = find_sorted_affected_classes(&all_affected_klasses);
-+ 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<all_affected_klasses.length(); i++) {
-+ RC_TRACE(0x00000002, ("Processing affected class %d of %d",
-+ i+1, all_affected_klasses.length()));
-+
-+ instanceKlassHandle the_class = all_affected_klasses.at(i);
-+ RC_TRACE(0x00000002, ("name=%s",
-+ the_class->name()->as_C_string()));
-+
-+ 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, &not_changed)) != JVMTI_ERROR_NONE) {
-+ RC_TRACE(0x00000001, ("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_TRACE(0x00000002, ("Before resolving from stream"));
-+
-+ 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());
-+ Symbol* the_class_sym = the_class->name();
-+ ClassFileStream st((u1*) class_bytes, class_byte_count, (char *)"__VM_RedefineClasses__");
-+ instanceKlassHandle new_class(THREAD, SystemDictionary::resolve_from_stream(the_class_sym,
-+ the_class_loader,
-+ protection_domain,
-+ &st,
-+ true,
-+ the_class,
-+ THREAD));
-+
-+ not_changed = false;
-+
-+ RC_TIMER_STOP(_timer_class_loading);
-+ RC_TIMER_START(_timer_prologue);
-+
-+ RC_TRACE(0x00000002, ("After resolving class from stream!"));
-+ // Clear class_being_redefined just to be sure.
-+ state->clear_class_being_redefined();
-+
-+ result = check_exception();
-+ if (result != JVMTI_ERROR_NONE) break;
-+
-+#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, "");
-+
-+
-+ objArrayOop k_interfaces = new_class->local_interfaces();
-+ for (int j=0; j<k_interfaces->length(); j++) {
-+ assert(((klassOop)k_interfaces->obj_at(j))->klass_part()->is_newest_version(), "just checking");
-+ }
-+
-+ if (!THREAD->is_Compiler_thread()) {
-+
-+ RC_TRACE(0x00000002, ("name=%s loader="INTPTR_FORMAT" protection_domain="INTPTR_FORMAT" ",
-+ the_class->name()->as_C_string(),
-+ (address)(the_class->class_loader()),
-+ (address)(the_class->protection_domain())));
-+ // If we are on the compiler thread, we must not try to resolve a class.
-+ klassOop 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()->klass_part()->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 if (AllowAdvancedClassRedefinition) {
-+ redefinition_flags = calculate_redefinition_flags(new_class);
-+ } else {
-+ jvmtiError allowed = check_redefinition_allowed(new_class);
-+ if (allowed != JVMTI_ERROR_NONE) {
-+ RC_TRACE(0x00000001, ("Error redefinition not allowed!"));
-+ result = allowed;
-+ break;
-+ }
-+ redefinition_flags = Klass::ModifyClass;
-+ }
-+
-+ if (new_class->super() != NULL) {
-+ redefinition_flags = redefinition_flags | new_class->super()->klass_part()->redefinition_flags();
-+ }
-+
-+ for (int j=0; j<new_class->local_interfaces()->length(); j++) {
-+ redefinition_flags = redefinition_flags | ((klassOop)new_class->local_interfaces()->obj_at(j))->klass_part()->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 {
-+ assert(new_class->layout_helper() >> 1 == new_class->old_version()->klass_part()->layout_helper() >> 1, "must be equal");
-+ assert(new_class->fields()->length() == ((instanceKlass*)new_class->old_version()->klass_part())->fields()->length(), "must be equal");
-+
-+ fieldDescriptor fd_new;
-+ fieldDescriptor fd_old;
-+ for (JavaFieldStream fs(new_class); !fs.done(); fs.next()) {
-+ fd_new.initialize(new_class(), fs.index());
-+ fd_old.initialize(new_class->old_version(), fs.index());
-+ transfer_special_access_flags(&fd_old, &fd_new);
-+ }
-+ }
-+
-+ 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()));
-+ }
-+ }
-+
-+#ifdef ASSERT
-+ assert(new_class->super() == NULL || new_class->super()->klass_part()->new_version() == NULL, "Super klass must be newest version!");
-+
-+ the_class->vtable()->verify(tty);
-+ new_class->vtable()->verify(tty);
-+#endif
-+
-+ RC_TRACE(0x00000002, ("Verification done!"));
-+
-+ if (i == all_affected_klasses.length() - 1) {
-+
-+ // This was the last class processed => check if additional classes have been loaded in the meantime
-+
-+ RC_TIMER_STOP(_timer_prologue);
-+ lock_threads();
-+ RC_TIMER_START(_timer_prologue);
-+
-+ for (int j=0; j<all_affected_klasses.length(); j++) {
-+
-+ klassOop initial_klass = all_affected_klasses.at(j)();
-+ Klass *initial_subklass = initial_klass->klass_part()->subklass();
-+ Klass *cur_klass = initial_subklass;
-+ while(cur_klass != NULL) {
-+
-+ if(cur_klass->oop_is_instance() && cur_klass->is_newest_version()) {
-+ instanceKlassHandle handle(THREAD, cur_klass->as_klassOop());
-+ if (!all_affected_klasses.contains(handle)) {
-+
-+ int k = i + 1;
-+ for (; k<all_affected_klasses.length(); k++) {
-+ if (all_affected_klasses.at(k)->is_subtype_of(cur_klass->as_klassOop())) {
-+ break;
-+ }
-+ }
-+ all_affected_klasses.insert_before(k, handle);
-+ RC_TRACE(0x00000002, ("Adding newly loaded class to affected classes: %s",
-+ cur_klass->name()->as_C_string()));
-+ }
-+ }
-+
-+ cur_klass = cur_klass->next_sibling();
-+ }
-+ }
-+
-+ int new_count = all_affected_klasses.length() - 1 - i;
-+ if (new_count != 0) {
-+
-+ unlock_threads();
-+ RC_TRACE(0x00000001, ("Found new number of affected classes: %d",
-+ new_count));
-+ }
-+ }
-+ }
+
+ if (result != JVMTI_ERROR_NONE) {
+ rollback();
@@ -5896,8 +5850,12 @@ index 606be1c..ef4f380 100644
+
+ RC_TRACE(0x00000001, ("Finished verification!"));
+ return JVMTI_ERROR_NONE;
-+}
-+
+ }
+
+-
+-jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
+- instanceKlassHandle the_class,
+- instanceKlassHandle scratch_class) {
+void VM_RedefineClasses::lock_threads() {
+
+ RC_TIMER_START(_timer_wait_for_locks);
@@ -6070,12 +6028,11 @@ index 606be1c..ef4f380 100644
++oi; // advance to next old method
break;
default:
-@@ -833,2120 +880,2265 @@
+@@ -833,2121 +880,2266 @@
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.
@@ -6083,6 +6040,8 @@ index 606be1c..ef4f380 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;
+
+
@@ -6104,29 +6063,51 @@ index 606be1c..ef4f380 100644
- // not happen in regular constant pool merging use, but it can
- // happen if a corrupt annotation is processed.
- return 0;
-- }
+ int i;
-
-- int value = _index_map_p->at(old_index);
-- if (value == -1) {
-- // the old_index is not mapped
-- return 0;
-- }
++
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Check superclasses
+ assert(new_class->super() == NULL || new_class->super()->klass_part()->is_newest_version(), "");
+ if (the_class->super() != new_class->super()) {
+ // Super class changed
-
-- return value;
--} // end find_new_index()
++
+ klassOop cur_klass = the_class->super();
+ while (cur_klass != NULL) {
+ if (!new_class->is_subclass_of(cur_klass->klass_part()->newest_version())) {
+ RC_TRACE(0x00000002, ("Removed super class %s",
+ cur_klass->klass_part()->name()->as_C_string()));
+ result = result | Klass::RemoveSuperType | Klass::ModifyInstances | Klass::ModifyClass;
++
++ if (!cur_klass->klass_part()->has_subtype_changed()) {
++ RC_TRACE(0x00000002, ("Subtype changed of class %s",
++ cur_klass->klass_part()->name()->as_C_string()));
++ cur_klass->klass_part()->set_subtype_changed(true);
++ }
++ }
++
++ cur_klass = cur_klass->klass_part()->super();
++ }
++
++ cur_klass = new_class->super();
++ while (cur_klass != NULL) {
++ if (!the_class->is_subclass_of(cur_klass->klass_part()->old_version())) {
++ RC_TRACE(0x00000002, ("Added super class %s",
++ cur_klass->klass_part()->name()->as_C_string()));
++ result = result | Klass::ModifyClass | Klass::ModifyInstances;
++ }
++ 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()
+-
-
-// Find new bootstrap specifier index value for old bootstrap specifier index
-// value by seaching the index map. Returns zero (-1) if there is no mapped
@@ -6280,349 +6261,9 @@ index 606be1c..ef4f380 100644
- 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;
-+ if (!cur_klass->klass_part()->has_subtype_changed()) {
-+ RC_TRACE(0x00000002, ("Subtype changed of class %s",
-+ cur_klass->klass_part()->name()->as_C_string()));
-+ cur_klass->klass_part()->set_subtype_changed(true);
- }
- }
-+
-+ cur_klass = cur_klass->klass_part()->super();
- }
-
-- // 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;
-- }
--
-- // 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;
-+ cur_klass = new_class->super();
-+ while (cur_klass != NULL) {
-+ if (!the_class->is_subclass_of(cur_klass->klass_part()->old_version())) {
-+ RC_TRACE(0x00000002, ("Added super class %s",
-+ cur_klass->klass_part()->name()->as_C_string()));
-+ result = result | Klass::ModifyClass | Klass::ModifyInstances;
- }
-- }
--
-- res = merge_cp_and_rewrite(the_class, scratch_class, THREAD);
-- if (res != JVMTI_ERROR_NONE) {
-- return res;
-- }
--
-- 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);
-- }
--
-- 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;
-- }
-- }
-- }
--
-- 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()
--
--
--// Map old_index to new_index as needed.
--void VM_RedefineClasses::map_operand_index(int old_index, int new_index) {
-- if (find_new_operand_index(old_index) != -1) {
-- // old_index is already mapped
-- return;
-- }
--
-- if (old_index == new_index) {
-- // no mapping is needed
-- return;
-- }
--
-- _operands_index_map_p->at_put(old_index, new_index);
-- _operands_index_map_count++;
--
-- RC_TRACE(0x00040000, ("mapped bootstrap specifier at index %d to %d", 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
--// in *merge_cp_p. Also creates a map of indices from entries in
--// scratch_cp to the corresponding entry in *merge_cp_p. Index map
--// entries are only created for entries in scratch_cp that occupy a
--// different location in *merged_cp_p.
--bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp,
-- constantPoolHandle scratch_cp, constantPoolHandle *merge_cp_p,
-- int *merge_cp_length_p, TRAPS) {
--
-- if (merge_cp_p == NULL) {
-- assert(false, "caller must provide scatch constantPool");
-- return false; // robustness
-- }
-- if (merge_cp_length_p == NULL) {
-- assert(false, "caller must provide scatch CP length");
-- return false; // robustness
-- }
-- // Worst case we need old_cp->length() + scratch_cp()->length(),
-- // but the caller might be smart so make sure we have at least
-- // the minimum.
-- if ((*merge_cp_p)->length() < old_cp->length()) {
-- assert(false, "merge area too small");
-- return false; // robustness
-- }
--
-- RC_TRACE_WITH_THREAD(0x00010000, THREAD,
-- ("old_cp_len=%d, scratch_cp_len=%d", old_cp->length(),
-- scratch_cp->length()));
--
-- {
-- // Pass 0:
-- // The old_cp is copied to *merge_cp_p; this means that any code
-- // using old_cp does not have to change. This work looks like a
-- // perfect fit for constantPoolOop::copy_cp_to(), but we need to
-- // handle one special case:
-- // - revert JVM_CONSTANT_Class to JVM_CONSTANT_UnresolvedClass
-- // This will make verification happy.
--
-- int old_i; // index into old_cp
--
-- // index zero (0) is not used in constantPools
-- for (old_i = 1; old_i < old_cp->length(); old_i++) {
-- // leave debugging crumb
-- jbyte old_tag = old_cp->tag_at(old_i).value();
-- switch (old_tag) {
-- case JVM_CONSTANT_Class:
-- case JVM_CONSTANT_UnresolvedClass:
-- // revert the copy to JVM_CONSTANT_UnresolvedClass
-- // May be resolving while calling this so do the same for
-- // JVM_CONSTANT_UnresolvedClass (klass_name_at() deals with transition)
-- (*merge_cp_p)->unresolved_klass_at_put(old_i,
-- old_cp->klass_name_at(old_i));
-- break;
--
-- case JVM_CONSTANT_Double:
-- case JVM_CONSTANT_Long:
-- // just copy the entry to *merge_cp_p, but double and long take
-- // two constant pool entries
-- constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
-- old_i++;
-- break;
--
-- default:
-- // just copy the entry to *merge_cp_p
-- constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
-- break;
-- }
-- } // end for each old_cp entry
--
-- constantPoolOopDesc::copy_operands(old_cp, *merge_cp_p, CHECK_0);
-- (*merge_cp_p)->extend_operands(scratch_cp, CHECK_0);
--
-- // 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;
-- }
--
-- // 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 scratch_i; // index into scratch_cp
-- {
-- // Pass 1a:
-- // Compare scratch_cp entries to the old_cp entries that we have
-- // already copied to *merge_cp_p. In this pass, we are eliminating
-- // exact duplicates (matching entry at same index) so we only
-- // compare entries in the common indice range.
-- int increment = 1;
-- int pass1a_length = MIN2(old_cp->length(), scratch_cp->length());
-- for (scratch_i = 1; scratch_i < pass1a_length; scratch_i += increment) {
-- switch (scratch_cp->tag_at(scratch_i).value()) {
-- case JVM_CONSTANT_Double:
-- case JVM_CONSTANT_Long:
-- // double and long take two constant pool entries
-- increment = 2;
-- break;
--
-- default:
-- increment = 1;
-- break;
-- }
--
-- bool match = scratch_cp->compare_entry_to(scratch_i, *merge_cp_p,
-- scratch_i, CHECK_0);
-- if (match) {
-- // found a match at the same index so nothing more to do
-- continue;
-- } else if (is_unresolved_class_mismatch(scratch_cp, scratch_i,
-- *merge_cp_p, scratch_i)) {
-- // The mismatch in compare_entry_to() above is because of a
-- // resolved versus unresolved class entry at the same index
-- // with the same string value. Since Pass 0 reverted any
-- // class entries to unresolved class entries in *merge_cp_p,
-- // we go with the unresolved class entry.
-- continue;
-- } else if (is_unresolved_string_mismatch(scratch_cp, scratch_i,
-- *merge_cp_p, scratch_i)) {
-- // The mismatch in compare_entry_to() above is because of a
-- // resolved versus unresolved string entry at the same index
-- // with the same string value. We can live with whichever
-- // happens to be at scratch_i in *merge_cp_p.
-- continue;
-- }
--
-- int found_i = scratch_cp->find_matching_entry(scratch_i, *merge_cp_p,
-- CHECK_0);
-- if (found_i != 0) {
-- guarantee(found_i != scratch_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.
-- map_index(scratch_cp, scratch_i, found_i);
-- continue;
-- }
--
-- // The find_matching_entry() call above could fail to find a match
-- // due to a resolved versus unresolved class or string entry situation
-- // like we solved above with the is_unresolved_*_mismatch() calls.
-- // However, we would have to call is_unresolved_*_mismatch() over
-- // all of *merge_cp_p (potentially) and that doesn't seem to be
-- // worth the time.
--
-- // 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);
-+ cur_klass = cur_klass->klass_part()->super();
- }
- }
-
-- RC_TRACE_WITH_THREAD(0x00020000, THREAD,
-- ("after pass 1a: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
-- *merge_cp_length_p, scratch_i, _index_map_count));
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Check interfaces
-
-- if (scratch_i < scratch_cp->length()) {
-- // Pass 1b:
-- // old_cp is smaller than scratch_cp so there are entries in
-- // scratch_cp that we have not yet processed. We take care of
-- // those now.
-- int increment = 1;
-- for (; scratch_i < scratch_cp->length(); scratch_i += increment) {
-- switch (scratch_cp->tag_at(scratch_i).value()) {
-- case JVM_CONSTANT_Double:
-- case JVM_CONSTANT_Long:
-- // double and long take two constant pool entries
-- increment = 2;
-- break;
--
-- default:
-- increment = 1;
-- break;
++
+ // Interfaces removed?
+ objArrayOop old_interfaces = the_class->transitive_interfaces();
+ for (i = 0; i<old_interfaces->length(); i++) {
@@ -6637,89 +6278,21 @@ index 606be1c..ef4f380 100644
+ old_interface->name()->as_C_string()));
+ old_interface->set_subtype_changed(true);
}
--
-- int found_i =
-- scratch_cp->find_matching_entry(scratch_i, *merge_cp_p, CHECK_0);
-- if (found_i != 0) {
-- // Found a matching entry somewhere else in *merge_cp_p so
-- // just need a mapping entry.
-- map_index(scratch_cp, scratch_i, found_i);
-- continue;
-- }
--
-- // 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);
}
-
-- 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));
-- }
-- finalize_operands_merge(*merge_cp_p, THREAD);
--
-- return true;
--} // end merge_constant_pools()
--
--
--// Merge constant pools between the_class and scratch_class and
--// potentially rewrite bytecodes in scratch_class to use the merged
--// constant pool.
--jvmtiError VM_RedefineClasses::merge_cp_and_rewrite(
-- instanceKlassHandle the_class, instanceKlassHandle scratch_class,
-- TRAPS) {
-- // worst case merged constant pool length is old and new combined
-- int merge_cp_length = the_class->constants()->length()
-- + scratch_class->constants()->length();
--
-- constantPoolHandle old_cp(THREAD, the_class->constants());
-- constantPoolHandle scratch_cp(THREAD, scratch_class->constants());
--
-- // Constant pools are not easily reused so we allocate a new one
-- // each time.
-- // merge_cp is created unsafe for concurrent GC processing. It
-- // should be marked safe before discarding it. Even though
-- // garbage, if it crosses a card boundary, it may be scanned
-- // in order to find the start of the first complete object on the card.
-- constantPoolHandle merge_cp(THREAD,
-- oopFactory::new_constantPool(merge_cp_length,
-- oopDesc::IsUnsafeConc,
-- THREAD));
-- int orig_length = old_cp->orig_length();
-- if (orig_length == 0) {
-- // This old_cp is an actual original constant pool. We save
-- // the original length in the merged constant pool so that
-- // merge_constant_pools() can be more efficient. If a constant
-- // pool has a non-zero orig_length() value, then that constant
-- // pool was created by a merge operation in RedefineClasses.
-- merge_cp->set_orig_length(old_cp->length());
-- } else {
-- // This old_cp is a merged constant pool from a previous
-- // RedefineClasses() calls so just copy the orig_length()
-- // value.
-- merge_cp->set_orig_length(old_cp->orig_length());
- }
-
-- ResourceMark rm(THREAD);
-- _index_map_count = 0;
-- _index_map_p = new intArray(scratch_cp->length(), -1);
--
-- _operands_cur_length = constantPoolOopDesc::operand_array_length(old_cp->operands());
-- _operands_index_map_count = 0;
-- _operands_index_map_p = new intArray(
-- constantPoolOopDesc::operand_array_length(scratch_cp->operands()), -1);
--
-- // reference to the cp holder is needed for copy_operands()
-- merge_cp->set_pool_holder(scratch_class());
-- bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp,
-- &merge_cp_length, THREAD);
-- merge_cp->set_pool_holder(NULL);
--
-- if (!result) {
-- // The merge can fail due to memory allocation failure or due
-- // to robustness checks.
-- return JVMTI_ERROR_INTERNAL;
+- // 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++) {
@@ -6728,28 +6301,16 @@ index 606be1c..ef4f380 100644
+ RC_TRACE(0x00000002, ("Added interface %s",
+ ((klassOop)new_interfaces->obj_at(i))->klass_part()->name()->as_C_string()));
+ }
- }
-
-- RC_TRACE_WITH_THREAD(0x00010000, THREAD,
-- ("merge_cp_len=%d, index_map_len=%d", merge_cp_length, _index_map_count));
-
-- if (_index_map_count == 0) {
-- // there is nothing to map between the new and merged constant pools
++ }
++
++
+ // 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?
+ }
-
-- if (old_cp->length() == scratch_cp->length()) {
-- // The old and new constant pools are the same length and the
-- // index map is empty. This means that the three constant pools
-- // are equivalent (but not the same). Unfortunately, the new
-- // constant pool has not gone through link resolution nor have
-- // the new class bytecodes gone through constant pool cache
-- // rewriting so we can't use the old constant pool with the new
-- // class.
++
+ // Check if the number, names, types and order of fields declared in these classes
+ // are the same.
+ JavaFieldStream old_fs(the_class);
@@ -6774,22 +6335,11 @@ index 606be1c..ef4f380 100644
+ result = result | Klass::ModifyInstances;
+ }
+ }
-
-- merge_cp()->set_is_conc_safe(true);
-- merge_cp = constantPoolHandle(); // toss the merged constant pool
-- } else if (old_cp->length() < scratch_cp->length()) {
-- // The old constant pool has fewer entries than the new constant
-- // pool and the index map is empty. This means the new constant
-- // pool is a superset of the old constant pool. However, the old
-- // class bytecodes have already gone through constant pool cache
-- // rewriting so we can't use the new constant pool with the old
-- // class.
++
+ if (!old_fs.done() || !new_fs.done()) {
+ result = result | Klass::ModifyInstances;
+ }
-
-- merge_cp()->set_is_conc_safe(true);
-- merge_cp = constantPoolHandle(); // toss the merged constant pool
++
+ // 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
@@ -6830,11 +6380,7 @@ index 606be1c..ef4f380 100644
+ // Old method, at the end, is deleted
+ k_old_method = (methodOop) k_old_methods->obj_at(oi);
+ method_was = deleted;
- } else {
-- // The old constant pool has more entries than the new constant
-- // pool and the index map is empty. This means that both the old
-- // and merged constant pools are supersets of the new constant
-- // pool.
++ } else {
+ // There are more methods in both the old and new lists
+ k_old_method = (methodOop) k_old_methods->obj_at(oi);
+ k_new_method = (methodOop) k_new_methods->obj_at(ni);
@@ -6843,7 +6389,8 @@ index 606be1c..ef4f380 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()) {
@@ -6869,27 +6416,7 @@ index 606be1c..ef4f380 100644
+ break;
+ }
+ }
-
-- // Replace the new constant pool with a shrunken copy of the
-- // merged constant pool; the previous new constant pool will
-- // get GCed.
-- set_new_constant_pool(scratch_class, merge_cp, merge_cp_length,
-- THREAD);
-- // drop local ref to the merged constant pool
-- merge_cp()->set_is_conc_safe(true);
-- merge_cp = constantPoolHandle();
-- }
-- } else {
-- if (RC_TRACE_ENABLED(0x00040000)) {
-- // don't want to loop unless we are tracing
-- int count = 0;
-- for (int i = 1; i < _index_map_p->length(); i++) {
-- int value = _index_map_p->at(i);
--
-- if (value != -1) {
-- RC_TRACE_WITH_THREAD(0x00040000, THREAD,
-- ("index_map[%d]: old=%d new=%d", count, i, value));
-- count++;
++
+ if (nj >= n_new_methods) {
+ // reached the end without a match; so method was deleted
+ method_was = deleted;
@@ -6897,10 +6424,15 @@ index 606be1c..ef4f380 100644
}
}
-- // 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;
+- // 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
@@ -6911,87 +6443,30 @@ index 606be1c..ef4f380 100644
+ result = result | Klass::ModifyClass;
}
-
-- // 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,
-- THREAD);
-- merge_cp()->set_is_conc_safe(true);
-- }
-- 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
-- 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
-- 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
-- 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
-- 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
-- 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;
--} // 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;
-- }
+- // 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);
+- }
-
-- // 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());
-+ {
+- 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) {
@@ -7005,8 +6480,12 @@ index 606be1c..ef4f380 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));
@@ -7023,13 +6502,32 @@ index 606be1c..ef4f380 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) {
@@ -7059,10 +6557,9 @@ index 606be1c..ef4f380 100644
+ break;
+ default:
+ ShouldNotReachHere();
- }
- }
-
-- return true;
++ }
++ }
++
+ if (new_class()->size() != new_class->old_version()->size()) {
+ result |= Klass::ModifyClassSize;
+ }
@@ -7078,72 +6575,28 @@ index 606be1c..ef4f380 100644
+
+ // (tw) Check method bodies to be able to return NoChange?
+ return result;
- }
-
++}
++
+void VM_RedefineClasses::calculate_instance_update_information(klassOop new_version) {
-
--// Rewrite constant pool references in 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) {
++
+ class UpdateFieldsEvolutionClosure : public FieldEvolutionClosure {
-
-- *new_method_p = methodHandle(); // default is no new method
++
+ private:
-
-- // 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;
++
+ GrowableArray<int> info;
+ int curPosition;
+ bool copy_backwards;
-
-- // Bytecodes and their length
-- address code_base = method->code_base();
-- int code_length = method->code_size();
++
+ public:
-
-- 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);
++
+ bool does_copy_backwards() {
+ return copy_backwards;
- }
-
-- assert(bc_length != 0, "impossible bytecode length");
++ }
++
+ UpdateFieldsEvolutionClosure(klassOop klass) {
-
-- switch (c) {
-- case Bytecodes::_ldc:
-- {
-- int cp_index = *(bcp + 1);
-- int new_index = find_new_index(cp_index);
++
+ int base_offset = instanceOopDesc::base_offset_in_bytes();
-
-- 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;
++
+ 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);
+ }
@@ -7221,36 +6674,15 @@ index 606be1c..ef4f380 100644
+ case T_ARRAY:
+ if (UseCompressedOops) {
+ size = sizeof(narrowOop);
- } 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);
++ } else {
+ size = (sizeof(oop));
+ }
+ break;
-
-- Relocator rc(method, NULL /* no RelocatorListener needed */);
-- methodHandle m;
-- {
-- Pause_No_Safepoint_Verifier pnsv(&nsv);
++
+ default:
+ ShouldNotReachHere();
+ }
-
-- // 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");
++
+ assert(size > 0, "");
+ return size;
+
@@ -7432,60 +6864,10 @@ index 606be1c..ef4f380 100644
+ element->blueprint()->name()->as_C_string()));
+ _result = false;
+ 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::_invokedynamic : // 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;
++ }
+
+ } else {
+ Pair<int, klassOop> *cur = obj->klass()->klass_part()->type_check_information();
@@ -7495,12 +6877,391 @@ index 606be1c..ef4f380 100644
+ check_field(obj, (*cur).left(), (*cur).right());
+ cur++;
+ }
-+ }
-+ }
+ }
+ }
}
-- } // end for each bytecode
--} // end rewrite_cp_refs_in_method()
+- 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()
+-
+-
+-// Map old_index to new_index as needed.
+-void VM_RedefineClasses::map_operand_index(int old_index, int new_index) {
+- if (find_new_operand_index(old_index) != -1) {
+- // old_index is already mapped
+- return;
+- }
+-
+- if (old_index == new_index) {
+- // no mapping is needed
+- return;
+- }
+-
+- _operands_index_map_p->at_put(old_index, new_index);
+- _operands_index_map_count++;
+-
+- RC_TRACE(0x00040000, ("mapped bootstrap specifier at index %d to %d", 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
+-// in *merge_cp_p. Also creates a map of indices from entries in
+-// scratch_cp to the corresponding entry in *merge_cp_p. Index map
+-// entries are only created for entries in scratch_cp that occupy a
+-// different location in *merged_cp_p.
+-bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp,
+- constantPoolHandle scratch_cp, constantPoolHandle *merge_cp_p,
+- int *merge_cp_length_p, TRAPS) {
+-
+- if (merge_cp_p == NULL) {
+- assert(false, "caller must provide scatch constantPool");
+- return false; // robustness
+- }
+- if (merge_cp_length_p == NULL) {
+- assert(false, "caller must provide scatch CP length");
+- return false; // robustness
+- }
+- // Worst case we need old_cp->length() + scratch_cp()->length(),
+- // but the caller might be smart so make sure we have at least
+- // the minimum.
+- if ((*merge_cp_p)->length() < old_cp->length()) {
+- assert(false, "merge area too small");
+- return false; // robustness
+- }
+-
+- RC_TRACE_WITH_THREAD(0x00010000, THREAD,
+- ("old_cp_len=%d, scratch_cp_len=%d", old_cp->length(),
+- scratch_cp->length()));
+-
+- {
+- // Pass 0:
+- // The old_cp is copied to *merge_cp_p; this means that any code
+- // using old_cp does not have to change. This work looks like a
+- // perfect fit for constantPoolOop::copy_cp_to(), but we need to
+- // handle one special case:
+- // - revert JVM_CONSTANT_Class to JVM_CONSTANT_UnresolvedClass
+- // This will make verification happy.
+-
+- int old_i; // index into old_cp
+-
+- // index zero (0) is not used in constantPools
+- for (old_i = 1; old_i < old_cp->length(); old_i++) {
+- // leave debugging crumb
+- jbyte old_tag = old_cp->tag_at(old_i).value();
+- switch (old_tag) {
+- case JVM_CONSTANT_Class:
+- case JVM_CONSTANT_UnresolvedClass:
+- // revert the copy to JVM_CONSTANT_UnresolvedClass
+- // May be resolving while calling this so do the same for
+- // JVM_CONSTANT_UnresolvedClass (klass_name_at() deals with transition)
+- (*merge_cp_p)->unresolved_klass_at_put(old_i,
+- old_cp->klass_name_at(old_i));
+- break;
+-
+- case JVM_CONSTANT_Double:
+- case JVM_CONSTANT_Long:
+- // just copy the entry to *merge_cp_p, but double and long take
+- // two constant pool entries
+- constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
+- old_i++;
+- break;
+-
+- default:
+- // just copy the entry to *merge_cp_p
+- constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
+- break;
+- }
+- } // end for each old_cp entry
+-
+- constantPoolOopDesc::copy_operands(old_cp, *merge_cp_p, CHECK_0);
+- (*merge_cp_p)->extend_operands(scratch_cp, CHECK_0);
+-
+- // 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;
+- }
+-
+- // 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 scratch_i; // index into scratch_cp
+- {
+- // Pass 1a:
+- // Compare scratch_cp entries to the old_cp entries that we have
+- // already copied to *merge_cp_p. In this pass, we are eliminating
+- // exact duplicates (matching entry at same index) so we only
+- // compare entries in the common indice range.
+- int increment = 1;
+- int pass1a_length = MIN2(old_cp->length(), scratch_cp->length());
+- for (scratch_i = 1; scratch_i < pass1a_length; scratch_i += increment) {
+- switch (scratch_cp->tag_at(scratch_i).value()) {
+- case JVM_CONSTANT_Double:
+- case JVM_CONSTANT_Long:
+- // double and long take two constant pool entries
+- increment = 2;
+- break;
+-
+- default:
+- increment = 1;
+- break;
+- }
+-
+- bool match = scratch_cp->compare_entry_to(scratch_i, *merge_cp_p,
+- scratch_i, CHECK_0);
+- if (match) {
+- // found a match at the same index so nothing more to do
+- continue;
+- } else if (is_unresolved_class_mismatch(scratch_cp, scratch_i,
+- *merge_cp_p, scratch_i)) {
+- // The mismatch in compare_entry_to() above is because of a
+- // resolved versus unresolved class entry at the same index
+- // with the same string value. Since Pass 0 reverted any
+- // class entries to unresolved class entries in *merge_cp_p,
+- // we go with the unresolved class entry.
+- continue;
+- } else if (is_unresolved_string_mismatch(scratch_cp, scratch_i,
+- *merge_cp_p, scratch_i)) {
+- // The mismatch in compare_entry_to() above is because of a
+- // resolved versus unresolved string entry at the same index
+- // with the same string value. We can live with whichever
+- // happens to be at scratch_i in *merge_cp_p.
+- continue;
+- }
+-
+- int found_i = scratch_cp->find_matching_entry(scratch_i, *merge_cp_p,
+- CHECK_0);
+- if (found_i != 0) {
+- guarantee(found_i != scratch_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.
+- map_index(scratch_cp, scratch_i, found_i);
+- continue;
+- }
+-
+- // The find_matching_entry() call above could fail to find a match
+- // due to a resolved versus unresolved class or string entry situation
+- // like we solved above with the is_unresolved_*_mismatch() calls.
+- // However, we would have to call is_unresolved_*_mismatch() over
+- // all of *merge_cp_p (potentially) and that doesn't seem to be
+- // worth the time.
+-
+- // 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);
+- }
+- }
+-
+- RC_TRACE_WITH_THREAD(0x00020000, THREAD,
+- ("after pass 1a: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
+- *merge_cp_length_p, scratch_i, _index_map_count));
+-
+- if (scratch_i < scratch_cp->length()) {
+- // Pass 1b:
+- // old_cp is smaller than scratch_cp so there are entries in
+- // scratch_cp that we have not yet processed. We take care of
+- // those now.
+- int increment = 1;
+- for (; scratch_i < scratch_cp->length(); scratch_i += increment) {
+- switch (scratch_cp->tag_at(scratch_i).value()) {
+- case JVM_CONSTANT_Double:
+- case JVM_CONSTANT_Long:
+- // double and long take two constant pool entries
+- increment = 2;
+- break;
+-
+- default:
+- increment = 1;
+- break;
+- }
+-
+- int found_i =
+- scratch_cp->find_matching_entry(scratch_i, *merge_cp_p, CHECK_0);
+- if (found_i != 0) {
+- // Found a matching entry somewhere else in *merge_cp_p so
+- // just need a mapping entry.
+- map_index(scratch_cp, scratch_i, found_i);
+- continue;
+- }
+-
+- // 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);
+- }
+-
+- 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));
+- }
+- finalize_operands_merge(*merge_cp_p, THREAD);
+-
+- return true;
+-} // end merge_constant_pools()
+-
+-
+-// Merge constant pools between the_class and scratch_class and
+-// potentially rewrite bytecodes in scratch_class to use the merged
+-// constant pool.
+-jvmtiError VM_RedefineClasses::merge_cp_and_rewrite(
+- instanceKlassHandle the_class, instanceKlassHandle scratch_class,
+- TRAPS) {
+- // worst case merged constant pool length is old and new combined
+- int merge_cp_length = the_class->constants()->length()
+- + scratch_class->constants()->length();
+-
+- constantPoolHandle old_cp(THREAD, the_class->constants());
+- constantPoolHandle scratch_cp(THREAD, scratch_class->constants());
+-
+- // Constant pools are not easily reused so we allocate a new one
+- // each time.
+- // merge_cp is created unsafe for concurrent GC processing. It
+- // should be marked safe before discarding it. Even though
+- // garbage, if it crosses a card boundary, it may be scanned
+- // in order to find the start of the first complete object on the card.
+- constantPoolHandle merge_cp(THREAD,
+- oopFactory::new_constantPool(merge_cp_length,
+- oopDesc::IsUnsafeConc,
+- THREAD));
+- int orig_length = old_cp->orig_length();
+- if (orig_length == 0) {
+- // This old_cp is an actual original constant pool. We save
+- // the original length in the merged constant pool so that
+- // merge_constant_pools() can be more efficient. If a constant
+- // pool has a non-zero orig_length() value, then that constant
+- // pool was created by a merge operation in RedefineClasses.
+- merge_cp->set_orig_length(old_cp->length());
+- } else {
+- // This old_cp is a merged constant pool from a previous
+- // RedefineClasses() calls so just copy the orig_length()
+- // value.
+- merge_cp->set_orig_length(old_cp->orig_length());
+- }
+-
+- ResourceMark rm(THREAD);
+- _index_map_count = 0;
+- _index_map_p = new intArray(scratch_cp->length(), -1);
+-
+- _operands_cur_length = constantPoolOopDesc::operand_array_length(old_cp->operands());
+- _operands_index_map_count = 0;
+- _operands_index_map_p = new intArray(
+- constantPoolOopDesc::operand_array_length(scratch_cp->operands()), -1);
+-
+- // reference to the cp holder is needed for copy_operands()
+- merge_cp->set_pool_holder(scratch_class());
+- bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp,
+- &merge_cp_length, THREAD);
+- merge_cp->set_pool_holder(NULL);
+-
+- if (!result) {
+- // The merge can fail due to memory allocation failure or due
+- // to robustness checks.
+- return JVMTI_ERROR_INTERNAL;
+- }
+-
+- RC_TRACE_WITH_THREAD(0x00010000, THREAD,
+- ("merge_cp_len=%d, index_map_len=%d", merge_cp_length, _index_map_count));
+-
+- if (_index_map_count == 0) {
+- // there is nothing to map between the new and merged constant pools
+-
+- if (old_cp->length() == scratch_cp->length()) {
+- // The old and new constant pools are the same length and the
+- // index map is empty. This means that the three constant pools
+- // are equivalent (but not the same). Unfortunately, the new
+- // constant pool has not gone through link resolution nor have
+- // the new class bytecodes gone through constant pool cache
+- // rewriting so we can't use the old constant pool with the new
+- // class.
+-
+- merge_cp()->set_is_conc_safe(true);
+- merge_cp = constantPoolHandle(); // toss the merged constant pool
+- } else if (old_cp->length() < scratch_cp->length()) {
+- // The old constant pool has fewer entries than the new constant
+- // pool and the index map is empty. This means the new constant
+- // pool is a superset of the old constant pool. However, the old
+- // class bytecodes have already gone through constant pool cache
+- // rewriting so we can't use the new constant pool with the old
+- // class.
+-
+- merge_cp()->set_is_conc_safe(true);
+- merge_cp = constantPoolHandle(); // toss the merged constant pool
+- } else {
+- // The old constant pool has more entries than the new constant
+- // pool and the index map is empty. This means that both the old
+- // and merged constant pools are supersets of the new constant
+- // pool.
+-
+- // Replace the new constant pool with a shrunken copy of the
+- // merged constant pool; the previous new constant pool will
+- // get GCed.
+- set_new_constant_pool(scratch_class, merge_cp, merge_cp_length,
+- THREAD);
+- // drop local ref to the merged constant pool
+- merge_cp()->set_is_conc_safe(true);
+- merge_cp = constantPoolHandle();
+- }
+- } else {
+- if (RC_TRACE_ENABLED(0x00040000)) {
+- // don't want to loop unless we are tracing
+- int count = 0;
+- for (int i = 1; i < _index_map_p->length(); i++) {
+- int value = _index_map_p->at(i);
+-
+- if (value != -1) {
+- RC_TRACE_WITH_THREAD(0x00040000, THREAD,
+- ("index_map[%d]: old=%d new=%d", count, i, value));
+- count++;
+ void check_field(oop obj, int offset, klassOop static_type) {
+ oop field_value = obj->obj_field(offset);
+ if (field_value != NULL) {
@@ -7520,21 +7281,18 @@ index 606be1c..ef4f380 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;
+ };
-
--// Rewrite constant pool references in the class_annotations field.
--bool VM_RedefineClasses::rewrite_cp_refs_in_class_annotations(
-- instanceKlassHandle scratch_class, TRAPS) {
++
+ CheckFieldTypesClosure myObjectClosure;
-
-- 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;
++
+ // make sure that heap is parsable (fills TLABs with filler objects)
+ Universe::heap()->ensure_parsability(false); // no need to retire TLABs
+
@@ -7550,187 +7308,27 @@ index 606be1c..ef4f380 100644
+ CompactingPermGenGen* gen = (CompactingPermGenGen*)gch->perm_gen();
+ gen->ro_space()->object_iterate(&myObjectClosure);
+ gen->rw_space()->object_iterate(&myObjectClosure);
- }
-
-- 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);
++ }
++
+ return myObjectClosure.result();
- }
-
--
--// 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;
++}
++
+void VM_RedefineClasses::clear_type_check_information(klassOop k) {
+ if (k->klass_part()->is_redefining()) {
+ k = k->klass_part()->old_version();
- }
-
-- 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:
--//
--// struct annotation {
--// u2 type_index;
--// u2 num_element_value_pairs;
--// {
--// u2 element_name_index;
--// element_value value;
--// } element_value_pairs[num_element_value_pairs];
--// }
--//
--bool VM_RedefineClasses::rewrite_cp_refs_in_annotation_struct(
-- typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) {
-- if ((byte_i_ref + 2 + 2) > annotations_typeArray->length()) {
-- // not enough room for smallest annotation_struct
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("length() is too small for annotation_struct"));
-- return false;
-- }
--
-- 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;
--
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("type_index=%d num_element_value_pairs=%d", type_index,
-- num_element_value_pairs));
--
-- int calc_num_element_value_pairs = 0;
-- for (; calc_num_element_value_pairs < num_element_value_pairs;
-- calc_num_element_value_pairs++) {
-- if ((byte_i_ref + 2) > annotations_typeArray->length()) {
-- // not enough room for another element_name_index, let alone
-- // the rest of another component
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("length() is too small for element_name_index"));
-- return false;
-- }
--
-- u2 element_name_index = rewrite_cp_ref_in_annotation_data(
-- annotations_typeArray, byte_i_ref,
-- "mapped old element_name_index=%d", THREAD);
--
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
-- ("element_name_index=%d", element_name_index));
--
-- 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;
-- }
-- } // 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()
--
--
--// Rewrite a constant pool reference at the current position in
--// annotations_typeArray if needed. Returns the original constant
--// pool reference if a rewrite was not needed or the new constant
--// pool reference if a rewrite was needed.
--u2 VM_RedefineClasses::rewrite_cp_ref_in_annotation_data(
-- typeArrayHandle annotations_typeArray, int &byte_i_ref,
-- const char * trace_mesg, TRAPS) {
--
-- address cp_index_addr = (address)
-- annotations_typeArray->byte_at_addr(byte_i_ref);
-- u2 old_cp_index = Bytes::get_Java_u2(cp_index_addr);
-- u2 new_cp_index = find_new_index(old_cp_index);
-- if (new_cp_index != 0) {
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD, (trace_mesg, old_cp_index));
-- Bytes::put_Java_u2(cp_index_addr, new_cp_index);
-- old_cp_index = new_cp_index;
-- }
-- byte_i_ref += 2;
-- return old_cp_index;
++ }
++
+ // We found an instance klass!
+ instanceKlass *cur_instance_klass = instanceKlass::cast(k);
+ cur_instance_klass->clear_type_check_information();
- }
-
++}
++
+void VM_RedefineClasses::update_active_methods() {
-
--// 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:
--//
--// struct element_value {
--// u1 tag;
--// union {
--// u2 const_value_index;
--// {
--// u2 type_name_index;
--// u2 const_name_index;
--// } enum_const_value;
--// u2 class_info_index;
--// annotation annotation_value;
--// struct {
--// u2 num_values;
--// element_value values[num_values];
--// } array_value;
--// } value;
--// }
--//
--bool VM_RedefineClasses::rewrite_cp_refs_in_element_value(
-- typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) {
++
+ RC_TRACE(0x00000002, ("Updating active methods"));
+ JavaThread *java_thread = Threads::first();
+ while (java_thread != NULL) {
-
-- 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"));
++
+ int stack_depth = 0;
+ if (java_thread->has_last_Java_frame()) {
+
@@ -7801,11 +7399,32 @@ index 606be1c..ef4f380 100644
+ }
+ vf = vf->sender();
+ }
-+ }
-+
+ }
+
+- // 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,
+- 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
+}
+
+void VM_RedefineClasses::method_forwarding() {
@@ -8255,49 +7874,34 @@ index 606be1c..ef4f380 100644
return false;
}
-- u1 tag = annotations_typeArray->byte_at(byte_i_ref);
-- byte_i_ref++;
-- RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("tag='%c'", tag));
+- // 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;
+ }
-- switch (tag) {
-- // These BaseType tag values are from Table 4.2 in VM spec:
-- case 'B': // byte
-- case 'C': // char
-- case 'D': // double
-- case 'F': // float
-- case 'I': // int
-- case 'J': // long
-- case 'S': // short
-- case 'Z': // boolean
+- // 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;
+ }
-- // The remaining tag values are from Table 4.8 in the 2nd-edition of
-- // the VM spec:
-- case 's':
-- {
-- // For the above tag values (including the BaseType values),
-- // value.const_value_index is right union field.
+- // 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;
+}
-
-- 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;
++
+void VM_RedefineClasses::rollback() {
+ RC_TRACE(0x00000001, ("Rolling back redefinition!"));
+ SystemDictionary::rollback_redefinition();
@@ -8326,7 +7930,7 @@ index 606be1c..ef4f380 100644
+ if (klass->new_version() != NULL && klass->new_version()->klass_part()->is_redefining()) {
+ obj = klass->klass_part()->new_version();
+ oopDesc::encode_store_heap_oop_not_null(p, obj);
- }
++ }
+ } else if (obj->blueprint()->newest_version() == SystemDictionary::Class_klass()->klass_part()->newest_version()) {
+ // update references to java.lang.Class to point to newest version. Only update references to non-primitive
+ // java.lang.Class instances.
@@ -8338,11 +7942,821 @@ index 606be1c..ef4f380 100644
+ obj = klass_oop->java_mirror();
+ }
+ oopDesc::encode_store_heap_oop_not_null(p, obj);
++
++
++ // FIXME: DCEVM: better implementation?
++ // Starting from JDK 7 java_mirror can be kept in the regular heap. Therefore, it is possible
++ // that new java_mirror is in the young generation whereas p is in tenured generation. In that
++ // case we need to run write barrier to make sure card table is properly updated. This will
++ // allow JVM to detect reference in tenured generation properly during young generation GC.
++ if (Universe::heap()->is_in_reserved(p)) {
++ if (GenCollectedHeap::heap()->is_in_young(obj)) {
++ GenRemSet* rs = GenCollectedHeap::heap()->rem_set();
++ assert(rs->rs_kind() == GenRemSet::CardTable, "Wrong rem set kind.");
++ CardTableRS* _rs = (CardTableRS*)rs;
++ _rs->inline_write_ref_field_gc(p, obj);
++ }
++ }
++ }
++ }
++ }
++}
++
++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, mtInternal) 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));
++ }
++ }
++
++ 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);
++
++ // Transfer init state
++ if (klass->old_version() != NULL) {
++ instanceKlass::ClassState state = instanceKlass::cast(klass->old_version())->init_state();
++ if (state > instanceKlass::linked) {
++ klass->initialize(Thread::current());
++ }
++ }
++
++ // 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::_invokedynamic : // 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:
+-//
+-// struct annotation {
+-// u2 type_index;
+-// u2 num_element_value_pairs;
+-// {
+-// u2 element_name_index;
+-// element_value value;
+-// } element_value_pairs[num_element_value_pairs];
+-// }
+-//
+-bool VM_RedefineClasses::rewrite_cp_refs_in_annotation_struct(
+- typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) {
+- if ((byte_i_ref + 2 + 2) > annotations_typeArray->length()) {
+- // not enough room for smallest annotation_struct
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("length() is too small for annotation_struct"));
+- return false;
+- }
+-
+- 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;
+-
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("type_index=%d num_element_value_pairs=%d", type_index,
+- num_element_value_pairs));
+-
+- int calc_num_element_value_pairs = 0;
+- for (; calc_num_element_value_pairs < num_element_value_pairs;
+- calc_num_element_value_pairs++) {
+- if ((byte_i_ref + 2) > annotations_typeArray->length()) {
+- // not enough room for another element_name_index, let alone
+- // the rest of another component
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("length() is too small for element_name_index"));
+- return false;
+- }
+-
+- u2 element_name_index = rewrite_cp_ref_in_annotation_data(
+- annotations_typeArray, byte_i_ref,
+- "mapped old element_name_index=%d", THREAD);
+-
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("element_name_index=%d", element_name_index));
+-
+- 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;
+- }
+- } // 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()
+-
+-
+-// Rewrite a constant pool reference at the current position in
+-// annotations_typeArray if needed. Returns the original constant
+-// pool reference if a rewrite was not needed or the new constant
+-// pool reference if a rewrite was needed.
+-u2 VM_RedefineClasses::rewrite_cp_ref_in_annotation_data(
+- typeArrayHandle annotations_typeArray, int &byte_i_ref,
+- const char * trace_mesg, TRAPS) {
+-
+- address cp_index_addr = (address)
+- annotations_typeArray->byte_at_addr(byte_i_ref);
+- u2 old_cp_index = Bytes::get_Java_u2(cp_index_addr);
+- u2 new_cp_index = find_new_index(old_cp_index);
+- if (new_cp_index != 0) {
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD, (trace_mesg, old_cp_index));
+- Bytes::put_Java_u2(cp_index_addr, new_cp_index);
+- old_cp_index = new_cp_index;
+- }
+- byte_i_ref += 2;
+- return old_cp_index;
+-}
+-
+-
+-// 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:
+-//
+-// struct element_value {
+-// u1 tag;
+-// union {
+-// u2 const_value_index;
+-// {
+-// u2 type_name_index;
+-// u2 const_name_index;
+-// } enum_const_value;
+-// u2 class_info_index;
+-// annotation annotation_value;
+-// struct {
+-// u2 num_values;
+-// element_value values[num_values];
+-// } array_value;
+-// } value;
+-// }
+-//
+-bool VM_RedefineClasses::rewrite_cp_refs_in_element_value(
+- typeArrayHandle annotations_typeArray, int &byte_i_ref, TRAPS) {
+-
+- if ((byte_i_ref + 1) > annotations_typeArray->length()) {
+- // not enough room for a tag let alone the rest of an element_value
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
+- ("length() is too small for a tag"));
+- return false;
+- }
+-
+- u1 tag = annotations_typeArray->byte_at(byte_i_ref);
+- byte_i_ref++;
+- RC_TRACE_WITH_THREAD(0x02000000, THREAD, ("tag='%c'", tag));
+-
+- switch (tag) {
+- // These BaseType tag values are from Table 4.2 in VM spec:
+- case 'B': // byte
+- case 'C': // char
+- case 'D': // double
+- case 'F': // float
+- case 'I': // int
+- case 'J': // long
+- case 'S': // short
+- case 'Z': // boolean
+-
+- // The remaining tag values are from Table 4.8 in the 2nd-edition of
+- // the VM spec:
+- case 's':
+- {
+- // For the above tag values (including the BaseType values),
+- // value.const_value_index is right union field.
+-
+- 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;
+- }
+-
- u2 const_value_index = rewrite_cp_ref_in_annotation_data(
- annotations_typeArray, byte_i_ref,
- "mapped old const_value_index=%d", THREAD);
-
+-
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("const_value_index=%d", const_value_index));
- } break;
@@ -8424,20 +8838,8 @@ index 606be1c..ef4f380 100644
- ("bad nested element_value at %d", calc_num_values));
- // propagate failure back to caller
- return false;
-+ // FIXME: DCEVM: better implementation?
-+ // Starting from JDK 7 java_mirror can be kept in the regular heap. Therefore, it is possible
-+ // that new java_mirror is in the young generation whereas p is in tenured generation. In that
-+ // case we need to run write barrier to make sure card table is properly updated. This will
-+ // allow JVM to detect reference in tenured generation properly during young generation GC.
-+ if (Universe::heap()->is_in_reserved(p)) {
-+ if (GenCollectedHeap::heap()->is_in_young(obj)) {
-+ GenRemSet* rs = GenCollectedHeap::heap()->rem_set();
-+ assert(rs->rs_kind() == GenRemSet::CardTable, "Wrong rem set kind.");
-+ CardTableRS* _rs = (CardTableRS*)rs;
-+ _rs->inline_write_ref_field_gc(p, obj);
-+ }
- }
- }
+- }
+- }
- assert(num_values == calc_num_values, "sanity check");
- } break;
-
@@ -8480,40 +8882,28 @@ index 606be1c..ef4f380 100644
- ("bad field_annotations at %d", i));
- // propagate failure back to caller
- return false;
- }
- }
-+}
-
+- }
+- }
+-
- return true;
-} // end rewrite_cp_refs_in_fields_annotations()
-+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();
-
+-
+-
-// Rewrite constant pool references in a methods_annotations field.
-bool VM_RedefineClasses::rewrite_cp_refs_in_methods_annotations(
- instanceKlassHandle scratch_class, TRAPS) {
-+ RC_TRACE(0x00000001, ("Entering doit!"));
-
+-
- objArrayHandle methods_annotations(THREAD,
- scratch_class->methods_annotations());
-
+-
- if (methods_annotations.is_null() || methods_annotations->length() == 0) {
- // no methods_annotations so nothing to do
- return true;
- }
-+ if ((_max_redefinition_flags & Klass::RemoveSuperType) != 0) {
-
+-
- RC_TRACE_WITH_THREAD(0x02000000, THREAD,
- ("methods_annotations length=%d", methods_annotations->length()));
-+ RC_TIMER_START(_timer_check_type);
-
+-
- for (int i = 0; i < methods_annotations->length(); i++) {
- typeArrayHandle method_annotations(THREAD,
- (typeArrayOop)methods_annotations->obj_at(i));
@@ -9119,513 +9509,17 @@ index 606be1c..ef4f380 100644
-
-
-// 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.
--//
--// 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;
--
-- // 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
-- // class loader is the initiating class loader, then it will also
-- // be the defining class loader. This also means that classes
-- // loaded by the bootstrap class loader cannot refer to classes
-- // loaded by a user-defined class loader. Note: a user-defined
-- // class loader can delegate to the bootstrap class loader.
-- //
-- // If the current class being redefined has a user-defined class
-- // loader as its defining class loader, then we can skip all
-- // classes loaded by the bootstrap class loader.
-- bool is_user_defined =
-- instanceKlass::cast(_the_class_oop)->class_loader() != NULL;
-- if (is_user_defined && ik->class_loader() == NULL) {
-+ 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;
- }
-
-- // This is a very busy routine. We don't want too much tracing
-- // printed out.
-- bool trace_name_printed = false;
-+ RC_TIMER_STOP(_timer_check_type);
-
-- // Very noisy: only enable this call if you are trying to determine
-- // that a specific class gets found by this routine.
-- // RC_TRACE macro has an embedded ResourceMark
-- // RC_TRACE_WITH_THREAD(0x00100000, THREAD,
-- // ("adjust check: name=%s", ik->external_name()));
-- // trace_name_printed = true;
-+ } else {
-+ RC_TRACE(0x00000001, ("No type narrowing => skipping check for type inconsistency"));
-+ }
-
-- // Fix the vtable embedded in the_class and subclasses of the_class,
-- // if one exists. We discard scratch_class and we don't keep an
-- // instanceKlass around to hold obsolete methods so we don't have
-- // any other instanceKlass embedded vtables to update. The vtable
-- // holds the methodOops for virtual (but not final) methods.
-- 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);
-- ik->vtable()->adjust_method_entries(_matching_old_methods,
-- _matching_new_methods,
-- _matching_methods_length,
-- &trace_name_printed);
-+ 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, mtInternal) 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);
- }
-
-- // If the current class has an itable and we are either redefining an
-- // interface or if the current class is a subclass of the_class, then
-- // we potentially have to fix the itable. If we are redefining an
-- // interface, then we have to call adjust_method_entries() for
-- // every instanceKlass that has an itable since there isn't a
-- // subclass relationship between an interface and an instanceKlass.
-- if (ik->itable_length() > 0 && (Klass::cast(_the_class_oop)->is_interface()
-- || ik->is_subclass_of(_the_class_oop))) {
-- // ik->itable() creates a wrapper object; rm cleans it up
-- ResourceMark rm(THREAD);
-- ik->itable()->adjust_method_entries(_matching_old_methods,
-- _matching_new_methods,
-- _matching_methods_length,
-- &trace_name_printed);
-+ // 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());
- }
-
-- // The constant pools in other classes (other_cp) can refer to
-- // methods in the_class. We have to update method information in
-- // other_cp's cache. If other_cp has a previous version, then we
-- // have to repeat the process for each previous version. The
-- // constant pool cache holds the methodOops for non-virtual
-- // methods and for virtual, final methods.
-- //
-- // Special case: if the current class is the_class, then new_cp
-- // has already been attached to the_class and old_cp has already
-- // been added as a previous version. The new_cp doesn't have any
-- // cached references to old methods so it doesn't need to be
-- // updated. We can simply start with the previous version(s) in
-- // that case.
-- constantPoolHandle other_cp;
-- constantPoolCacheOop cp_cache;
-+ _updated_oops = objectClosure.updated_oops();
-
-- if (k_oop != _the_class_oop) {
-- // this klass' constant pool cache may need adjustment
-- other_cp = constantPoolHandle(ik->constants());
-- cp_cache = other_cp->cache();
-- if (cp_cache != NULL) {
-- cp_cache->adjust_method_entries(_matching_old_methods,
-- _matching_new_methods,
-- _matching_methods_length,
-- &trace_name_printed);
-+ 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));
-+ }
-+ }
-+
-+ 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);
-+
-+ // Transfer init state
-+ if (klass->old_version() != NULL) {
-+ instanceKlass::ClassState state = instanceKlass::cast(klass->old_version())->init_state();
-+ if (state > instanceKlass::linked) {
-+ klass->initialize(Thread::current());
- }
- }
-- {
-- ResourceMark rm(THREAD);
-- // PreviousVersionInfo objects returned via PreviousVersionWalker
-- // contain a GrowableArray of handles. We have to clean up the
-- // GrowableArray _after_ the PreviousVersionWalker destructor
-- // has destroyed the handles.
-- {
-- // the previous versions' constant pool caches may need adjustment
-- PreviousVersionWalker pvw(ik);
-- for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
-- pv_info != NULL; pv_info = pvw.next_previous_version()) {
-- other_cp = pv_info->prev_constant_pool_handle();
-- cp_cache = other_cp->cache();
-- if (cp_cache != NULL) {
-- cp_cache->adjust_method_entries(_matching_old_methods,
-- _matching_new_methods,
-- _matching_methods_length,
-- &trace_name_printed);
-- }
-+
-+ // 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();
- }
-- } // pvw is cleaned up
-- } // rm is cleaned up
-+ }
-+ 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;
-+ }
-+ 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;
-+}
-+
-+#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();
-+ }
-+}
-+
-+#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);
-+ }
-+ }
-+}
-+
+// 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
+ // from their constant pool caches, itables, and/or vtables. We
+ // use the SystemDictionary::classes_do() facility and this helper
+-// to fix up these pointers.
+// 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.
+ //
+ // 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) {
+void VM_RedefineClasses::adjust_cpool_cache(klassOop k_oop_latest, oop initiating_loader, TRAPS) {
+ klassOop k_oop = k_oop_latest;
+ while (k_oop != NULL) {
@@ -9676,24 +9570,22 @@ index 606be1c..ef4f380 100644
+ }
+ }
+ 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 = _matching_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();
++ jmethodID jmid = old_method->find_jmethod_id_or_null();
+ if (old_method->new_version() != NULL && jmid == NULL) {
+ // (tw) Have to create jmethodID in this case
+ jmid = old_method->jmethod_id();
+ }
+
- if (jmid != NULL) {
- // There is a jmethodID, change it to point to the new method
-- methodHandle new_method_h(_matching_new_methods[j]);
++ 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]));
@@ -9707,35 +9599,18 @@ index 606be1c..ef4f380 100644
+ //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);
-- assert(JNIHandles::resolve_jmethod_id(jmid) == _matching_new_methods[j],
-- "should be replaced");
++ 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());
- }
- }
- }
-
--void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
-- BitMap *emcp_methods, int * emcp_method_count_p) {
-- *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 = _matching_old_methods[j];
-- methodOop new_method = _matching_new_methods[j];
-- methodOop old_array_method;
-
-- // Maintain an old_index into the _old_methods array by skipping
-- // deleted methods
-- while ((old_array_method = (methodOop) _old_methods->obj_at(old_index))
-- != old_method) {
-- ++old_index;
-- }
++ }
++ }
++}
++
++
+// Deoptimize all compiled code that depends on this class.
+//
+// If the can_redefine_classes capability is obtained in the onload
@@ -9753,100 +9628,20 @@ index 606be1c..ef4f380 100644
+//
+void VM_RedefineClasses::flush_dependent_code(instanceKlassHandle k_h, TRAPS) {
+ assert_locked_or_safepoint(Compile_lock);
-
-- 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.
-- //
-- // The old and new methods are EMCP and you would think that we
-- // could get rid of one of them here and now and save some space.
-- // However, the concept of EMCP only considers the bytecodes and
-- // the constant pool entries in the comparison. Other things,
-- // e.g., the line number table (LNT) or the local variable table
-- // (LVT) don't count in the comparison. So the new (and EMCP)
-- // method can have a new LNT that we need so we can't just
-- // overwrite the new method with the old method.
-- //
-- // When this routine is called, we have already attached the new
-- // methods to the_class so the old methods are effectively
-- // overwritten. However, if an old method is still executing,
-- // then the old method cannot be collected until sometime after
-- // the old method call has returned. So the overwriting of old
-- // methods by new methods will save us space except for those
-- // (hopefully few) old methods that are still executing.
-- //
-- // A method refers to a constMethodOop and this presents another
-- // possible avenue to space savings. The constMethodOop in the
-- // new method contains possibly new attributes (LNT, LVT, etc).
-- // At first glance, it seems possible to save space by replacing
-- // the constMethodOop in the old method with the constMethodOop
-- // from the new method. The old and new methods would share the
-- // same constMethodOop and we would save the space occupied by
-- // the old constMethodOop. However, the constMethodOop contains
-- // a back reference to the containing method. Sharing the
-- // constMethodOop between two methods could lead to confusion in
-- // the code that uses the back reference. This would lead to
-- // brittle code that could be broken in non-obvious ways now or
-- // in the future.
-- //
-- // Another possibility is to copy the constMethodOop from the new
-- // method to the old method and then overwrite the new method with
-- // the old method. Since the constMethodOop contains the bytecodes
-- // for the method embedded in the oop, this option would change
-- // the bytecodes out from under any threads executing the old
-- // method and make the thread's bcp invalid. Since EMCP requires
-- // that the bytecodes be the same modulo constant pool indices, it
-- // is straight forward to compute the correct new bcp in the new
-- // constMethodOop from the old bcp in the old constMethodOop. The
-- // time consuming part would be searching all the frames in all
-- // of the threads to find all of the calls to the old method.
-- //
-- // It looks like we will have to live with the limited savings
-- // that we get from effectively overwriting the old methods
-- // when the new methods are attached to the_class.
++
+ // All dependencies have been recorded from startup or this is a second or
+ // subsequent use of RedefineClasses
-
-- // track which methods are EMCP for add_previous_version() call
-- emcp_methods->set_bit(old_index);
-- (*emcp_method_count_p)++;
++
+ // 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();
-
-- // 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.
-- } else {
-- // mark obsolete methods as such
-- old_method->set_is_obsolete();
-- obsolete_count++;
++
+ ResourceMark rm(THREAD);
+ DeoptimizationMarker dm;
-
-- // 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
++
+ // Deoptimize all activations depending on marked nmethods
+ Deoptimization::deoptimize_dependents();
+
@@ -9877,7 +9672,7 @@ index 606be1c..ef4f380 100644
+ 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;
@@ -10094,40 +9889,16 @@ index 606be1c..ef4f380 100644
+ 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 %s(%s) as obsolete",
++ // 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()));
- }
-- old_method->set_is_old();
-- }
-- for (int i = 0; i < _deleted_methods_length; ++i) {
-- methodOop old_method = _deleted_methods[i];
--
-- assert(old_method->vtable_index() < 0,
-- "cannot delete methods with vtable entries");;
--
-- // 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));
++ 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.
@@ -10141,27 +9912,162 @@ index 606be1c..ef4f380 100644
+
+#ifndef PRODUCT
+void VM_RedefineClasses::check_class(klassOop k_oop, TRAPS) {
-+ Klass *k = k_oop->klass_part();
-+ if (k->oop_is_instance()) {
-+ HandleMark hm(THREAD);
-+ instanceKlass *ik = (instanceKlass *) k;
+ Klass *k = k_oop->klass_part();
+ if (k->oop_is_instance()) {
+ HandleMark hm(THREAD);
+ instanceKlass *ik = (instanceKlass *) k;
+-
+- // 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
+- // class loader is the initiating class loader, then it will also
+- // be the defining class loader. This also means that classes
+- // loaded by the bootstrap class loader cannot refer to classes
+- // loaded by a user-defined class loader. Note: a user-defined
+- // class loader can delegate to the bootstrap class loader.
+- //
+- // If the current class being redefined has a user-defined class
+- // loader as its defining class loader, then we can skip all
+- // classes loaded by the bootstrap class loader.
+- bool is_user_defined =
+- instanceKlass::cast(_the_class_oop)->class_loader() != NULL;
+- if (is_user_defined && ik->class_loader() == NULL) {
+- return;
+- }
+-
+- // This is a very busy routine. We don't want too much tracing
+- // printed out.
+- bool trace_name_printed = false;
+-
+- // Very noisy: only enable this call if you are trying to determine
+- // that a specific class gets found by this routine.
+- // RC_TRACE macro has an embedded ResourceMark
+- // RC_TRACE_WITH_THREAD(0x00100000, THREAD,
+- // ("adjust check: name=%s", ik->external_name()));
+- // trace_name_printed = true;
+-
+- // Fix the vtable embedded in the_class and subclasses of the_class,
+- // if one exists. We discard scratch_class and we don't keep an
+- // instanceKlass around to hold obsolete methods so we don't have
+- // any other instanceKlass embedded vtables to update. The vtable
+- // holds the methodOops for virtual (but not final) methods.
+- if (ik->vtable_length() > 0 && ik->is_subtype_of(_the_class_oop)) {
+- // ik->vtable() creates a wrapper object; rm cleans it up
+ assert(ik->is_newest_version(), "must be latest version in system dictionary");
+
+ if (ik->vtable_length() > 0) {
-+ ResourceMark rm(THREAD);
+ ResourceMark rm(THREAD);
+- ik->vtable()->adjust_method_entries(_matching_old_methods,
+- _matching_new_methods,
+- _matching_methods_length,
+- &trace_name_printed);
+- }
+-
+- // If the current class has an itable and we are either redefining an
+- // interface or if the current class is a subclass of the_class, then
+- // we potentially have to fix the itable. If we are redefining an
+- // interface, then we have to call adjust_method_entries() for
+- // every instanceKlass that has an itable since there isn't a
+- // subclass relationship between an interface and an instanceKlass.
+- if (ik->itable_length() > 0 && (Klass::cast(_the_class_oop)->is_interface()
+- || ik->is_subclass_of(_the_class_oop))) {
+- // ik->itable() creates a wrapper object; rm cleans it up
+- ResourceMark rm(THREAD);
+- ik->itable()->adjust_method_entries(_matching_old_methods,
+- _matching_new_methods,
+- _matching_methods_length,
+- &trace_name_printed);
+- }
+-
+- // The constant pools in other classes (other_cp) can refer to
+- // methods in the_class. We have to update method information in
+- // other_cp's cache. If other_cp has a previous version, then we
+- // have to repeat the process for each previous version. The
+- // constant pool cache holds the methodOops for non-virtual
+- // methods and for virtual, final methods.
+- //
+- // Special case: if the current class is the_class, then new_cp
+- // has already been attached to the_class and old_cp has already
+- // been added as a previous version. The new_cp doesn't have any
+- // cached references to old methods so it doesn't need to be
+- // updated. We can simply start with the previous version(s) in
+- // that case.
+- constantPoolHandle other_cp;
+- constantPoolCacheOop cp_cache;
+-
+- if (k_oop != _the_class_oop) {
+- // this klass' constant pool cache may need adjustment
+- other_cp = constantPoolHandle(ik->constants());
+- cp_cache = other_cp->cache();
+- if (cp_cache != NULL) {
+- cp_cache->adjust_method_entries(_matching_old_methods,
+- _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);
+- // PreviousVersionInfo objects returned via PreviousVersionWalker
+- // contain a GrowableArray of handles. We have to clean up the
+- // GrowableArray _after_ the PreviousVersionWalker destructor
+- // has destroyed the handles.
+- {
+- // the previous versions' constant pool caches may need adjustment
+- PreviousVersionWalker pvw(ik);
+- for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
+- pv_info != NULL; pv_info = pvw.next_previous_version()) {
+- other_cp = pv_info->prev_constant_pool_handle();
+- cp_cache = other_cp->cache();
+- if (cp_cache != NULL) {
+- cp_cache->adjust_method_entries(_matching_old_methods,
+- _matching_new_methods,
+- _matching_methods_length,
+- &trace_name_printed);
+- }
+- }
+- } // pvw is cleaned up
+- } // rm is cleaned up
+- }
+-}
+-
+-void VM_RedefineClasses::update_jmethod_ids() {
+- for (int j = 0; j < _matching_methods_length; ++j) {
+- methodOop old_method = _matching_old_methods[j];
+- jmethodID jmid = old_method->find_jmethod_id_or_null();
+- if (jmid != NULL) {
+- // There is a jmethodID, change it to point to the new method
+- methodHandle new_method_h(_matching_new_methods[j]);
+- JNIHandles::change_method_associated_with_jmethod_id(jmid, new_method_h);
+- assert(JNIHandles::resolve_jmethod_id(jmid) == _matching_new_methods[j],
+- "should be replaced");
+
+ ik->vtable()->verify(tty, true);
-+ }
-+ }
-+}
-+
+ }
+ }
+ }
+
+-void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
+- BitMap *emcp_methods, int * emcp_method_count_p) {
+- *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 = _matching_old_methods[j];
+- methodOop new_method = _matching_new_methods[j];
+- methodOop old_array_method;
+-
+- // Maintain an old_index into the _old_methods array by skipping
+- // deleted methods
+- while ((old_array_method = (methodOop) _old_methods->obj_at(old_index))
+- != old_method) {
+- ++old_index;
+#endif
+
+VM_RedefineClasses::FindAffectedKlassesClosure::FindAffectedKlassesClosure( GrowableArray<instanceKlassHandle> *original_klasses, GrowableArray<instanceKlassHandle> *result )
@@ -10184,7 +10090,91 @@ index 606be1c..ef4f380 100644
+ 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
+- // 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.
+- //
+- // The old and new methods are EMCP and you would think that we
+- // could get rid of one of them here and now and save some space.
+- // However, the concept of EMCP only considers the bytecodes and
+- // the constant pool entries in the comparison. Other things,
+- // e.g., the line number table (LNT) or the local variable table
+- // (LVT) don't count in the comparison. So the new (and EMCP)
+- // method can have a new LNT that we need so we can't just
+- // overwrite the new method with the old method.
+- //
+- // When this routine is called, we have already attached the new
+- // methods to the_class so the old methods are effectively
+- // overwritten. However, if an old method is still executing,
+- // then the old method cannot be collected until sometime after
+- // the old method call has returned. So the overwriting of old
+- // methods by new methods will save us space except for those
+- // (hopefully few) old methods that are still executing.
+- //
+- // A method refers to a constMethodOop and this presents another
+- // possible avenue to space savings. The constMethodOop in the
+- // new method contains possibly new attributes (LNT, LVT, etc).
+- // At first glance, it seems possible to save space by replacing
+- // the constMethodOop in the old method with the constMethodOop
+- // from the new method. The old and new methods would share the
+- // same constMethodOop and we would save the space occupied by
+- // the old constMethodOop. However, the constMethodOop contains
+- // a back reference to the containing method. Sharing the
+- // constMethodOop between two methods could lead to confusion in
+- // the code that uses the back reference. This would lead to
+- // brittle code that could be broken in non-obvious ways now or
+- // in the future.
+- //
+- // Another possibility is to copy the constMethodOop from the new
+- // method to the old method and then overwrite the new method with
+- // the old method. Since the constMethodOop contains the bytecodes
+- // for the method embedded in the oop, this option would change
+- // the bytecodes out from under any threads executing the old
+- // method and make the thread's bcp invalid. Since EMCP requires
+- // that the bytecodes be the same modulo constant pool indices, it
+- // is straight forward to compute the correct new bcp in the new
+- // constMethodOop from the old bcp in the old constMethodOop. The
+- // time consuming part would be searching all the frames in all
+- // of the threads to find all of the calls to the old method.
+- //
+- // It looks like we will have to live with the limited savings
+- // that we get from effectively overwriting the old methods
+- // when the new methods are attached to the_class.
+-
+- // track which methods are EMCP for add_previous_version() call
+- emcp_methods->set_bit(old_index);
+- (*emcp_method_count_p)++;
+-
+- // An EMCP method is _not_ obsolete. An obsolete method has a
+- // different jmethodID than the current method. An EMCP method
+- // has the same jmethodID as the current method. Having the
+- // 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.
+- } else {
+- // mark obsolete methods as such
+- old_method->set_is_obsolete();
+- obsolete_count++;
+-
+- // 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
+ }
+}
+
@@ -10222,9 +10212,32 @@ index 606be1c..ef4f380 100644
+ 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
+- // 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) {
+- methodOop old_method = _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()));
+
+
+ RC_TRACE(0x00000001, ("Identified links between classes! "));
@@ -10245,7 +10258,11 @@ index 606be1c..ef4f380 100644
+ 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: "));
@@ -10295,8 +10312,8 @@ index 606be1c..ef4f380 100644
+ }
+
+ return JVMTI_ERROR_NONE;
-+}
-+
+ }
+
+void VM_RedefineClasses::oops_do(OopClosure *closure) {
+
+ if (_updated_oops != NULL) {
@@ -10322,9 +10339,10 @@ index 606be1c..ef4f380 100644
+ 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
@@ -2969,7 +3161,7 @@
// Same, caused by prefix removal only 3_2_1_m -> 3_2_m
//
@@ -10363,13 +10381,7 @@ index 606be1c..ef4f380 100644
+ // 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];
@@ -10384,6 +10396,13 @@ index 606be1c..ef4f380 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];
@@ -10452,7 +10471,11 @@ index 606be1c..ef4f380 100644
- 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.
-//
@@ -10988,15 +11011,10 @@ index 606be1c..ef4f380 100644
- m->print_name(tty);
- tty->cr();
- }
-+void VM_RedefineClasses::transfer_old_native_function_registrations(instanceKlassHandle old_klass) {
-+ TransferNativeFunctionRegistration transfer(old_klass);
-+ transfer.transfer_registrations(old_klass, _deleted_methods, _deleted_methods_length);
-+ transfer.transfer_registrations(old_klass, _matching_old_methods, _matching_methods_length);
- }
-diff --git a/src/share/vm/prims/jvmtiRedefineClasses.hpp b/src/share/vm/prims/jvmtiRedefineClasses.hpp
-index bfac62c..d7ba79f 100644
---- a/src/share/vm/prims/jvmtiRedefineClasses.hpp
-+++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp
+-}
+diff -r 882f6c762ac5 src/share/vm/prims/jvmtiRedefineClasses.hpp
+--- a/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -1,26 +1,29 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
@@ -11049,7 +11067,7 @@ index bfac62c..d7ba79f 100644
#ifndef SHARE_VM_PRIMS_JVMTIREDEFINECLASSES_HPP
#define SHARE_VM_PRIMS_JVMTIREDEFINECLASSES_HPP
-@@ -32,330 +35,27 @@
+@@ -32,331 +35,28 @@
#include "oops/objArrayOop.hpp"
#include "prims/jvmtiRedefineClassesTrace.hpp"
#include "runtime/vm_operations.hpp"
@@ -11385,12 +11403,13 @@ index bfac62c..d7ba79f 100644
static int _deleted_methods_length;
static int _added_methods_length;
static klassOop _the_class_oop;
-+
-+ static int _revision_number;
++ static int _revision_number;
++
// The instance fields are used to pass information from
// doit_prologue() to doit() and doit_epilogue().
-@@ -370,42 +70,28 @@
+ jint _class_count;
+@@ -370,43 +70,29 @@
// _index_map_p contains any entries.
int _index_map_count;
intArray * _index_map_p;
@@ -11435,7 +11454,7 @@ index bfac62c..d7ba79f 100644
+ 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);
jvmtiError load_new_class_versions(TRAPS);
--
+
- // Verify that the caller provided class definition(s) that meet
- // the restrictions of RedefineClasses. Normalize the order of
- // overloaded methods as needed.
@@ -11446,9 +11465,10 @@ index bfac62c..d7ba79f 100644
- // Used by compare_and_normalize_class_versions() when normalizing
- // overloaded methods or changing idnum as when adding or deleting methods.
- void swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class);
-
+-
// 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();
@@ -414,103 +100,99 @@
// Change jmethodIDs to point to the new methods
void update_jmethod_ids();
@@ -11625,10 +11645,9 @@ index bfac62c..d7ba79f 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..07bb6e3 100644
---- a/src/share/vm/prims/methodComparator.cpp
-+++ b/src/share/vm/prims/methodComparator.cpp
+diff -r 882f6c762ac5 src/share/vm/prims/methodComparator.cpp
+--- a/src/share/vm/prims/methodComparator.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/methodComparator.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -65,6 +65,7 @@
if (! args_same(c_old, c_new))
return false;
@@ -11637,10 +11656,9 @@ index 60eaf97..07bb6e3 100644
return true;
}
-diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp
-index 41fc42d..53b3e0c 100644
---- a/src/share/vm/prims/nativeLookup.cpp
-+++ b/src/share/vm/prims/nativeLookup.cpp
+diff -r 882f6c762ac5 src/share/vm/prims/nativeLookup.cpp
+--- a/src/share/vm/prims/nativeLookup.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/prims/nativeLookup.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -35,6 +35,7 @@
#include "oops/symbol.hpp"
#include "prims/jvm_misc.hpp"
@@ -11649,14 +11667,14 @@ index 41fc42d..53b3e0c 100644
#include "runtime/arguments.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
-@@ -52,7 +53,6 @@
- #ifdef TARGET_OS_FAMILY_bsd
+@@ -53,7 +54,6 @@
# include "os_bsd.inline.hpp"
#endif
--
+-
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;
@@ -138,6 +138,40 @@
{ CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) },
};
@@ -11708,10 +11726,9 @@ index 41fc42d..53b3e0c 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 0496367..62e9d55 100644
---- a/src/share/vm/runtime/arguments.cpp
-+++ b/src/share/vm/runtime/arguments.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/arguments.cpp
+--- a/src/share/vm/runtime/arguments.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/arguments.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -1874,6 +1874,15 @@
status = false;
}
@@ -11728,10 +11745,9 @@ index 0496367..62e9d55 100644
return status;
}
-diff --git a/src/share/vm/runtime/deoptimization.cpp b/src/share/vm/runtime/deoptimization.cpp
-index 2b767d4..e9b6f47 100644
---- a/src/share/vm/runtime/deoptimization.cpp
-+++ b/src/share/vm/runtime/deoptimization.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/deoptimization.cpp
+--- a/src/share/vm/runtime/deoptimization.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/deoptimization.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -599,6 +599,38 @@
// Cleanup thread deopt data
cleanup_deopt_info(thread, array);
@@ -11771,10 +11787,9 @@ index 2b767d4..e9b6f47 100644
#ifndef PRODUCT
if (VerifyStack) {
ResourceMark res_mark;
-diff --git a/src/share/vm/runtime/frame.cpp b/src/share/vm/runtime/frame.cpp
-index aacd835..3772b3f 100644
---- a/src/share/vm/runtime/frame.cpp
-+++ b/src/share/vm/runtime/frame.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/frame.cpp
+--- a/src/share/vm/runtime/frame.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/frame.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -408,6 +408,12 @@
*interpreter_frame_method_addr() = method;
}
@@ -11823,10 +11838,9 @@ index aacd835..3772b3f 100644
}
}
}
-diff --git a/src/share/vm/runtime/frame.hpp b/src/share/vm/runtime/frame.hpp
-index 9c7bb72..04a6595 100644
---- a/src/share/vm/runtime/frame.hpp
-+++ b/src/share/vm/runtime/frame.hpp
+diff -r 882f6c762ac5 src/share/vm/runtime/frame.hpp
+--- a/src/share/vm/runtime/frame.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/frame.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -346,6 +346,7 @@
// Method & constant pool cache
methodOop interpreter_frame_method() const;
@@ -11835,10 +11849,9 @@ index 9c7bb72..04a6595 100644
methodOop* interpreter_frame_method_addr() const;
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 0731ca0..cbd6eca 100644
---- a/src/share/vm/runtime/globals.hpp
-+++ b/src/share/vm/runtime/globals.hpp
+diff -r 882f6c762ac5 src/share/vm/runtime/globals.hpp
+--- a/src/share/vm/runtime/globals.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/globals.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -1229,9 +1229,23 @@
product(bool, StressLdcRewrite, false, \
"Force ldc -> ldc_w rewrite during RedefineClasses") \
@@ -11863,10 +11876,9 @@ index 0731ca0..cbd6eca 100644
develop(bool, StressMethodComparator, false, \
"run the MethodComparator on all loaded methods") \
\
-diff --git a/src/share/vm/runtime/interfaceSupport.hpp b/src/share/vm/runtime/interfaceSupport.hpp
-index 2875ee0..61fd8fe 100644
---- a/src/share/vm/runtime/interfaceSupport.hpp
-+++ b/src/share/vm/runtime/interfaceSupport.hpp
+diff -r 882f6c762ac5 src/share/vm/runtime/interfaceSupport.hpp
+--- a/src/share/vm/runtime/interfaceSupport.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/interfaceSupport.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -296,7 +296,7 @@
ThreadToNativeFromVM(JavaThread *thread) : ThreadStateTransition(thread) {
// We are leaving the VM at this point and going directly to native code.
@@ -11876,10 +11888,9 @@ index 2875ee0..61fd8fe 100644
thread->frame_anchor()->make_walkable(thread);
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
+diff -r 882f6c762ac5 src/share/vm/runtime/javaCalls.cpp
+--- a/src/share/vm/runtime/javaCalls.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/javaCalls.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -60,7 +60,7 @@
bool clear_pending_exception = true;
@@ -11889,10 +11900,9 @@ index edbba98..4a27925 100644
guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler");
_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
+diff -r 882f6c762ac5 src/share/vm/runtime/jniHandles.cpp
+--- a/src/share/vm/runtime/jniHandles.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/jniHandles.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -112,6 +112,10 @@
}
@@ -11904,10 +11914,9 @@ index 3cbcaca..30839d7 100644
return (jmethodID) make_weak_global(mh);
}
-diff --git a/src/share/vm/runtime/mutex.cpp b/src/share/vm/runtime/mutex.cpp
-index 2095237..c541434 100644
---- a/src/share/vm/runtime/mutex.cpp
-+++ b/src/share/vm/runtime/mutex.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/mutex.cpp
+--- a/src/share/vm/runtime/mutex.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/mutex.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -1227,7 +1227,7 @@
// in increasing rank order (modulo any native ranks)
for (tmp = locks; tmp != NULL; tmp = tmp->next()) {
@@ -11934,10 +11943,9 @@ index 2095237..c541434 100644
locks != NULL && locks->rank() <= this->rank() &&
!SafepointSynchronize::is_at_safepoint() &&
this != Interrupt_lock &&
-diff --git a/src/share/vm/runtime/mutex.hpp b/src/share/vm/runtime/mutex.hpp
-index 7d2cd82..11eb32e 100644
---- a/src/share/vm/runtime/mutex.hpp
-+++ b/src/share/vm/runtime/mutex.hpp
+diff -r 882f6c762ac5 src/share/vm/runtime/mutex.hpp
+--- a/src/share/vm/runtime/mutex.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/mutex.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -109,7 +109,8 @@
barrier = safepoint + 1,
nonleaf = barrier + 1,
@@ -11948,10 +11956,9 @@ index 7d2cd82..11eb32e 100644
};
// The WaitSet and EntryList linked lists are composed of ParkEvents.
-diff --git a/src/share/vm/runtime/mutexLocker.cpp b/src/share/vm/runtime/mutexLocker.cpp
-index 77fddef..9d453d4 100644
---- a/src/share/vm/runtime/mutexLocker.cpp
-+++ b/src/share/vm/runtime/mutexLocker.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/mutexLocker.cpp
+--- a/src/share/vm/runtime/mutexLocker.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/mutexLocker.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -49,6 +49,7 @@
// Consider using GCC's __read_mostly.
@@ -11984,10 +11991,9 @@ index 77fddef..9d453d4 100644
#ifdef INCLUDE_TRACE
def(JfrMsg_lock , Monitor, leaf, true);
-diff --git a/src/share/vm/runtime/mutexLocker.hpp b/src/share/vm/runtime/mutexLocker.hpp
-index a6549b1..089ed11 100644
---- a/src/share/vm/runtime/mutexLocker.hpp
-+++ b/src/share/vm/runtime/mutexLocker.hpp
+diff -r 882f6c762ac5 src/share/vm/runtime/mutexLocker.hpp
+--- a/src/share/vm/runtime/mutexLocker.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/mutexLocker.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -43,6 +43,8 @@
// Mutexes used in the VM.
@@ -11997,10 +12003,9 @@ index a6549b1..089ed11 100644
extern Monitor* SystemDictionary_lock; // a lock on the system dictonary
extern Mutex* PackageTable_lock; // a lock on the class loader package table
extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access
-diff --git a/src/share/vm/runtime/reflection.cpp b/src/share/vm/runtime/reflection.cpp
-index 1665d93..6baabba 100644
---- a/src/share/vm/runtime/reflection.cpp
-+++ b/src/share/vm/runtime/reflection.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/reflection.cpp
+--- a/src/share/vm/runtime/reflection.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/reflection.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -468,7 +468,8 @@
// sun/reflect/MagicAccessorImpl subclasses to succeed trivially.
if ( JDK_Version::is_gte_jdk14x_version()
@@ -12034,10 +12039,9 @@ index 1665d93..6baabba 100644
return true;
}
-diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp
-index 709d783..e0e19b1 100644
---- a/src/share/vm/runtime/sharedRuntime.cpp
-+++ b/src/share/vm/runtime/sharedRuntime.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/sharedRuntime.cpp
+--- a/src/share/vm/runtime/sharedRuntime.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/sharedRuntime.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -1137,7 +1137,20 @@
if (JvmtiExport::can_hotswap_or_post_breakpoint()) {
int retry_count = 0;
@@ -12060,10 +12064,9 @@ index 709d783..e0e19b1 100644
// If has a pending exception then there is no need to re-try to
// 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 f3acf4d..ea61cae 100644
---- a/src/share/vm/runtime/thread.cpp
-+++ b/src/share/vm/runtime/thread.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/thread.cpp
+--- a/src/share/vm/runtime/thread.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/thread.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -216,6 +216,8 @@
set_self_raw_id(0);
set_lgrp_id(-1);
@@ -12081,22 +12084,22 @@ index f3acf4d..ea61cae 100644
#ifdef ASSERT
_visited_for_critical_count = false;
-@@ -880,6 +883,15 @@
- bool Thread::owns_locks_but_compiled_lock() const {
- for(Monitor *cur = _owned_locks; cur; cur = cur->next()) {
- if (cur != Compile_lock) return true;
-+ }
-+ return false;
-+}
-+
+@@ -884,6 +887,15 @@
+ return false;
+ }
+
+bool Thread::owns_locks_but_redefine_classes_lock() const {
+ for(Monitor *cur = _owned_locks; cur; cur = cur->next()) {
+ if (cur != RedefineClasses_lock && cur->rank() != Mutex::redefine_classes) {
+ return true;
+ }
- }
- return false;
- }
++ }
++ return false;
++}
++
+
+ #endif
+
@@ -1637,7 +1649,7 @@
ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);
@@ -12131,11 +12134,10 @@ index f3acf4d..ea61cae 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 774bd27..4ca4502 100644
---- a/src/share/vm/runtime/thread.hpp
-+++ b/src/share/vm/runtime/thread.hpp
-@@ -203,10 +203,13 @@
+diff -r 882f6c762ac5 src/share/vm/runtime/thread.hpp
+--- a/src/share/vm/runtime/thread.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/thread.hpp Thu Jul 09 23:18:17 2015 -0700
+@@ -203,11 +203,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; }
@@ -12144,11 +12146,12 @@ index 774bd27..4ca4502 100644
private:
// Debug tracing
static void trace(const char* msg, const Thread* const thread) PRODUCT_RETURN;
-+
-+ Mutex* _redefine_classes_mutex;
++ Mutex* _redefine_classes_mutex;
++
// Active_handles points to a block of handles
JNIHandleBlock* _active_handles;
+
@@ -530,10 +533,15 @@
uintptr_t _self_raw_id; // used by get_thread (mutable)
int _lgrp_id;
@@ -12217,10 +12220,9 @@ index 774bd27..4ca4502 100644
// Initializes the vm and creates the vm thread
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 09e324f..d47ffef 100644
---- a/src/share/vm/runtime/vframe.cpp
-+++ b/src/share/vm/runtime/vframe.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/vframe.cpp
+--- a/src/share/vm/runtime/vframe.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/vframe.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -253,6 +253,46 @@
return fr().interpreter_frame_method();
}
@@ -12268,10 +12270,9 @@ index 09e324f..d47ffef 100644
StackValueCollection* interpretedVFrame::locals() const {
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
+diff -r 882f6c762ac5 src/share/vm/runtime/vframe.hpp
+--- a/src/share/vm/runtime/vframe.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/vframe.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -163,6 +163,7 @@
StackValueCollection* locals() const;
StackValueCollection* expressions() const;
@@ -12280,10 +12281,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 0a3e0da..3d294e1 100644
---- a/src/share/vm/runtime/vmThread.cpp
-+++ b/src/share/vm/runtime/vmThread.cpp
+diff -r 882f6c762ac5 src/share/vm/runtime/vmThread.cpp
+--- a/src/share/vm/runtime/vmThread.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/runtime/vmThread.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -694,6 +694,10 @@
void VMThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
Thread::oops_do(f, cf);
@@ -12295,10 +12295,9 @@ index 0a3e0da..3d294e1 100644
}
//------------------------------------------------------------------------------------------------------------------
-diff --git a/src/share/vm/utilities/exceptions.cpp b/src/share/vm/utilities/exceptions.cpp
-index 03f254d..c9e0efc 100644
---- a/src/share/vm/utilities/exceptions.cpp
-+++ b/src/share/vm/utilities/exceptions.cpp
+diff -r 882f6c762ac5 src/share/vm/utilities/exceptions.cpp
+--- a/src/share/vm/utilities/exceptions.cpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/utilities/exceptions.cpp Thu Jul 09 23:18:17 2015 -0700
@@ -254,6 +254,8 @@
assert(thread->is_Java_thread(), "can only be called by a Java thread");
assert(!thread->has_pending_exception(), "already has exception");
@@ -12334,10 +12333,9 @@ index 03f254d..c9e0efc 100644
return h_exception;
}
-diff --git a/src/share/vm/utilities/growableArray.hpp b/src/share/vm/utilities/growableArray.hpp
-index ea92a80..05e940e 100644
---- a/src/share/vm/utilities/growableArray.hpp
-+++ b/src/share/vm/utilities/growableArray.hpp
+diff -r 882f6c762ac5 src/share/vm/utilities/growableArray.hpp
+--- a/src/share/vm/utilities/growableArray.hpp Thu Jul 09 23:10:04 2015 -0700
++++ b/src/share/vm/utilities/growableArray.hpp Thu Jul 09 23:18:17 2015 -0700
@@ -145,6 +145,33 @@
assert(on_stack(), "fast ResourceObj path only");
return (void*)resource_allocate_bytes(thread, elementSize * _max);
@@ -12371,4 +12369,4 @@ index ea92a80..05e940e 100644
+ }
};
- template<class E> class GrowableArray : public GenericGrowableArray { \ No newline at end of file
+ template<class E> class GrowableArray : public GenericGrowableArray {
diff --git a/hotspot/.hg/patches/series b/hotspot/.hg/patches/series
index c15467c0..10f843cb 100644
--- a/hotspot/.hg/patches/series
+++ b/hotspot/.hg/patches/series
@@ -35,8 +35,9 @@ light-jdk7u79-b02.patch #+light-jdk7u79-b02
light-jdk7u60-deopt-cp.patch #+light-jdk7u60-b09 #+light-jdk7u71-b01 #+light-jdk7u79-b02
full-jdk7u60-b09.patch #+full-jdk7u60-b09
full-jdk7u71-b01.patch #+full-jdk7u71-b01
-full-jdk7u79-b02.patch #+full-jdk7u79-b02
-full-jdk7u60-deopt-cp.patch #+full-jdk7u60-b09 #+full-jdk7u71-b01 #+full-jdk7u79-b02
+full-jdk7u79-b15.patch #+full-jdk7u79-b15
+full-jdk7u60-deopt-cp.patch #+full-jdk7u60-b09 #+full-jdk7u71-b01 #+full-jdk7u79-b15
+full-jdk7u79-b15-method-handles.patch #+full-jdk7u79-b15
light-jdk8u5-b13.patch #+light-jdk8u5-b13