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 }