You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
5.7 KiB
165 lines
5.7 KiB
/*
|
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package java.lang.invoke;
|
|
|
|
import java.util.Arrays;
|
|
import static java.lang.invoke.LambdaForm.*;
|
|
import static java.lang.invoke.MethodHandleStatics.*;
|
|
|
|
/**
|
|
* A method handle whose invocation behavior is determined by a target.
|
|
* The delegating MH itself can hold extra "intentions" beyond the simple behavior.
|
|
* @author jrose
|
|
*/
|
|
/*non-public*/
|
|
abstract class DelegatingMethodHandle extends MethodHandle {
|
|
protected DelegatingMethodHandle(MethodHandle target) {
|
|
this(target.type(), target);
|
|
}
|
|
|
|
protected DelegatingMethodHandle(MethodType type, MethodHandle target) {
|
|
super(type, chooseDelegatingForm(target));
|
|
}
|
|
|
|
protected DelegatingMethodHandle(MethodType type, LambdaForm form) {
|
|
super(type, form);
|
|
}
|
|
|
|
/** Define this to extract the delegated target which supplies the invocation behavior. */
|
|
abstract protected MethodHandle getTarget();
|
|
|
|
@Override
|
|
abstract MethodHandle asTypeUncached(MethodType newType);
|
|
|
|
@Override
|
|
MemberName internalMemberName() {
|
|
return getTarget().internalMemberName();
|
|
}
|
|
|
|
@Override
|
|
boolean isInvokeSpecial() {
|
|
return getTarget().isInvokeSpecial();
|
|
}
|
|
|
|
@Override
|
|
Class<?> internalCallerClass() {
|
|
return getTarget().internalCallerClass();
|
|
}
|
|
|
|
@Override
|
|
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
|
|
// FIXME: rethink 'copyWith' protocol; it is too low-level for use on all MHs
|
|
throw newIllegalArgumentException("do not use this");
|
|
}
|
|
|
|
@Override
|
|
String internalProperties() {
|
|
return "\n& Class="+getClass().getSimpleName()+
|
|
"\n& Target="+getTarget().debugString();
|
|
}
|
|
|
|
@Override
|
|
BoundMethodHandle rebind() {
|
|
return getTarget().rebind();
|
|
}
|
|
|
|
private static LambdaForm chooseDelegatingForm(MethodHandle target) {
|
|
if (target instanceof SimpleMethodHandle)
|
|
return target.internalForm(); // no need for an indirection
|
|
return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget);
|
|
}
|
|
|
|
static LambdaForm makeReinvokerForm(MethodHandle target,
|
|
int whichCache,
|
|
Object constraint,
|
|
NamedFunction getTargetFn) {
|
|
String debugString;
|
|
switch(whichCache) {
|
|
case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break;
|
|
case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break;
|
|
default: debugString = "MH.reinvoke"; break;
|
|
}
|
|
// No pre-action needed.
|
|
return makeReinvokerForm(target, whichCache, constraint, debugString, true, getTargetFn, null);
|
|
}
|
|
/** Create a LF which simply reinvokes a target of the given basic type. */
|
|
static LambdaForm makeReinvokerForm(MethodHandle target,
|
|
int whichCache,
|
|
Object constraint,
|
|
String debugString,
|
|
boolean forceInline,
|
|
NamedFunction getTargetFn,
|
|
NamedFunction preActionFn) {
|
|
MethodType mtype = target.type().basicType();
|
|
boolean customized = (whichCache < 0 ||
|
|
mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY);
|
|
boolean hasPreAction = (preActionFn != null);
|
|
LambdaForm form;
|
|
if (!customized) {
|
|
form = mtype.form().cachedLambdaForm(whichCache);
|
|
if (form != null) return form;
|
|
}
|
|
final int THIS_DMH = 0;
|
|
final int ARG_BASE = 1;
|
|
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
|
|
int nameCursor = ARG_LIMIT;
|
|
final int PRE_ACTION = hasPreAction ? nameCursor++ : -1;
|
|
final int NEXT_MH = customized ? -1 : nameCursor++;
|
|
final int REINVOKE = nameCursor++;
|
|
LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
|
|
assert(names.length == nameCursor);
|
|
names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint);
|
|
Object[] targetArgs;
|
|
if (hasPreAction) {
|
|
names[PRE_ACTION] = new LambdaForm.Name(preActionFn, names[THIS_DMH]);
|
|
}
|
|
if (customized) {
|
|
targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
|
|
names[REINVOKE] = new LambdaForm.Name(target, targetArgs); // the invoker is the target itself
|
|
} else {
|
|
names[NEXT_MH] = new LambdaForm.Name(getTargetFn, names[THIS_DMH]);
|
|
targetArgs = Arrays.copyOfRange(names, THIS_DMH, ARG_LIMIT, Object[].class);
|
|
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
|
|
names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs);
|
|
}
|
|
form = new LambdaForm(debugString, ARG_LIMIT, names, forceInline);
|
|
if (!customized) {
|
|
form = mtype.form().setCachedLambdaForm(whichCache, form);
|
|
}
|
|
return form;
|
|
}
|
|
|
|
static final NamedFunction NF_getTarget;
|
|
static {
|
|
try {
|
|
NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
|
|
.getDeclaredMethod("getTarget"));
|
|
} catch (ReflectiveOperationException ex) {
|
|
throw newInternalError(ex);
|
|
}
|
|
}
|
|
}
|