--- /dev/null
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+package com.github.dcevm.test.fields;
+
+import com.github.dcevm.test.TestUtil;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import static com.github.dcevm.test.util.HotSwapTestHelper.__toVersion__;
+import static com.github.dcevm.test.util.HotSwapTestHelper.__version__;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test for replacing field with MethodHandle pointing to it.
+ *
+ * @author Ivan Dubrov
+ */
+public class StaticFieldHandleTest {
+
+ // Version 0
+ public static class A {
+ public static int fieldA;
+ public static int fieldB;
+ }
+
+ // Version 1 (fields swapped)
+ public static class A___1 {
+ public static int fieldB;
+ public static int fieldA;
+ }
+
+ // Version 2 (fields removed)
+ public static class A___2 {
+ }
+
+ // Version 3 (field type changed)
+ public static class A___3 {
+ public String fieldA;
+ public int fieldB;
+ }
+
+ @Before
+ @After
+ public void setUp() throws Exception {
+ __toVersion__(0);
+ }
+
+ @Test
+ public void testStaticFieldChangeOrder() throws Throwable {
+ MethodHandle handle = MethodHandles.publicLookup().findStaticGetter(A.class, "fieldA", int.class);
+
+ A.fieldA = 3;
+ A.fieldB = 5;
+ assertEquals(3, handle.invoke());
+
+ // Swap fields A and B
+ __toVersion__(1);
+ assertEquals(3, handle.invoke());
+ }
+
+ @Test
+ @Ignore
+ public void testStaticFieldRemoved() throws Throwable {
+ MethodHandle handle = MethodHandles.publicLookup().findStaticGetter(A.class, "fieldA", int.class);
+
+ A.fieldA = 3;
+ A.fieldB = 5;
+ assertEquals(3, handle.invoke());
+
+ // Remove fieldA
+ __toVersion__(2);
+
+ handle.invoke();
+ }
+
+ @Test
+ @Ignore
+ public void testStaticFieldTypeChange() throws Throwable {
+ MethodHandle handle = MethodHandles.publicLookup().findStaticGetter(A.class, "fieldA", int.class);
+
+ A.fieldA = 3;
+ A.fieldB = 5;
+ assertEquals(3, handle.invoke());
+
+ // Remove fieldA
+ __toVersion__(3);
+
+ handle.invoke();
+ }
+}
\ No newline at end of file
if (method->is_hidden()) {
if (skip_hidden) continue;
}
+@@ -2617,10 +2619,55 @@
+ }
+ }
+
++// 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() {
++ Klass* 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() {
++ Klass* 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;
+ int java_lang_invoke_MethodHandle::_form_offset;
++int java_lang_invoke_MethodHandle::_as_type_cache_offset;
+
+ int java_lang_invoke_MemberName::_clazz_offset;
+ int java_lang_invoke_MemberName::_name_offset;
+@@ -2640,6 +2687,7 @@
+ if (_form_offset == 0) {
+ EnableInvokeDynamic = false;
+ }
++ compute_offset(_as_type_cache_offset, klass_oop, vmSymbols::as_type_cache_name(), vmSymbols::java_lang_invoke_MethodHandle_signature());
+ }
+ }
+
+@@ -2679,6 +2727,16 @@
+ mh->obj_field_put(_form_offset, lform);
+ }
+
++oop java_lang_invoke_MethodHandle::as_type_cache(oop mh) {
++ assert(_as_type_cache_offset != 0, "");
++ return mh->obj_field(_as_type_cache_offset);
++}
++
++void java_lang_invoke_MethodHandle::set_as_type_cache(oop mh, oop as_type_cache) {
++ assert(_as_type_cache_offset != 0, "");
++ mh->obj_field_put(_as_type_cache_offset, as_type_cache);
++}
++
+ /// MemberName accessors
+
+ oop java_lang_invoke_MemberName::clazz(oop mname) {
+@@ -3269,6 +3327,9 @@
+ java_lang_invoke_LambdaForm::compute_offsets();
+ java_lang_invoke_MethodType::compute_offsets();
+ java_lang_invoke_CallSite::compute_offsets();
++
++ java_lang_invoke_DirectMethodHandle_StaticAccessor::compute_offsets();
++ java_lang_invoke_DirectMethodHandle_Accessor::compute_offsets();
+ }
+ java_security_AccessControlContext::compute_offsets();
+ // Initialize reflection classes. The layouts of these classes
+diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
+--- a/src/share/vm/classfile/javaClasses.hpp
++++ b/src/share/vm/classfile/javaClasses.hpp
+@@ -953,6 +953,7 @@
+ private:
+ static int _type_offset; // the MethodType of this MH
+ static int _form_offset; // the LambdaForm of this MH
++ static int _as_type_cache_offset; // (DCEVM) internal cache, cleared on redefinition when field is not available
+
+ static void compute_offsets();
+
+@@ -964,6 +965,9 @@
+ static oop form(oop mh);
+ static void set_form(oop mh, oop lform);
+
++ static oop as_type_cache(oop mh);
++ static void set_as_type_cache(oop mh, oop as_type_cache);
++
+ // Testers
+ static bool is_subclass(Klass* klass) {
+ return klass->is_subclass_of(SystemDictionary::MethodHandle_klass());
+@@ -1003,6 +1007,52 @@
+ 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(Klass* klass) {
++ return klass->is_subclass_of(SystemDictionary::DirectMethodHandle_StaticAccessor_klass());
++ }
++ static bool is_instance(oop obj) {
++ return obj != NULL && is_subclass(obj->klass());
++ }
++};
++
++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(Klass* klass) {
++ return 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 --git a/src/share/vm/classfile/loaderConstraints.cpp b/src/share/vm/classfile/loaderConstraints.cpp
--- a/src/share/vm/classfile/loaderConstraints.cpp
+++ b/src/share/vm/classfile/loaderConstraints.cpp
diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp
--- a/src/share/vm/classfile/systemDictionary.hpp
+++ b/src/share/vm/classfile/systemDictionary.hpp
-@@ -269,7 +269,7 @@
+@@ -151,6 +151,8 @@
+ \
+ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
+ do_klass(DirectMethodHandle_klass, java_lang_invoke_DirectMethodHandle, Opt ) \
++ 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 ) \
+@@ -269,7 +271,7 @@
// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
static Klass* resolve_from_stream(Symbol* class_name, Handle class_loader,
Handle protection_domain,
// Lookup an already loaded class. If not found NULL is returned.
static Klass* find(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS);
-@@ -339,6 +339,8 @@
+@@ -339,6 +341,8 @@
// System loader lock
static oop system_loader_lock() { return _system_loader_lock_obj; }
private:
// Extended Redefine classes support (tbi)
static void preloaded_classes_do(KlassClosure* f);
-@@ -408,6 +410,9 @@
+@@ -408,6 +412,9 @@
initialize_wk_klasses_until((WKID) limit, start_id, THREAD);
}
public:
#define WK_KLASS_DECLARE(name, symbol, option) \
static Klass* name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); } \
-@@ -613,7 +618,7 @@
+@@ -613,7 +620,7 @@
// after waiting, but before reentering SystemDictionary_lock
// to preserve lock order semantics.
static void double_lock_wait(Handle lockObject, TRAPS);
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
+--- a/src/share/vm/classfile/vmSymbols.hpp
++++ b/src/share/vm/classfile/vmSymbols.hpp
+@@ -256,6 +256,8 @@
+ template(java_lang_invoke_CallSite, "java/lang/invoke/CallSite") \
+ template(java_lang_invoke_ConstantCallSite, "java/lang/invoke/ConstantCallSite") \
+ template(java_lang_invoke_DirectMethodHandle, "java/lang/invoke/DirectMethodHandle") \
++ 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_MutableCallSite, "java/lang/invoke/MutableCallSite") \
+ template(java_lang_invoke_VolatileCallSite, "java/lang/invoke/VolatileCallSite") \
+ template(java_lang_invoke_MethodHandle, "java/lang/invoke/MethodHandle") \
+@@ -397,6 +399,11 @@
+ template(signers_name, "signers_name") \
+ template(loader_data_name, "loader_data") \
+ template(dependencies_name, "dependencies") \
++ template(static_offset_name, "staticOffset") \
++ template(static_base_name, "staticBase") \
++ template(field_offset_name, "fieldOffset") \
++ template(field_type_name, "fieldType") \
++ template(as_type_cache_name, "asTypeCache") \
+ \
+ /* non-intrinsic name/signature pairs: */ \
+ template(register_method_name, "register") \
diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp
--- a/src/share/vm/interpreter/linkResolver.cpp
+++ b/src/share/vm/interpreter/linkResolver.cpp
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/jvmtiRedefineClasses2.cpp
-@@ -0,0 +1,2028 @@
+@@ -0,0 +1,2085 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ // Forward pointers to InstanceKlass and mirror class to new versions
+ template <class T>
+ inline void do_oop_work(T* p) {
-+ oop oop = oopDesc::load_decode_heap_oop(p);
-+ if (oop == NULL) {
++ oop obj = oopDesc::load_decode_heap_oop(p);
++ if (obj == NULL) {
+ return;
+ }
-+ if (oop->is_instanceMirror()) {
-+ Klass* klass = java_lang_Class::as_Klass(oop);
++ if (obj->is_instanceMirror()) {
++ Klass* klass = java_lang_Class::as_Klass(obj);
+ if (klass != NULL && klass->oop_is_instance()) {
-+ assert(oop == InstanceKlass::cast(klass)->java_mirror(), "just checking");
++ assert(obj == InstanceKlass::cast(klass)->java_mirror(), "just checking");
+ if (klass->new_version() != NULL) {
-+ oop = InstanceKlass::cast(klass->new_version())->java_mirror();
-+ S::oop_store(p, oop);
++ obj = InstanceKlass::cast(klass->new_version())->java_mirror();
++ S::oop_store(p, obj);
+ }
+ }
+ }
+ RC_TIMER_START(_timer_heap_iteration);
+
+ class ChangePointersObjectClosure : public ObjectClosure {
++ private:
+
-+ private:
++ // 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,
++ };
+
+ OopClosure *_closure;
+ bool _needs_instance_update;
+ Copy::aligned_disjoint_words((HeapWord*)o, (HeapWord*)_tmp_obj, size);
+ }
+
++ void 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)) {
++ Method* m = (Method*) java_lang_invoke_MemberName::vmtarget(obj);
++ if (m != NULL && !m->method_holder()->is_newest_version()) {
++ // Let's try to re-resolve method
++ InstanceKlass* newest = InstanceKlass::cast(m->method_holder()->newest_version());
++ Method* new_method = newest->find_method(m->name(), m->signature());
++
++ // Note: we might set NULL at this point, which should force AbstractMethodError at runtime
++ java_lang_invoke_MemberName::set_vmtarget(obj, new_method);
++ }
++ } else if (MethodHandles::ref_kind_is_field(ref_kind)) {
++ Klass* k = (Klass*) java_lang_invoke_MemberName::vmtarget(obj);
++ if (k != NULL && !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)) {
++ InstanceKlass* newest = InstanceKlass::cast(k->newest_version());
++ fieldDescriptor fd_new;
++ if (newest->find_local_field(fd.name(), fd.signature(), &fd_new)) {
++ java_lang_invoke_MemberName::set_vmtarget(obj, newest);
++ java_lang_invoke_MemberName::set_vmindex(obj, fd_new.offset());
++ } else {
++ // Well, not much we can do here. JVM will crash once faulty MH is invoked.
++ }
++ }
++ }
++ }
++ }
++
++ void update_direct_method_handle(oop obj) {
++ // Always update member name first.
++ oop mem_name = java_lang_invoke_DirectMethodHandle::member(obj);
++ update_member_name(mem_name);
++
++ // 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)) {
++ if (java_lang_invoke_DirectMethodHandle_StaticAccessor::is_instance(obj)) {
++ InstanceKlass* ik = InstanceKlass::cast(obj->klass());
++ if (java_lang_invoke_MemberName::vmindex(mem_name) != 0) {
++ // 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);
++ java_lang_invoke_DirectMethodHandle_StaticAccessor::set_static_offset(obj, offset);
++ }
++ }
++ }
++ }
++
+ virtual void do_object(oop obj) {
++ // 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)) {
++ update_direct_method_handle(obj);
++ }
++
+ // FIXME: if (obj->is_instanceKlass()) return;
+ if (obj->is_instanceMirror()) {
+ // static fields may have references to old java.lang.Class instances, update them
+
+ // JSR-292 support
+
-+ // Transfer method handles
++ // Swap method handles
+ MemberNameTable* mnt = the_old_class->member_names();
+ the_new_class->set_member_names(mnt);
+ the_old_class->set_member_names(NULL);
-+ if (mnt != NULL) {
-+ for (int i = 0; i < mnt->length(); i++) {
-+ oop mem_name = mnt->get_member_name(i);
-+ if (mem_name != NULL) {
-+ Method* method = (Method*) java_lang_invoke_MemberName::vmtarget(mem_name);
-+
-+ // Replace the method with matching one from the new class
-+ Method* new_method = the_new_class->find_method(method->name(), method->signature());
-+ java_lang_invoke_MemberName::set_vmtarget(mem_name, new_method);
-+ }
-+ }
-+ }
-+
+
+#ifdef ASSERT
+