jvm从InvokedDynamic调用Java varargs方法
我想从Java动态调用本机方法。 因为方法签名在编译时是未知的,所以我为大多数具有相同签名的基本返回类型创建了泛型本机方法:
class NativeHook {
public static native int callInt(String funcName, Object... funcArgs);
public static native void callVoid(String funcName, Object... funcArgs);
public static native Object callObject(String funcName, Object... funcArgs);
private static MethodHandle getNativeMethod(String callName, Class<?> returnType) {
return MethodHandles.lookup().findStatic(NativeHook.class, callName,
MethodType.methodType(returnType, String.class, Object[].class));
}
}
我希望创建一个MethodHandle,然后调用一个匹配的callXXX
方法并传入装箱的funcArgs
,就好像它们是单独提供的一样。这些callXXX
方法可以如下访问:
MethodHandle callInt = getNativeMethod("callInt", int.class);
MethodHandle boundCallInt = callInt.bindTo("my_c_function_name").asVarargsCollector(Object[].class);
// returns NativeHook.callInt("my_c_function_name", 1, 2, 3)
boundCallInt.invokeWithArguments(1, 2, 3);
我使用这个引导方法间接引用invokedynamic中的这个callXXX
方法,其工作方式与上面相同:
public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) {
if (type.returnType() == int.class) {
MethodHandle callInt = getNativeMethod("callInt", int.class);
return new ConstantCallSite(callInt.bindTo(name).asVarargsCollector(Object[].class));
}
}
然后使用InvokedDynamic完成调用,如下所示:
mv.visitIntInsn(BIPUSH, 1);
mv.visitIntInsn(BIPUSH, 2);
mv.visitIntInsn(BIPUSH, 3);
mv.visitInvokeDynamicInsn("my_c_function_name", "(III)I", NativeHook.bootstrapHandle);
但是,这无法按预期工作,并引发异常:
Caused by: java.lang.invoke.WrongMethodTypeException: MethodHandle(Object[])int should be of type (int,int,int)int
at java.lang.invoke.CallSite.wrongTargetType(CallSite.java:194)
at java.lang.invoke.CallSite.makeSite(CallSite.java:335)
... 16 more
如何构造一个适当的MethodHandle,它像常规方法一样接受参数,然后调用varargcallXXX
方法
# 1 楼答案
在the package documentation中,我们找到了语句
因此,就
invoke
而言,兼容是不够的,但它必须与invokeExact
兼容应用} 对其进行调整:
.asVarargsCollector(Object[].class)
后,可以invoke
句柄,但它与确切的签名不匹配。但我们可以通过^{这意味着
asVarargsCollector
和asType
的组合应该有效。但是我们也可以考虑在同一方法文档中提到的^ {CD1>}和^ {CD2>}之间的一般关系:换句话说,如果
invoke
工作成功,那么asType
转换也必须能够满足invokeExact
的要求我们可以证明:
bootstrap方法已经接收到必需的
MethodType
作为第三个参数,因此它需要做的就是使用该类型应用.asType(type)