package java.lang.invoke;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.invoke.NativeEntryPoint;
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.MethodHandleNatives.Constants.LM_TRUSTED;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
import static java.lang.invoke.MethodHandleStatics.newInternalError;
class NativeMethodHandle extends MethodHandle {
final NativeEntryPoint nep;
final MethodHandle fallback;
private NativeMethodHandle(MethodType type, LambdaForm form, MethodHandle fallback, NativeEntryPoint nep) {
super(type, form);
this.fallback = fallback;
this.nep = nep;
}
public static MethodHandle make(NativeEntryPoint nep, MethodHandle fallback) {
MethodType type = nep.type();
if (!allTypesPrimitive(type))
throw new IllegalArgumentException("Type must only contain primitives: " + type);
if (type != fallback.type())
throw new IllegalArgumentException("Type of fallback must match");
LambdaForm lform = preparedLambdaForm(type);
return new NativeMethodHandle(type, lform, fallback, nep);
}
private static boolean allTypesPrimitive(MethodType type) {
if (!type.returnType().isPrimitive())
return false;
for (Class<?> pType : type.parameterArray()) {
if (!pType.isPrimitive())
return false;
}
return true;
}
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
private static LambdaForm preparedLambdaForm(MethodType mtype) {
int id = MethodTypeForm.LF_INVNATIVE;
mtype = mtype.basicType();
LambdaForm lform = mtype.form().cachedLambdaForm(id);
if (lform != null) return lform;
lform = makePreparedLambdaForm(mtype);
return mtype.form().setCachedLambdaForm(id, lform);
}
private static LambdaForm makePreparedLambdaForm(MethodType mtype) {
MethodType linkerType = mtype.insertParameterTypes(0, MethodHandle.class)
.appendParameterTypes(Object.class);
MemberName linker = new MemberName(MethodHandle.class, "linkToNative", linkerType, REF_invokeStatic);
try {
linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, LM_TRUSTED, NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
final int NMH_THIS = 0;
final int ARG_BASE = 1;
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
int nameCursor = ARG_LIMIT;
final int GET_FALLBACK = nameCursor++;
final int GET_NEP = nameCursor++;
final int LINKER_CALL = nameCursor++;
LambdaForm.Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
assert (names.length == nameCursor);
names[GET_FALLBACK] = new LambdaForm.Name(Lazy.NF_internalFallback, names[NMH_THIS]);
names[GET_NEP] = new LambdaForm.Name(Lazy.NF_internalNativeEntryPoint, names[NMH_THIS]);
Object[] outArgs = new Object[linkerType.parameterCount()];
outArgs[0] = names[GET_FALLBACK];
System.arraycopy(names, ARG_BASE, outArgs, 1, mtype.parameterCount());
outArgs[outArgs.length - 1] = names[GET_NEP];
names[LINKER_CALL] = new LambdaForm.Name(linker, outArgs);
LambdaForm lform = new LambdaForm(ARG_LIMIT, names, LAST_RESULT);
lform.compileToBytecode();
return lform;
}
final
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
assert (this.getClass() == NativeMethodHandle.class);
return new NativeMethodHandle(mt, lf, fallback, nep);
}
@Override
BoundMethodHandle rebind() {
return BoundMethodHandle.makeReinvoker(this);
}
@ForceInline
static Object internalNativeEntryPoint(Object mh) {
return ((NativeMethodHandle)mh).nep;
}
@ForceInline
static MethodHandle internalFallback(Object mh) {
return ((NativeMethodHandle)mh).fallback;
}
private static class Lazy {
static final NamedFunction
NF_internalNativeEntryPoint;
static final NamedFunction
NF_internalFallback;
static {
try {
Class<NativeMethodHandle> THIS_CLASS = NativeMethodHandle.class;
NamedFunction[] nfs = new NamedFunction[]{
NF_internalNativeEntryPoint = new NamedFunction(
THIS_CLASS.getDeclaredMethod("internalNativeEntryPoint", Object.class)),
NF_internalFallback = new NamedFunction(
THIS_CLASS.getDeclaredMethod("internalFallback", Object.class))
};
for (NamedFunction nf : nfs) {
assert (InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
nf.resolve();
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
}
}
}