JDK-18 Foreign Functions : 如何调用非静态函数?
JDK-18 Foreign Functions : How to upCall non-static functions?
我一直在研究 JDK-18 中的 jdk.incubator.foreign
内容。这很不错。比 JNI 快得多。快一个数量级。外部内存的东西比 UNSAFE
的东西更好(也许稍微快一点)。等不及发货了。
有一件事我想不通:如何 upCall
到非静态 JVM 函数?
如果我不能,我如何传递一些上下文来回传递,以便我可以将上下文转换为 java 静态函数中的正确 instance/type?在 java 中,如何从 this
创建一个 ValueLayout.ADDRESS
?反之亦然?
我能弄清楚如何做到这一点的唯一方法是保留实例化 classes 的列表,并在列表中往返索引。这似乎是一个黑客。
也许 JVM 保留随时不受限制地移动 JVM 内存的权利,所以也许这是不可能的?如果是这样,推荐的模式是什么?
---编辑-添加代码示例---
public class RoundTripExample {
private String name;
RoundTripExample(String _name) {
this.name = _name;
}
public void callback() {
System.out.println("Called from native"+name);
}
public static void main(String[] args) throws Throwable {
var fName = new File("../zig/zig-out/lib/libnativeFuncs.so").getCanonicalFile();
System.load(fName.toString());
var instance =new RoundTripExample("round trip name");
CLinker link = CLinker.systemCLinker();
SymbolLookup symLook = SymbolLookup.loaderLookup();
ResourceScope scope = ResourceScope.newSharedScope();
var nativeFunc = link.downcallHandle(
symLook.lookup("zigCallTest").get(),
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS)
);
var handle =
MethodHandles.lookup().findVirtual(
RoundTripExample.class,
"callback",
MethodType.methodType(void.class)
);
handle.bindTo(instance);
var upcall = link.upcallStub(
handle,
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS),
ZigStubs.scope
);
nativeFunc.invoke(upcall);
}
}
假设这是方法,问题是创建 upCall
句柄。您只能将句柄传递给采用 LONG、INT、ADDRESS 等的函数。class 的实例不是其中任何一个。
如果您需要传递的上下文对于目标函数来说是常量,您可以使用 MethodHandles.insertArguments
将其绑定到目标方法句柄,然后使用生成的方法句柄创建上调存根。
如果目标函数的上下文不是常量,那么使用列表并将索引传递给所需对象的想法是一个很好的方法。这本质上是一种将对象转换为整数的方法,方法是将其插入列表,然后通过再次在列表中查找返回对象。
没有安全的方法可以将对象转换为纯本机地址,因为正如您所说,对象可能会被 JVM 移动。
在示例中,使用 bindTo
看起来可行。在这种情况下,您忘记分配 bindTo
:
的结果
handle = handle.bindTo(instance);
此外,您必须删除从本机代码传递的地址参数,因为您的 Java 代码似乎没有使用它:
handle = MethodHandles.dropArguments(handle, 0, MemoryAddress.class);
var upcall = link.upcallStub(
handle,
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS),
ZigStubs.scope
);
我一直在研究 JDK-18 中的 jdk.incubator.foreign
内容。这很不错。比 JNI 快得多。快一个数量级。外部内存的东西比 UNSAFE
的东西更好(也许稍微快一点)。等不及发货了。
有一件事我想不通:如何 upCall
到非静态 JVM 函数?
如果我不能,我如何传递一些上下文来回传递,以便我可以将上下文转换为 java 静态函数中的正确 instance/type?在 java 中,如何从 this
创建一个 ValueLayout.ADDRESS
?反之亦然?
我能弄清楚如何做到这一点的唯一方法是保留实例化 classes 的列表,并在列表中往返索引。这似乎是一个黑客。
也许 JVM 保留随时不受限制地移动 JVM 内存的权利,所以也许这是不可能的?如果是这样,推荐的模式是什么?
---编辑-添加代码示例---
public class RoundTripExample {
private String name;
RoundTripExample(String _name) {
this.name = _name;
}
public void callback() {
System.out.println("Called from native"+name);
}
public static void main(String[] args) throws Throwable {
var fName = new File("../zig/zig-out/lib/libnativeFuncs.so").getCanonicalFile();
System.load(fName.toString());
var instance =new RoundTripExample("round trip name");
CLinker link = CLinker.systemCLinker();
SymbolLookup symLook = SymbolLookup.loaderLookup();
ResourceScope scope = ResourceScope.newSharedScope();
var nativeFunc = link.downcallHandle(
symLook.lookup("zigCallTest").get(),
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS)
);
var handle =
MethodHandles.lookup().findVirtual(
RoundTripExample.class,
"callback",
MethodType.methodType(void.class)
);
handle.bindTo(instance);
var upcall = link.upcallStub(
handle,
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS),
ZigStubs.scope
);
nativeFunc.invoke(upcall);
}
}
假设这是方法,问题是创建 upCall
句柄。您只能将句柄传递给采用 LONG、INT、ADDRESS 等的函数。class 的实例不是其中任何一个。
如果您需要传递的上下文对于目标函数来说是常量,您可以使用 MethodHandles.insertArguments
将其绑定到目标方法句柄,然后使用生成的方法句柄创建上调存根。
如果目标函数的上下文不是常量,那么使用列表并将索引传递给所需对象的想法是一个很好的方法。这本质上是一种将对象转换为整数的方法,方法是将其插入列表,然后通过再次在列表中查找返回对象。
没有安全的方法可以将对象转换为纯本机地址,因为正如您所说,对象可能会被 JVM 移动。
在示例中,使用 bindTo
看起来可行。在这种情况下,您忘记分配 bindTo
:
handle = handle.bindTo(instance);
此外,您必须删除从本机代码传递的地址参数,因为您的 Java 代码似乎没有使用它:
handle = MethodHandles.dropArguments(handle, 0, MemoryAddress.class);
var upcall = link.upcallStub(
handle,
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS),
ZigStubs.scope
);