8006293: Reduce ScriptObject.findCallMethodMethod
Reviewed-by: lagergren, jlaskey
This commit is contained in:
parent
246e4e8daf
commit
0c53c5de50
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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)}
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user