下面列出了java.lang.invoke.MethodHandles#dropArguments ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
// NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
final MethodType type = mh.type();
newHandle = newHandle.asVarargsCollector(type.parameterType(type.parameterCount() - 1));
}
return newHandle;
}
private static MethodHandle getBoundBeanMethodGetter(final Object source, final MethodHandle methodGetter) {
try {
// NOTE: we're relying on the fact that "dyn:getMethod:..." return value is constant for any given method
// name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is
// constant for any given method name and object's class.)
return MethodHandles.dropArguments(MethodHandles.constant(Object.class,
Bootstrap.bindCallable(methodGetter.invoke(source), source, null)), 0, Object.class);
} catch(RuntimeException|Error e) {
throw e;
} catch(final Throwable t) {
throw new RuntimeException(t);
}
}
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) {
final Object receiver = linkRequest.getReceiver();
if(!(receiver instanceof DynamicMethod)) {
return null;
}
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
return null;
}
final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR);
final DynamicMethod dynMethod = (DynamicMethod)receiver;
final boolean constructor = dynMethod.isConstructor();
final MethodHandle invocation;
if (operator == "call" && !constructor) {
invocation = dynMethod.getInvocation(
CallSiteDescriptorFactory.dropParameterTypes(desc, 0, 1), linkerServices);
} else if (operator == "new" && constructor) {
final MethodHandle ctorInvocation = dynMethod.getInvocation(desc, linkerServices);
if(ctorInvocation == null) {
return null;
}
// Insert null for StaticClass parameter
invocation = MethodHandles.insertArguments(ctorInvocation, 0, (Object)null);
} else {
return null;
}
if (invocation != null) {
return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0,
desc.getMethodType().parameterType(0)), Guards.getIdentityGuard(receiver));
}
return null;
}
private static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
// NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
final MethodType type = mh.type();
newHandle = newHandle.asVarargsCollector(type.parameterType(type.parameterCount() - 1));
}
return newHandle;
}
/**
* Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
* chain.
* @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
* @return a method handle for prune-and-invoke
*/
private MethodHandle makePruneAndInvokeMethod(MethodHandle relink) {
// Bind prune to (this, relink)
final MethodHandle boundPrune = MethodHandles.insertArguments(PRUNE, 0, this, relink);
// Make it ignore all incoming arguments
final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
// Invoke prune, then invoke the call site target with original arguments
return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune);
}
/**
* Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
* chain.
* @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
* @return a method handle for prune-and-invoke
*/
private MethodHandle makePruneAndInvokeMethod(final MethodHandle relink, final MethodHandle prune) {
// Bind prune to (this, relink)
final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink);
// Make it ignore all incoming arguments
final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
// Invoke prune, then invoke the call site target with original arguments
return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune);
}
public static MethodHandle addTrailingArgs(MethodHandle target, int nargs,
List<Class<?>> classes) {
int targetLen = target.type().parameterCount();
int extra = (nargs - targetLen);
if (extra <= 0) {
return target;
}
List<Class<?>> fakeArgs = new ArrayList<>(extra);
for (int i = 0; i < extra; ++i) {
fakeArgs.add(classes.get(i % classes.size()));
}
return MethodHandles.dropArguments(target, targetLen, fakeArgs);
}
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) {
final Object receiver = linkRequest.getReceiver();
if(!(receiver instanceof DynamicMethod)) {
return null;
}
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
return null;
}
final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR);
final DynamicMethod dynMethod = (DynamicMethod)receiver;
final boolean constructor = dynMethod.isConstructor();
final MethodHandle invocation;
if (operator == "call" && !constructor) {
invocation = dynMethod.getInvocation(
CallSiteDescriptorFactory.dropParameterTypes(desc, 0, 1), linkerServices);
} else if (operator == "new" && constructor) {
final MethodHandle ctorInvocation = dynMethod.getInvocation(desc, linkerServices);
if(ctorInvocation == null) {
return null;
}
// Insert null for StaticClass parameter
invocation = MethodHandles.insertArguments(ctorInvocation, 0, (Object)null);
} else {
return null;
}
if (invocation != null) {
return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0,
desc.getMethodType().parameterType(0)), Guards.getIdentityGuard(receiver));
}
return null;
}
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) {
final Object receiver = linkRequest.getReceiver();
if(!(receiver instanceof DynamicMethod)) {
return null;
}
final DynamicMethod dynMethod = (DynamicMethod)receiver;
final boolean constructor = dynMethod.isConstructor();
final MethodHandle invocation;
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
final Operation op = NamedOperation.getBaseOperation(desc.getOperation());
if (op == StandardOperation.CALL && !constructor) {
invocation = dynMethod.getInvocation(desc.changeMethodType(
desc.getMethodType().dropParameterTypes(0, 1)), linkerServices);
} else if (op == StandardOperation.NEW && constructor) {
final MethodHandle ctorInvocation = dynMethod.getInvocation(desc, linkerServices);
if(ctorInvocation == null) {
return null;
}
// Insert null for StaticClass parameter
invocation = MethodHandles.insertArguments(ctorInvocation, 0, (Object)null);
} else {
return null;
}
if (invocation != null) {
return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0,
desc.getMethodType().parameterType(0)), Guards.getIdentityGuard(receiver));
}
return null;
}
private static MethodHandle empty_void(MethodType methodType) {
if (IS_JAVA_8) {
return MethodHandles.dropArguments(NOP, 0, methodType.parameterList());
}
return MethodHandles.empty(methodType);
}
@Override
public MethodHandle dropArguments(final MethodHandle target, final int pos, final Class<?>... values) {
final MethodHandle mh = MethodHandles.dropArguments(target, pos, values);
return debug(mh, "dropArguments", target, pos, values);
}
@Override
public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> values) {
final MethodHandle mh = MethodHandles.dropArguments(target, pos, values);
return debug(mh, "dropArguments", target, pos, values);
}
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
final Object objBoundCallable = linkRequest.getReceiver();
if(!(objBoundCallable instanceof BoundCallable)) {
return null;
}
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
if (descriptor.getNameTokenCount() < 2 || !"dyn".equals(descriptor.getNameToken(CallSiteDescriptor.SCHEME))) {
return null;
}
final String operation = descriptor.getNameToken(CallSiteDescriptor.OPERATOR);
// We need to distinguish "dyn:new" from "dyn:call" because "dyn:call" sites have parameter list of the form
// "callee, this, args", while "dyn:call" sites have "callee, args" -- they lack the "this" parameter.
final boolean isCall;
if ("new".equals(operation)) {
isCall = false;
} else if ("call".equals(operation)) {
isCall = true;
} else {
// Only dyn:call and dyn:new are supported.
return null;
}
final BoundCallable boundCallable = (BoundCallable)objBoundCallable;
final Object callable = boundCallable.getCallable();
final Object boundThis = boundCallable.getBoundThis();
// We need to ask the linker services for a delegate invocation on the target callable.
// Replace arguments (boundCallable[, this], args) => (callable[, boundThis], boundArgs, args) when delegating
final Object[] args = linkRequest.getArguments();
final Object[] boundArgs = boundCallable.getBoundArgs();
final int argsLen = args.length;
final int boundArgsLen = boundArgs.length;
final Object[] newArgs = new Object[argsLen + boundArgsLen];
newArgs[0] = callable;
final int firstArgIndex;
if (isCall) {
newArgs[1] = boundThis;
firstArgIndex = 2;
} else {
firstArgIndex = 1;
}
System.arraycopy(boundArgs, 0, newArgs, firstArgIndex, boundArgsLen);
System.arraycopy(args, firstArgIndex, newArgs, firstArgIndex + boundArgsLen, argsLen - firstArgIndex);
// Use R(T0, T1, T2, ...) => R(callable.class, boundThis.class, boundArg0.class, ..., boundArgn.class, T2, ...)
// call site type when delegating to underlying linker (for dyn:new, there's no this).
final MethodType type = descriptor.getMethodType();
// Use R(T0, ...) => R(callable.class, ...)
MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass());
if (isCall) {
// R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...)
newMethodType = newMethodType.changeParameterType(1, boundThis == null? Object.class : boundThis.getClass());
}
// R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...)
for(int i = boundArgs.length; i-- > 0;) {
newMethodType = newMethodType.insertParameterTypes(firstArgIndex, boundArgs[i] == null ? Object.class : boundArgs[i].getClass());
}
final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(newMethodType);
// Delegate to target's linker
final GuardedInvocation inv = linkerServices.getGuardedInvocation(linkRequest.replaceArguments(newDescriptor, newArgs));
if(inv == null) {
return null;
}
// Bind (callable[, boundThis], boundArgs) to the delegate handle
final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0,
Arrays.copyOf(newArgs, firstArgIndex + boundArgs.length));
final Class<?> p0Type = type.parameterType(0);
final MethodHandle droppingHandle;
if (isCall) {
// Ignore incoming boundCallable and this
droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1));
} else {
// Ignore incoming boundCallable
droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type);
}
// Identity guard on boundCallable object
final MethodHandle newGuard = Guards.getIdentityGuard(boundCallable);
return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type)));
}
@Override
public MethodHandle dropArguments(final MethodHandle target, final int pos, final Class<?>... values) {
final MethodHandle mh = MethodHandles.dropArguments(target, pos, values);
return debug(mh, "dropArguments", target, pos, values);
}
@Override
public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> values) {
final MethodHandle mh = MethodHandles.dropArguments(target, pos, values);
return debug(mh, "dropArguments", target, pos, values);
}
private GuardedInvocationComponent getPropertySetter(CallSiteDescriptor callSiteDescriptor,
LinkerServices linkerServices, List<String> operations) throws Exception {
final MethodType type = callSiteDescriptor.getMethodType();
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward.
// We want setters that conform to "R(O, V)"
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
CallSiteDescriptorFactory.dropParameterTypes(callSiteDescriptor, 1, 2), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->R(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// R(O, N, V)->R(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
}
default: {
// More than two name components; don't know what to do with it.
return null;
}
}
}
@Override
public MethodHandle dropArguments(final MethodHandle target, final int pos, final Class<?>... valueTypes) {
return MethodHandles.dropArguments(target, pos, valueTypes);
}
static MethodHandle slap(MethodHandle mh, Class<?> addType) {
return MethodHandles.dropArguments(mh, mh.type().parameterCount(), addType);
}
private static MethodHandle invalidCallArgumentsHandle(String name, MethodType type, WrongMethodTypeException e) {
// Add native call name?
MethodHandle mh = MethodHandles.insertArguments(invalidNativeCallArgumentsMH, 0, e.getMessage());
return MethodHandles.dropArguments(mh, 1, type.dropParameterTypes(0, 1).parameterArray());
}
private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor,
LinkerServices linkerServices, List<String> ops) throws Exception {
final MethodType type = callSiteDescriptor.getMethodType();
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have exactly two arguments: receiver and name
assertParameterCount(callSiteDescriptor, 2);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
// only with a bunch of method signature adjustments. Basically, retrieve method getter
// AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
// or delegate to next component's invocation.
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
AnnotatedDynamicMethod.class));
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup());
final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
callSiteBoundMethodGetter);
// Object(AnnotatedDynamicMethod, Object)->R(AnnotatedDynamicMethod, T0)
final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
// Since it's in the target of a fold, drop the unnecessary second argument
// R(AnnotatedDynamicMethod, T0)->R(AnnotatedDynamicMethod, T0, T1)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
type.parameterType(1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, ops);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(AnnotatedDynamicMethod)->R(AnnotatedDynamicMethod, T0, T1); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
} else {
// R(T0, T1)->R(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, AnnotatedDynamicMethod.class);
}
// fold(R(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeGetter, type);
}
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have exactly one argument: receiver
assertParameterCount(callSiteDescriptor, 1);
// Fixed name
final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
CallSiteDescriptor.NAME_OPERAND));
if(annGetter == null) {
// We have no such property, always delegate to the next component operation
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
}
final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
// NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
// overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
// method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
// we're linking against a field getter, don't make the assumption.
// NOTE: No delegation to the next component operation if we have a property with this name, even if its
// value is null.
final ValidationType validationType = annGetter.validationType;
// TODO: we aren't using the type that declares the most generic getter here!
return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType,
type), clazz, validationType);
}
default: {
// Can't do anything with more than 3 name components
return null;
}
}
}