如何使用Java FFI访问MemoryLayout中的C_指针

如何使用Java FFI访问MemoryLayout中的C_指针,java,ffi,project-panama,Java,Ffi,Project Panama,使用JDK 16中的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.

使用JDK 16中的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);
    }
publicstaticvoidcheckprimitivecarriercompat(类载体,MemoryLayout布局){
checkLayoutType(布局,ValueLayout.class);
如果(!isValidPrimitiveCarrier(载波))
抛出新的IllegalArgumentException(“不支持的承运人:+carrier”);//抛出此异常,承运人的值为MemoryAddress
if(Wrapper.forPrimitiveType(carrier).bitWidth()!=layout.bitSize())
抛出新的IllegalArgumentException(“载波大小不匹配:“+Carrier+”!=“+layout”);
}
根据巴拿马的文档,C_指针的Java载体应该是
MemoryAddress
,但这在这里不起作用


那么使用long来访问这样的指针是否正确呢?还是别的什么?

正如Johannes在评论中指出的,可以用来调整
句柄,您必须接受并返回
内存地址

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);

简而言之,您必须使用
long
,然后调整生成的
VarHandle