8006293: Reduce ScriptObject.findCallMethodMethod

Reviewed-by: lagergren, jlaskey
This commit is contained in:
Attila Szegedi 2013-01-15 13:10:20 +01:00
parent 246e4e8daf
commit 0c53c5de50
6 changed files with 61 additions and 114 deletions

View File

@ -62,9 +62,6 @@ public abstract class ScriptFunction extends ScriptObject {
/** 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);
@ -386,24 +383,6 @@ public abstract class ScriptFunction extends ScriptObject {
return i < args.length ? args[i] : UNDEFINED;
}
/**
* 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.

View File

@ -69,7 +69,6 @@ import jdk.nashorn.internal.runtime.linker.NashornGuards;
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 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
/**
* 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 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @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);
// 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");
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");
// 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());
}
/**
@ -1922,41 +1893,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
null, NashornGuards.getMapGuard(getMap()));
}
/**
* 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.

View File

@ -131,12 +131,13 @@ public class WithObject extends ScriptObject implements Scope {
// 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 @@ public class WithObject extends ScriptObject implements Scope {
find = self.findProperty(fallBack, true);
if (find != null) {
switch (operator) {
case "callMethod":
link = self.createNoSuchMethodInvocation(desc);
break;
case "getMethod":
link = self.noSuchMethod(desc);
break;

View File

@ -79,7 +79,7 @@ public final class Bootstrap {
}
/**
* 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 @@ public final class Bootstrap {
* 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();
}
/**

View File

@ -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.ArrayList;
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
@ -298,6 +297,11 @@ public final class MethodHandleFactory {
return MethodHandles.dropArguments(target, pos, valueTypes);
}
@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);
@ -499,6 +503,12 @@ public final class MethodHandleFactory {
return debug(mh, "dropArguments", target, pos, values);
}
@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);

View File

@ -30,6 +30,7 @@ import java.lang.invoke.MethodHandles;
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
@ -91,6 +92,17 @@ public interface MethodHandleFunctionality {
*/
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)}
*