nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
changeset 18841 9bbc4b8832b2
parent 16245 6a1c6c8bc113
child 24778 2ff5d7041566
--- a/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Wed Jul 03 14:08:00 2013 +0530
+++ b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Wed Jul 03 12:39:28 2013 +0200
@@ -84,29 +84,22 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
-import java.lang.reflect.Array;
-import jdk.internal.dynalink.linker.LinkerServices;
-import jdk.internal.dynalink.support.Guards;
 
 /**
- * A dynamic method bound to exactly one, non-overloaded Java method. Handles varargs.
+ * A dynamic method bound to exactly one Java method or constructor that is not caller sensitive. Since its target is
+ * not caller sensitive, this class pre-caches its method handle and always returns it from the call to
+ * {@link #getTarget(Lookup)}. Can be used in general to represents dynamic methods bound to a single method handle,
+ * even if that handle is not mapped to a Java method, i.e. as a wrapper around field getters/setters, array element
+ * getters/setters, etc.
  *
  * @author Attila Szegedi
  */
-class SimpleDynamicMethod extends DynamicMethod {
+class SimpleDynamicMethod extends SingleDynamicMethod {
     private final MethodHandle target;
 
     /**
-     * Creates a simple dynamic method with no name.
-     * @param target the target method handle
-     */
-    SimpleDynamicMethod(MethodHandle target) {
-        this(target, null);
-    }
-
-    /**
      * Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle
      * signature.
      *
@@ -115,125 +108,26 @@
      * @param name the simple name of the method
      */
     SimpleDynamicMethod(MethodHandle target, Class<?> clazz, String name) {
-        this(target, getName(target, clazz, name));
-    }
-
-    SimpleDynamicMethod(MethodHandle target, String name) {
-        super(name);
+        super(getName(target, clazz, name));
         this.target = target;
     }
 
     private static String getName(MethodHandle target, Class<?> clazz, String name) {
-        return getMethodNameWithSignature(target, getClassAndMethodName(clazz, name));
-    }
-
-    static String getMethodNameWithSignature(MethodHandle target, String methodName) {
-        final String typeStr = target.type().toString();
-        final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
-        int secondParamIndex = typeStr.indexOf(',') + 1;
-        if(secondParamIndex == 0) {
-            secondParamIndex = retTypeIndex - 1;
-        }
-        return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
-    }
-
-    /**
-     * Returns the target of this dynamic method
-     *
-     * @return the target of this dynamic method
-     */
-    MethodHandle getTarget() {
-        return target;
+        return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
     }
 
     @Override
-    SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
-        return typeMatchesDescription(paramTypes, target.type()) ? this : null;
+    boolean isVarArgs() {
+        return target.isVarargsCollector();
     }
 
     @Override
-    MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices) {
-        final MethodType methodType = target.type();
-        final int paramsLen = methodType.parameterCount();
-        final boolean varArgs = target.isVarargsCollector();
-        final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
-        final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
-        final int argsLen = callSiteType.parameterCount();
-        if(argsLen < fixParamsLen) {
-            // Less actual arguments than number of fixed declared arguments; can't invoke.
-            return null;
-        }
-        // Method handle has the same number of fixed arguments as the call site type
-        if(argsLen == fixParamsLen) {
-            // Method handle that matches the number of actual arguments as the number of fixed arguments
-            final MethodHandle matchedMethod;
-            if(varArgs) {
-                // If vararg, add a zero-length array of the expected type as the last argument to signify no variable
-                // arguments.
-                matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
-                        methodType.parameterType(fixParamsLen).getComponentType(), 0));
-            } else {
-                // Otherwise, just use the method
-                matchedMethod = fixTarget;
-            }
-            return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
-        }
-
-        // What's below only works for varargs
-        if(!varArgs) {
-            return null;
-        }
-
-        final Class<?> varArgType = methodType.parameterType(fixParamsLen);
-        // Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
-        // must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
-        if(argsLen == paramsLen) {
-            final Class<?> callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
-            if(varArgType.isAssignableFrom(callSiteLastArgType)) {
-                // Call site signature guarantees we'll always be passed a single compatible array; just link directly
-                // to the method.
-                return createConvertingInvocation(fixTarget, linkerServices, callSiteType);
-            }
-            if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
-                // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
-                // link immediately to a vararg-packing method handle.
-                return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
-            }
-            // Call site signature makes no guarantees that the single argument in the vararg position will be
-            // compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
-            // method when it is not.
-            return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
-                    createConvertingInvocation(fixTarget, linkerServices, callSiteType),
-                    createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
-        }
-
-        // Remaining case: more than one vararg.
-        return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
+    MethodType getMethodType() {
+        return target.type();
     }
 
     @Override
-    public boolean contains(MethodHandle mh) {
-        return target.type().parameterList().equals(mh.type().parameterList());
-    }
-
-    /**
-     * Creates a method handle out of the original target that will collect the varargs for the exact component type of
-     * the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
-     * for which it is necessary when later passed to linkerServices.convertArguments().
-     *
-     * @param target the original method handle
-     * @param parameterCount the total number of arguments in the new method handle
-     * @return a collecting method handle
-     */
-    static MethodHandle collectArguments(MethodHandle target, final int parameterCount) {
-        final MethodType methodType = target.type();
-        final int fixParamsLen = methodType.parameterCount() - 1;
-        final Class<?> arrayType = methodType.parameterType(fixParamsLen);
-        return target.asCollector(arrayType, parameterCount - fixParamsLen);
-    }
-
-    private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod,
-            final LinkerServices linkerServices, final MethodType callSiteType) {
-        return linkerServices.asType(sizedMethod, callSiteType);
+    MethodHandle getTarget(Lookup lookup) {
+        return target;
     }
 }