|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
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; |
|
|
|
/** |
|
* This class models a method handle to a native function. A native method handle is made up of a {@link NativeEntryPoint}, |
|
* which is used to capture the characteristics of the native call (such as calling convention to be used, |
|
* or whether a native transition is required) and a <em>fallback</em> method handle, which can be used |
|
* when intrinsification of this method handle is not possible. |
|
*/ |
|
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: " + type + " != " + fallback.type()); |
|
|
|
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); |
|
} |
|
} |
|
} |
|
} |