src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java

changeset 404
18d467e94150
parent 101
f8221ce53c2e
child 952
6d5471a497fb
child 962
ac62e33a99b0
     1.1 --- a/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Wed Jul 03 14:08:00 2013 +0530
     1.2 +++ b/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Wed Jul 03 12:39:28 2013 +0200
     1.3 @@ -84,29 +84,22 @@
     1.4  package jdk.internal.dynalink.beans;
     1.5  
     1.6  import java.lang.invoke.MethodHandle;
     1.7 -import java.lang.invoke.MethodHandles;
     1.8 +import java.lang.invoke.MethodHandles.Lookup;
     1.9  import java.lang.invoke.MethodType;
    1.10 -import java.lang.reflect.Array;
    1.11 -import jdk.internal.dynalink.linker.LinkerServices;
    1.12 -import jdk.internal.dynalink.support.Guards;
    1.13  
    1.14  /**
    1.15 - * A dynamic method bound to exactly one, non-overloaded Java method. Handles varargs.
    1.16 + * A dynamic method bound to exactly one Java method or constructor that is not caller sensitive. Since its target is
    1.17 + * not caller sensitive, this class pre-caches its method handle and always returns it from the call to
    1.18 + * {@link #getTarget(Lookup)}. Can be used in general to represents dynamic methods bound to a single method handle,
    1.19 + * even if that handle is not mapped to a Java method, i.e. as a wrapper around field getters/setters, array element
    1.20 + * getters/setters, etc.
    1.21   *
    1.22   * @author Attila Szegedi
    1.23   */
    1.24 -class SimpleDynamicMethod extends DynamicMethod {
    1.25 +class SimpleDynamicMethod extends SingleDynamicMethod {
    1.26      private final MethodHandle target;
    1.27  
    1.28      /**
    1.29 -     * Creates a simple dynamic method with no name.
    1.30 -     * @param target the target method handle
    1.31 -     */
    1.32 -    SimpleDynamicMethod(MethodHandle target) {
    1.33 -        this(target, null);
    1.34 -    }
    1.35 -
    1.36 -    /**
    1.37       * Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle
    1.38       * signature.
    1.39       *
    1.40 @@ -115,125 +108,26 @@
    1.41       * @param name the simple name of the method
    1.42       */
    1.43      SimpleDynamicMethod(MethodHandle target, Class<?> clazz, String name) {
    1.44 -        this(target, getName(target, clazz, name));
    1.45 -    }
    1.46 -
    1.47 -    SimpleDynamicMethod(MethodHandle target, String name) {
    1.48 -        super(name);
    1.49 +        super(getName(target, clazz, name));
    1.50          this.target = target;
    1.51      }
    1.52  
    1.53      private static String getName(MethodHandle target, Class<?> clazz, String name) {
    1.54 -        return getMethodNameWithSignature(target, getClassAndMethodName(clazz, name));
    1.55 -    }
    1.56 -
    1.57 -    static String getMethodNameWithSignature(MethodHandle target, String methodName) {
    1.58 -        final String typeStr = target.type().toString();
    1.59 -        final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
    1.60 -        int secondParamIndex = typeStr.indexOf(',') + 1;
    1.61 -        if(secondParamIndex == 0) {
    1.62 -            secondParamIndex = retTypeIndex - 1;
    1.63 -        }
    1.64 -        return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
    1.65 -    }
    1.66 -
    1.67 -    /**
    1.68 -     * Returns the target of this dynamic method
    1.69 -     *
    1.70 -     * @return the target of this dynamic method
    1.71 -     */
    1.72 -    MethodHandle getTarget() {
    1.73 -        return target;
    1.74 +        return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
    1.75      }
    1.76  
    1.77      @Override
    1.78 -    SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
    1.79 -        return typeMatchesDescription(paramTypes, target.type()) ? this : null;
    1.80 +    boolean isVarArgs() {
    1.81 +        return target.isVarargsCollector();
    1.82      }
    1.83  
    1.84      @Override
    1.85 -    MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices) {
    1.86 -        final MethodType methodType = target.type();
    1.87 -        final int paramsLen = methodType.parameterCount();
    1.88 -        final boolean varArgs = target.isVarargsCollector();
    1.89 -        final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
    1.90 -        final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
    1.91 -        final int argsLen = callSiteType.parameterCount();
    1.92 -        if(argsLen < fixParamsLen) {
    1.93 -            // Less actual arguments than number of fixed declared arguments; can't invoke.
    1.94 -            return null;
    1.95 -        }
    1.96 -        // Method handle has the same number of fixed arguments as the call site type
    1.97 -        if(argsLen == fixParamsLen) {
    1.98 -            // Method handle that matches the number of actual arguments as the number of fixed arguments
    1.99 -            final MethodHandle matchedMethod;
   1.100 -            if(varArgs) {
   1.101 -                // If vararg, add a zero-length array of the expected type as the last argument to signify no variable
   1.102 -                // arguments.
   1.103 -                matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
   1.104 -                        methodType.parameterType(fixParamsLen).getComponentType(), 0));
   1.105 -            } else {
   1.106 -                // Otherwise, just use the method
   1.107 -                matchedMethod = fixTarget;
   1.108 -            }
   1.109 -            return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
   1.110 -        }
   1.111 -
   1.112 -        // What's below only works for varargs
   1.113 -        if(!varArgs) {
   1.114 -            return null;
   1.115 -        }
   1.116 -
   1.117 -        final Class<?> varArgType = methodType.parameterType(fixParamsLen);
   1.118 -        // Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
   1.119 -        // must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
   1.120 -        if(argsLen == paramsLen) {
   1.121 -            final Class<?> callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
   1.122 -            if(varArgType.isAssignableFrom(callSiteLastArgType)) {
   1.123 -                // Call site signature guarantees we'll always be passed a single compatible array; just link directly
   1.124 -                // to the method.
   1.125 -                return createConvertingInvocation(fixTarget, linkerServices, callSiteType);
   1.126 -            }
   1.127 -            if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
   1.128 -                // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
   1.129 -                // link immediately to a vararg-packing method handle.
   1.130 -                return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
   1.131 -            }
   1.132 -            // Call site signature makes no guarantees that the single argument in the vararg position will be
   1.133 -            // compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
   1.134 -            // method when it is not.
   1.135 -            return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
   1.136 -                    createConvertingInvocation(fixTarget, linkerServices, callSiteType),
   1.137 -                    createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
   1.138 -        }
   1.139 -
   1.140 -        // Remaining case: more than one vararg.
   1.141 -        return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
   1.142 +    MethodType getMethodType() {
   1.143 +        return target.type();
   1.144      }
   1.145  
   1.146      @Override
   1.147 -    public boolean contains(MethodHandle mh) {
   1.148 -        return target.type().parameterList().equals(mh.type().parameterList());
   1.149 -    }
   1.150 -
   1.151 -    /**
   1.152 -     * Creates a method handle out of the original target that will collect the varargs for the exact component type of
   1.153 -     * the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
   1.154 -     * for which it is necessary when later passed to linkerServices.convertArguments().
   1.155 -     *
   1.156 -     * @param target the original method handle
   1.157 -     * @param parameterCount the total number of arguments in the new method handle
   1.158 -     * @return a collecting method handle
   1.159 -     */
   1.160 -    static MethodHandle collectArguments(MethodHandle target, final int parameterCount) {
   1.161 -        final MethodType methodType = target.type();
   1.162 -        final int fixParamsLen = methodType.parameterCount() - 1;
   1.163 -        final Class<?> arrayType = methodType.parameterType(fixParamsLen);
   1.164 -        return target.asCollector(arrayType, parameterCount - fixParamsLen);
   1.165 -    }
   1.166 -
   1.167 -    private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod,
   1.168 -            final LinkerServices linkerServices, final MethodType callSiteType) {
   1.169 -        return linkerServices.asType(sizedMethod, callSiteType);
   1.170 +    MethodHandle getTarget(Lookup lookup) {
   1.171 +        return target;
   1.172      }
   1.173  }

mercurial