jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java
changeset 36934 590fc47a0aeb
parent 36435 0408881ad616
child 37343 35a2231828a7
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Mar 24 11:21:18 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Mar 24 11:21:21 2016 +0100
@@ -25,12 +25,15 @@
 
 package java.lang.invoke;
 
+import jdk.internal.ref.CleanerFactory;
+import sun.invoke.util.Wrapper;
+
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.reflect.Field;
+
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
-import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandleStatics.TRACE_METHOD_LINKAGE;
 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
-import jdk.internal.ref.CleanerFactory;
 
 /**
  * The JVM interface for the method handles package is all here.
@@ -367,8 +370,14 @@
                                      Class<?> defc, String name, Object type,
                                      Object[] appendixResult) {
         try {
-            if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
-                return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult);
+            if (refKind == REF_invokeVirtual) {
+                if (defc == MethodHandle.class) {
+                    return Invokers.methodHandleInvokeLinkerMethod(
+                            name, fixMethodType(callerClass, type), appendixResult);
+                } else if (defc == VarHandle.class) {
+                    return varHandleOperationLinkerMethod(
+                            name, fixMethodType(callerClass, type), appendixResult);
+                }
             }
         } catch (Throwable ex) {
             if (ex instanceof LinkageError)
@@ -400,6 +409,80 @@
         }
     }
 
+    /**
+     * Obtain the method to link to the VarHandle operation.
+     * This method is located here and not in Invokers to avoid
+     * intializing that and other classes early on in VM bootup.
+     */
+    private static MemberName varHandleOperationLinkerMethod(String name,
+                                                             MethodType mtype,
+                                                             Object[] appendixResult) {
+        // Get the signature method type
+        MethodType sigType = mtype.basicType();
+
+        // Get the access kind from the method name
+        VarHandle.AccessMode ak;
+        try {
+            ak = VarHandle.AccessMode.valueOf(name);
+        } catch (IllegalArgumentException e) {
+            throw MethodHandleStatics.newInternalError(e);
+        }
+
+        // If not polymorphic in the return type, such as the compareAndSet
+        // methods that return boolean
+        if (ak.isPolyMorphicInReturnType) {
+            if (ak.returnType != mtype.returnType()) {
+                // The caller contains a different return type than that
+                // defined by the method
+                throw newNoSuchMethodErrorOnVarHandle(name, mtype);
+            }
+            // Adjust the return type of the signature method type
+            sigType = sigType.changeReturnType(ak.returnType);
+        }
+
+        // Get the guard method type for linking
+        MethodType guardType = sigType
+                // VarHandle at start
+                .insertParameterTypes(0, VarHandle.class)
+                // Access descriptor at end
+                .appendParameterTypes(VarHandle.AccessDescriptor.class);
+
+        // Create the appendix descriptor constant
+        VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal());
+        appendixResult[0] = ad;
+
+        if (MethodHandleStatics.VAR_HANDLE_GUARDS) {
+            MemberName linker = new MemberName(
+                    VarHandleGuards.class, "guard_" + getVarHandleMethodSignature(sigType),
+                    guardType, REF_invokeStatic);
+            try {
+                return MemberName.getFactory().resolveOrFail(
+                        REF_invokeStatic, linker, VarHandleGuards.class, ReflectiveOperationException.class);
+            } catch (ReflectiveOperationException ex) {
+                // Fall back to lambda form linkage if guard method is not available
+                // TODO Optionally log fallback ?
+            }
+        }
+        return Invokers.varHandleInvokeLinkerMethod(name, mtype);
+    }
+    static String getVarHandleMethodSignature(MethodType mt) {
+        StringBuilder sb = new StringBuilder(mt.parameterCount() + 1);
+
+        for (int i = 0; i < mt.parameterCount(); i++) {
+            Class<?> pt = mt.parameterType(i);
+            sb.append(getCharType(pt));
+        }
+
+        sb.append('_').append(getCharType(mt.returnType()));
+
+        return sb.toString();
+    }
+    static char getCharType(Class<?> pt) {
+        return Wrapper.forBasicType(pt).basicTypeChar();
+    }
+    static NoSuchMethodError newNoSuchMethodErrorOnVarHandle(String name, MethodType mtype) {
+        return new NoSuchMethodError("VarHandle." + name + mtype);
+    }
 
     /**
      * The JVM is resolving a CONSTANT_MethodHandle CP entry.  And it wants our help.