Procházet zdrojové kódy

Working on static field DMH's fixes

tags/light-jdk8u5+52
Ivan Dubrov před 10 roky
rodič
revize
ad604726a8

+ 118
- 0
dcevm/src/test/java7/com/github/dcevm/test/fields/StaticFieldHandleTest.java Zobrazit soubor

@@ -0,0 +1,118 @@
/*
* 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();
}
}

+ 282
- 27
hotspot/.hg/patches/light-jdk8u5-b13.patch Zobrazit soubor

@@ -392,6 +392,171 @@ diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/jav
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
@@ -561,7 +726,16 @@ diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfil
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,
@@ -570,7 +744,7 @@ diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfil
// 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; }
@@ -579,7 +753,7 @@ diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfil
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);
}
@@ -589,7 +763,7 @@ diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfil
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);
@@ -639,6 +813,30 @@ diff --git a/src/share/vm/classfile/verifier.hpp b/src/share/vm/classfile/verifi
instanceKlassHandle _klass; // the class being verified
methodHandle _method; // current method being verified
VerificationType _this_type; // the verification type of the current class
diff --git a/src/share/vm/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
@@ -1365,7 +1563,7 @@ diff --git a/src/share/vm/prims/jvmtiRedefineClasses2.cpp b/src/share/vm/prims/j
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.
@@ -2434,17 +2632,17 @@ new file mode 100644
+ // 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);
+ }
+ }
+ }
@@ -2495,8 +2693,13 @@ new file mode 100644
+ 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;
@@ -2519,7 +2722,72 @@ new file mode 100644
+ 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
@@ -2989,23 +3257,10 @@ new file mode 100644
+
+ // 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
+

Načítá se…
Zrušit
Uložit