changeset 48926:486fbc280f39 condy-folding

Support for VarHandle.toSymbolicRef
author psandoz
date Fri, 19 Jan 2018 16:02:22 -0800
parents a12a140204e3
children 369c4b342c3e
files src/java.base/share/classes/java/lang/invoke/VarHandle.java src/java.base/share/classes/java/lang/invoke/VarHandles.java src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template src/java.base/share/classes/java/lang/sym/SymbolicRefs.java test/jdk/java/lang/sym/DynamicConstantRefTest.java
diffstat 5 files changed, 81 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java	Fri Jan 19 15:06:08 2018 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java	Fri Jan 19 16:02:22 2018 -0800
@@ -1985,8 +1985,8 @@
 
     @Override
     public Optional<VarHandleRef> toSymbolicRef(MethodHandles.Lookup lookup) {
-        // @@@ this is a partial function for field and array
-        throw new UnsupportedOperationException();
+        // partial function for field and array only
+        return Optional.empty();
     }
 
     @Stable
--- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java	Fri Jan 19 15:06:08 2018 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java	Fri Jan 19 16:02:22 2018 -0800
@@ -25,6 +25,9 @@
 
 package java.lang.invoke;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 
 final class VarHandles {
@@ -144,6 +147,38 @@
         }
     }
 
+    // Required by instance field handles
+    static Field getFieldFromRecieverAndOffset(Class<?> receiverType,
+                                               long offset,
+                                               Class<?> fieldType) {
+        for (Field f : receiverType.getDeclaredFields()) {
+            if (Modifier.isStatic(f.getModifiers())) continue;
+
+            if (offset == UNSAFE.objectFieldOffset(f)) {
+                assert f.getType() == fieldType;
+                return f;
+            }
+        }
+        throw new InternalError("Field not found at offset");
+    }
+
+    // Required by instance static field handles
+    static Field getStaticFieldFromBaseAndOffset(Object base,
+                                                 long offset,
+                                                 Class<?> fieldType) {
+        // @@@ This is a little fragile assuming the base is the class
+        Class<?> receiverType = (Class<?>) base;
+        for (Field f : receiverType.getDeclaredFields()) {
+            if (!Modifier.isStatic(f.getModifiers())) continue;
+
+            if (offset == UNSAFE.staticFieldOffset(f)) {
+                assert f.getType() == fieldType;
+                return f;
+            }
+        }
+        throw new InternalError("Static field not found at offset");
+    }
+
     static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
         if (!arrayClass.isArray())
             throw new IllegalArgumentException("not an array: " + arrayClass);
--- a/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template	Fri Jan 19 15:06:08 2018 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template	Fri Jan 19 16:02:22 2018 -0800
@@ -27,7 +27,9 @@
 import jdk.internal.util.Preconditions;
 import jdk.internal.vm.annotation.ForceInline;
 
+import java.lang.sym.VarHandleRef;
 import java.util.Objects;
+import java.util.Optional;
 
 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 
@@ -72,6 +74,18 @@
             return Long.hashCode(fieldOffset);
         }
 
+        @Override
+        public Optional<VarHandleRef> toSymbolicRef(MethodHandles.Lookup lookup) {
+            var receiverTypeRef = receiverType.toSymbolicRef(lookup);
+            var fieldTypeRef = {#if[Object]?fieldType:$type$.class}.toSymbolicRef(lookup);
+            if (!receiverTypeRef.isPresent() || !fieldTypeRef.isPresent())
+                return Optional.empty();
+
+            String name = VarHandles.getFieldFromRecieverAndOffset(
+                receiverType, fieldOffset, {#if[Object]?fieldType:$type$.class}).getName();
+            return Optional.of(VarHandleRef.ofField(receiverTypeRef.get(), name, fieldTypeRef.get()));
+        }
+
         @ForceInline
         static $type$ get(FieldInstanceReadOnly handle, Object holder) {
             return UNSAFE.get$Type$(Objects.requireNonNull(handle.receiverType.cast(holder)),
@@ -346,6 +360,20 @@
         }
 
         @Override
+        public Optional<VarHandleRef> toSymbolicRef(MethodHandles.Lookup lookup) {
+            var fieldTypeRef = {#if[Object]?fieldType:$type$.class}.toSymbolicRef(lookup);
+            if (!fieldTypeRef.isPresent())
+                return Optional.empty();
+
+            var staticField = VarHandles.getStaticFieldFromBaseAndOffset(
+                base, fieldOffset, {#if[Object]?fieldType:$type$.class});
+            var receiverTypeRef = staticField.getDeclaringClass().toSymbolicRef(lookup);
+            if (!receiverTypeRef.isPresent())
+                return Optional.empty();
+            return Optional.of(VarHandleRef.ofStaticField(receiverTypeRef.get(), staticField.getName(), fieldTypeRef.get()));
+        }
+
+        @Override
         final MethodType accessModeTypeUncached(AccessMode accessMode) {
             return accessMode.at.accessModeType(null, {#if[Object]?fieldType:$type$.class});
         }
@@ -610,6 +638,15 @@
         }
 
         @Override
+        public Optional<VarHandleRef> toSymbolicRef(MethodHandles.Lookup lookup) {
+            var arrayTypeRef = {#if[Object]?arrayType:$type$[].class}.toSymbolicRef(lookup);
+            if (!arrayTypeRef.isPresent())
+                return Optional.empty();
+
+            return Optional.of(VarHandleRef.ofArray(arrayTypeRef.get()));
+        }
+
+        @Override
         final MethodType accessModeTypeUncached(AccessMode accessMode) {
             return accessMode.at.accessModeType({#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class);
         }
--- a/src/java.base/share/classes/java/lang/sym/SymbolicRefs.java	Fri Jan 19 15:06:08 2018 -0800
+++ b/src/java.base/share/classes/java/lang/sym/SymbolicRefs.java	Fri Jan 19 16:02:22 2018 -0800
@@ -255,15 +255,15 @@
 
     @Foldable
     static final MethodHandleRef MHR_VARHANDLEREF_FIELD_FACTORY
-            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_VarHandleRef, "fieldVarHandle", CR_VarHandleRef, CR_ClassRef, CR_String, CR_ClassRef);
+            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_VarHandleRef, "ofField", CR_VarHandleRef, CR_ClassRef, CR_String, CR_ClassRef);
 
     @Foldable
     static final MethodHandleRef MHR_VARHANDLEREF_STATIC_FIELD_FACTORY
-            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_VarHandleRef, "staticFieldVarHandle", CR_VarHandleRef, CR_ClassRef, CR_String, CR_ClassRef);
+            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_VarHandleRef, "ofStaticField", CR_VarHandleRef, CR_ClassRef, CR_String, CR_ClassRef);
 
     @Foldable
     static final MethodHandleRef MHR_VARHANDLEREF_ARRAY_FACTORY
-            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_VarHandleRef, "arrayVarHandle", CR_VarHandleRef, CR_ClassRef);
+            = MethodHandleRef.of(MethodHandleRef.Kind.STATIC, CR_VarHandleRef, "ofArray", CR_VarHandleRef, CR_ClassRef);
 
     @Foldable
     static final MethodHandleRef MHR_DYNAMICCONSTANTREF_FACTORY
--- a/test/jdk/java/lang/sym/DynamicConstantRefTest.java	Fri Jan 19 15:06:08 2018 -0800
+++ b/test/jdk/java/lang/sym/DynamicConstantRefTest.java	Fri Jan 19 16:02:22 2018 -0800
@@ -60,11 +60,11 @@
         assertEquals(r.resolveRef(LOOKUP), c);
     }
 
-    private void testVarHandleRef(DynamicConstantRef<VarHandle> r, VarHandle vh) {
-//        testSymbolicRef(r);
-//        assertEquals(r.resolveRef(LOOKUP), vh);
+    private void testVarHandleRef(DynamicConstantRef<VarHandle> r, VarHandle vh) throws ReflectiveOperationException  {
+        testSymbolicRef(r);
+        assertEquals(r.resolveRef(LOOKUP), vh);
 
-//        assertEquals(vh.toSymbolicRef(LOOKUP).get(), r);
+        assertEquals(vh.toSymbolicRef(LOOKUP).get(), r);
         // @@@ Test other assertable properties
     }