如何使用 Java Panama FFI 访问 MemoryLayout 中的 C_POINTER
How to access a C_POINTER in a MemoryLayout using Java Panama FFI
使用JDK16中的FFI预览,我有这样的内存布局:
class FfiTest {
static GroupLayout layout = MemoryLayout.ofStruct(
C_INT.withName("someInt"),
MemoryLayout.ofPaddingBits(32), // So the following pointer is aligned at 64 bits
C_POINTER.withName("somePtr")
);
}
然后我在本机代码的回调中收到指向此类结构的指针:
public static void someCallback(MemoryAddress address) {
try (MemorySegment seg = address.asSegmentRestricted(FfiTest.layout.byteSize())) {
// Works: fetching int from native structure, correct value is returned
VarHandle intHandle = FfiTest.layout.varHandle(int.class, MemoryLayout.PathElement.groupElement("someInt"));
int intResult = (int) vh.get(seg);
// Does not work: get the pointer as a MemoryAddress, fatal JVM crash with Hotspot log
VarHandle badPtrHandle = FfiTest.layout.varHandle(MemoryAddress.class, MemoryLayout.PathElement.groupElement("somePtr"));
// Works: get the pointer as a long, correct value is returned
VarHandle goodPtrHandle = FfiTest.layout.varHandle(long.class, MemoryLayout.PathElement.groupElement("somePtr"));
long longResult = (long) goodPtrHandle.get(seg);
}
}
jdk.internal.foreign.Utils
中的 JDK 代码内部抛出异常:
public static void checkPrimitiveCarrierCompat(Class<?> carrier, MemoryLayout layout) {
checkLayoutType(layout, ValueLayout.class);
if (!isValidPrimitiveCarrier(carrier))
throw new IllegalArgumentException("Unsupported carrier: " + carrier); // Throws this exception, carrier has the value MemoryAddress
if (Wrapper.forPrimitiveType(carrier).bitWidth() != layout.bitSize())
throw new IllegalArgumentException("Carrier size mismatch: " + carrier + " != " + layout);
}
根据巴拿马文档,C_POINTER
的 Java 承运人应该是 MemoryAddress
,但这在这里不起作用。
那么使用 longs 来访问这样的指针是否正确?或者别的什么?
正如 Johannes 在评论中指出的那样,MemoryHandles::asAddressVarHandle
可用于调整您必须接受的 long
句柄和 return 一个 MemoryAddress
:
VarHandle goodPtrHandle = FfiTest.layout.varHandle(long.class, MemoryLayout.PathElement.groupElement("somePtr"));
long longResult = (long) goodPtrHandle.get(seg);
VarHandle addrHandle = MemoryHandles.asAddressVarHandle(goodPtrHandle);
MemoryAddress addrResult = (MemoryAddress) addrHandle.get(seg);
使用JDK16中的FFI预览,我有这样的内存布局:
class FfiTest {
static GroupLayout layout = MemoryLayout.ofStruct(
C_INT.withName("someInt"),
MemoryLayout.ofPaddingBits(32), // So the following pointer is aligned at 64 bits
C_POINTER.withName("somePtr")
);
}
然后我在本机代码的回调中收到指向此类结构的指针:
public static void someCallback(MemoryAddress address) {
try (MemorySegment seg = address.asSegmentRestricted(FfiTest.layout.byteSize())) {
// Works: fetching int from native structure, correct value is returned
VarHandle intHandle = FfiTest.layout.varHandle(int.class, MemoryLayout.PathElement.groupElement("someInt"));
int intResult = (int) vh.get(seg);
// Does not work: get the pointer as a MemoryAddress, fatal JVM crash with Hotspot log
VarHandle badPtrHandle = FfiTest.layout.varHandle(MemoryAddress.class, MemoryLayout.PathElement.groupElement("somePtr"));
// Works: get the pointer as a long, correct value is returned
VarHandle goodPtrHandle = FfiTest.layout.varHandle(long.class, MemoryLayout.PathElement.groupElement("somePtr"));
long longResult = (long) goodPtrHandle.get(seg);
}
}
jdk.internal.foreign.Utils
中的 JDK 代码内部抛出异常:
public static void checkPrimitiveCarrierCompat(Class<?> carrier, MemoryLayout layout) {
checkLayoutType(layout, ValueLayout.class);
if (!isValidPrimitiveCarrier(carrier))
throw new IllegalArgumentException("Unsupported carrier: " + carrier); // Throws this exception, carrier has the value MemoryAddress
if (Wrapper.forPrimitiveType(carrier).bitWidth() != layout.bitSize())
throw new IllegalArgumentException("Carrier size mismatch: " + carrier + " != " + layout);
}
根据巴拿马文档,C_POINTER
的 Java 承运人应该是 MemoryAddress
,但这在这里不起作用。
那么使用 longs 来访问这样的指针是否正确?或者别的什么?
正如 Johannes 在评论中指出的那样,MemoryHandles::asAddressVarHandle
可用于调整您必须接受的 long
句柄和 return 一个 MemoryAddress
:
VarHandle goodPtrHandle = FfiTest.layout.varHandle(long.class, MemoryLayout.PathElement.groupElement("somePtr"));
long longResult = (long) goodPtrHandle.get(seg);
VarHandle addrHandle = MemoryHandles.asAddressVarHandle(goodPtrHandle);
MemoryAddress addrResult = (MemoryAddress) addrHandle.get(seg);