|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package java.lang.invoke; |
|
|
|
import java.util.Arrays; |
|
import static java.lang.invoke.LambdaForm.*; |
|
import static java.lang.invoke.LambdaForm.Kind.*; |
|
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual; |
|
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 |
|
*/ |
|
|
|
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); |
|
} |
|
|
|
|
|
protected abstract 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) { |
|
|
|
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(); |
|
return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget); |
|
} |
|
|
|
static LambdaForm makeReinvokerForm(MethodHandle target, |
|
int whichCache, |
|
Object constraint, |
|
NamedFunction getTargetFn) { |
|
|
|
return makeReinvokerForm(target, whichCache, constraint, true, getTargetFn, null); |
|
} |
|
|
|
static LambdaForm makeReinvokerForm(MethodHandle target, |
|
int whichCache, |
|
Object constraint, |
|
boolean forceInline, |
|
NamedFunction getTargetFn, |
|
NamedFunction preActionFn) { |
|
MethodType mtype = target.type().basicType(); |
|
Kind kind = whichKind(whichCache); |
|
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); |
|
} 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]; |
|
names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs); |
|
} |
|
form = new LambdaForm(ARG_LIMIT, names, forceInline, kind); |
|
if (!customized) { |
|
form = mtype.form().setCachedLambdaForm(whichCache, form); |
|
} |
|
return form; |
|
} |
|
|
|
private static Kind whichKind(int whichCache) { |
|
switch(whichCache) { |
|
case MethodTypeForm.LF_REBIND: return BOUND_REINVOKER; |
|
case MethodTypeForm.LF_DELEGATE: return DELEGATE; |
|
default: return REINVOKER; |
|
} |
|
} |
|
|
|
static final NamedFunction NF_getTarget; |
|
static { |
|
try { |
|
MemberName member = new MemberName(DelegatingMethodHandle.class, "getTarget", |
|
MethodType.methodType(MethodHandle.class), REF_invokeVirtual); |
|
NF_getTarget = new NamedFunction( |
|
MemberName.getFactory() |
|
.resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, NoSuchMethodException.class)); |
|
} catch (ReflectiveOperationException ex) { |
|
throw newInternalError(ex); |
|
} |
|
// The Holder class will contain pre-generated DelegatingMethodHandles resolved |
|
// speculatively using MemberName.getFactory().resolveOrNull. However, that |
|
// doesn't initialize the class, which subtly breaks inlining etc. By forcing |
|
|
|
UNSAFE.ensureClassInitialized(Holder.class); |
|
} |
|
|
|
|
|
final class Holder {} |
|
} |