--- 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;
}
}