8006293: Reduce ScriptObject.findCallMethodMethod
Reviewed-by: lagergren, jlaskey
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java Mon Jan 14 21:30:13 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Jan 15 13:10:20 2013 +0100
@@ -62,9 +62,6 @@
/** Method handle for name getter for this ScriptFunction */
public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class);
- /** Method handle for invokehelper for this ScriptFunction - used from applies */
- public static final MethodHandle INVOKEHELPER = findOwnMH("invokeHelper", Object.class, Object.class, Object.class, Object[].class);
-
/** Method handle for allocate function for this ScriptFunction */
public static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class);
@@ -387,24 +384,6 @@
}
/**
- * Helper function used for implementation of apply
- * @param func script function
- * @param self reference to {@code this} for apply
- * @param args arguments to apply
- * @return result of apply
- * @throws Throwable if invocation throws an error or exception
- */
- public static Object invokeHelper(final Object func, final Object self, final Object... args) throws Throwable {
- if (func instanceof ScriptFunction) {
- return ((ScriptFunction)func).invoke(self, args);
- }
-
- typeError(Context.getGlobal(), "not.a.function", ScriptRuntime.safeToString(func));
-
- return UNDEFINED;
- }
-
- /**
* Construct new object using this constructor.
* @param self Target object.
* @param args Call arguments.
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Mon Jan 14 21:30:13 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Tue Jan 15 13:10:20 2013 +0100
@@ -69,7 +69,6 @@
import org.dynalang.dynalink.CallSiteDescriptor;
import org.dynalang.dynalink.linker.GuardedInvocation;
import org.dynalang.dynalink.support.CallSiteDescriptorFactory;
-import org.dynalang.dynalink.support.Guards;
/**
* Base class for generic JavaScript objects.
@@ -1587,7 +1586,10 @@
}
/**
- * Find the appropriate CALL method for an invoke dynamic call.
+ * Find an implementation for a "dyn:callMethod" operation. Note that Nashorn internally never uses
+ * "dyn:callMethod", but instead always emits two call sites in bytecode, one for "dyn:getMethod", and then another
+ * one for "dyn:call". Explicit support for "dyn:callMethod" is provided for the benefit of potential external
+ * callers. The implementation itself actually folds a "dyn:getMethod" method handle into a "dyn:call" method handle.
*
* @param desc The call site descriptor.
* @param megaMorphic is this call site megaMorphic, as reported by Dynalink - then just do apply
@@ -1595,49 +1597,18 @@
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final boolean megaMorphic) {
- final String name = desc.getNameToken(2);
- final MethodType callType = desc.getMethodType();
- final FindProperty find = findProperty(name, true);
-
- if (find == null) {
- return createNoSuchMethodInvocation(desc);
- }
-
- if (find.getProperty().hasGetterFunction()) {
- final GuardedInvocation link = findGetMethod(CallSiteDescriptorFactory.changeReturnType(desc, Object.class), megaMorphic, "getMethod");
- final MethodHandle getter = link.getInvocation(); //this cannot be anything but an object as this is the function
-
- MethodHandle invoker = ScriptFunction.INVOKEHELPER;
- invoker = MH.asCollector(invoker, Object[].class, callType.parameterCount() - 1); //deduct self
- invoker = MH.foldArguments(invoker, MH.asType(getter, getter.type().changeReturnType(Object.class))); //getter->func to first arguments. self and object parameters remain
-
- return new GuardedInvocation(invoker, link.getSwitchPoint(), link.getGuard());
- }
-
- //retrieve the appropriate scriptfunction
- final Object value = getObjectValue(find);
-
- MethodHandle methodHandle = getCallMethodHandle(value, callType, null);
-
- if (methodHandle != null) {
- if (find.isScope()) {
- final boolean strictCallee = ((ScriptFunction)value).isStrict();
- if (strictCallee && NashornCallSiteDescriptor.isScope(desc)) {
- methodHandle = bindTo(methodHandle, UNDEFINED);
- } else {
- methodHandle = bindTo(methodHandle, Context.getGlobal());
- }
- }
-
- final MethodHandle guard = find.isSelf() ? Guards.getIdentityGuard(this) : NashornGuards.getMapGuard(getMap());
- final int invokeFlags = ((ScriptFunction)value).isStrict()? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
-
- return new NashornGuardedInvocation(methodHandle, null, guard, invokeFlags);
- }
-
- typeError(Context.getGlobal(), "no.such.function", name, ScriptRuntime.safeToString(this));
-
- throw new AssertionError("should not reach here");
+ // R(P0, P1, ...)
+ final MethodType callType = desc.getMethodType();
+ // use type Object(P0) for the getter
+ final CallSiteDescriptor getterType = desc.changeMethodType(MethodType.methodType(Object.class, callType.parameterType(0)));
+ final GuardedInvocation getter = findGetMethod(getterType, megaMorphic, "getMethod");
+
+ // Object(P0) => Object(P0, P1, ...)
+ final MethodHandle argDroppingGetter = MH.dropArguments(getter.getInvocation(), 1, callType.parameterList().subList(1, callType.parameterCount()));
+ // R(Object, P0, P1, ...)
+ final MethodHandle invoker = Bootstrap.createDynamicInvoker("dyn:call", callType.insertParameterTypes(0, argDroppingGetter.type().returnType()));
+ // Fold Object(P0, P1, ...) into R(Object, P0, P1, ...) => R(P0, P1, ...)
+ return getter.replaceMethods(MH.foldArguments(invoker, argDroppingGetter), getter.getGuard());
}
/**
@@ -1923,41 +1894,6 @@
}
/**
- * Create an invocation that will raise NoSuchMethod error
- *
- * @param desc call site descriptor
- *
- * @return Guarded invocation to be invoked at the call site
- */
- public GuardedInvocation createNoSuchMethodInvocation(final CallSiteDescriptor desc) {
- final String name = desc.getNameToken(2);
- final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true);
- final boolean scopeCall = isScope() && NashornCallSiteDescriptor.isScope(desc);
-
- if (find != null) {
- final ScriptFunction func = (ScriptFunction)getObjectValue(find);
- MethodHandle methodHandle = getCallMethodHandle(func, desc.getMethodType(), name);
-
- if (methodHandle != null) {
- if (scopeCall && func.isStrict()) {
- methodHandle = bindTo(methodHandle, UNDEFINED);
- }
- return new GuardedInvocation(methodHandle,
- find.isInherited()? getMap().getProtoGetSwitchPoint(NO_SUCH_PROPERTY_NAME) : null,
- getKnownFunctionPropertyGuard(getMap(), find.getGetter(Object.class), find.getOwner(), func));
- }
- }
-
- if (scopeCall) {
- referenceError(Context.getGlobal(), "not.defined", name);
- } else {
- typeError(Context.getGlobal(), "no.such.function", name, ScriptRuntime.safeToString(this));
- }
-
- return null;
- }
-
- /**
* Fall back if a property is not found.
* @param desc the call site descriptor.
* @return GuardedInvocation to be invoked at call site.
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java Mon Jan 14 21:30:13 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java Tue Jan 15 13:10:20 2013 +0100
@@ -131,12 +131,13 @@
// the property is not found - now check for
// __noSuchProperty__ and __noSuchMethod__ in expression
if (self != null) {
- String fallBack;
+ final String fallBack;
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
switch (operator) {
case "callMethod":
+ throw new AssertionError(); // Nashorn never emits callMethod
case "getMethod":
fallBack = NO_SUCH_METHOD_NAME;
break;
@@ -153,9 +154,6 @@
find = self.findProperty(fallBack, true);
if (find != null) {
switch (operator) {
- case "callMethod":
- link = self.createNoSuchMethodInvocation(desc);
- break;
case "getMethod":
link = self.noSuchMethod(desc);
break;
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Mon Jan 14 21:30:13 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Tue Jan 15 13:10:20 2013 +0100
@@ -79,7 +79,7 @@
}
/**
- * Return a dynamic invoker for a specified dynamic operation. You can use this method to create a method handle
+ * Returns a dynamic invoker for a specified dynamic operation. You can use this method to create a method handle
* that when invoked acts completely as if it were a Nashorn-linked call site. An overview of available dynamic
* operations can be found in the <a href="https://github.com/szegedi/dynalink/wiki/User-Guide-0.4">Dynalink User Guide</a>,
* but we'll show few examples here:
@@ -170,12 +170,24 @@
* delegating to the function will be returned.</li>
* </ul>
* @param opDesc Dynalink dynamic operation descriptor.
- * @param rtype return type of the operation
- * @param ptypes parameter types of the operation
+ * @param rtype the return type for the operation
+ * @param ptypes the parameter types for the operation
* @return MethodHandle for invoking the operation.
*/
public static MethodHandle createDynamicInvoker(final String opDesc, final Class<?> rtype, final Class<?>... ptypes) {
- return bootstrap(null, opDesc, MethodType.methodType(rtype, ptypes), 0).dynamicInvoker();
+ return createDynamicInvoker(opDesc, MethodType.methodType(rtype, ptypes));
+ }
+
+ /**
+ * Returns a dynamic invoker for a specified dynamic operation. Similar to
+ * {@link #createDynamicInvoker(String, Class, Class...)} but with return and parameter types composed into a
+ * method type in the signature. See the discussion of that method for details.
+ * @param opDesc Dynalink dynamic operation descriptor.
+ * @param type the method type for the operation
+ * @return MethodHandle for invoking the operation.
+ */
+ public static MethodHandle createDynamicInvoker(final String opDesc, final MethodType type) {
+ return bootstrap(null, opDesc, type, 0).dynamicInvoker();
}
/**
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/MethodHandleFactory.java Mon Jan 14 21:30:13 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/MethodHandleFactory.java Tue Jan 15 13:10:20 2013 +0100
@@ -25,12 +25,6 @@
package jdk.nashorn.internal.runtime.linker;
-import jdk.nashorn.internal.runtime.ConsString;
-import jdk.nashorn.internal.runtime.Debug;
-import jdk.nashorn.internal.runtime.DebugLogger;
-import jdk.nashorn.internal.runtime.ScriptObject;
-import jdk.nashorn.internal.runtime.options.Options;
-
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.invoke.MethodHandle;
@@ -42,6 +36,11 @@
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
+import jdk.nashorn.internal.runtime.ConsString;
+import jdk.nashorn.internal.runtime.Debug;
+import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.options.Options;
/**
* This class is abstraction for all method handle, switchpoint and method type
@@ -299,6 +298,11 @@
}
@Override
+ public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> valueTypes) {
+ return MethodHandles.dropArguments(target, pos, valueTypes);
+ }
+
+ @Override
public MethodHandle asType(final MethodHandle handle, final MethodType type) {
return handle.asType(type);
}
@@ -500,6 +504,12 @@
}
@Override
+ public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> values) {
+ final MethodHandle mh = super.dropArguments(target, pos, values);
+ return debug(mh, "dropArguments", target, pos, values);
+ }
+
+ @Override
public MethodHandle asType(final MethodHandle handle, final MethodType type) {
final MethodHandle mh = super.asType(handle, type);
return debug(mh, "asType", handle, type);
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/MethodHandleFunctionality.java Mon Jan 14 21:30:13 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/MethodHandleFunctionality.java Tue Jan 15 13:10:20 2013 +0100
@@ -30,6 +30,7 @@
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.lang.reflect.Method;
+import java.util.List;
/**
* Wrapper for all method handle related functions used in Nashorn. This interface only exists
@@ -92,6 +93,17 @@
public MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes);
/**
+ * Wrapper for {@link MethodHandles#dropArguments(MethodHandle, int, List)}
+ *
+ * @param target target method handle
+ * @param pos start argument index
+ * @param valueTypes valueTypes of arguments to drop
+ *
+ * @return handle with dropped arguments
+ */
+ public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> valueTypes);
+
+ /**
* Wrapper for {@link MethodHandles#foldArguments(MethodHandle, MethodHandle)}
*
* @param target target method handle