javajava-ffm

Pass argument of type void** (pointers of pointers) using Java FFM API


How to pass argument void** using java FFM API?

void initHandle(void* handle);
void useHandles(void** handles);

The following did not work for me:

var LINKER = Linker.nativeLinker();
var SYM_LOOKUP = SymbolLookup.loaderLookup().or(LINKER.defaultLookup());
var INIT_HANDLE = LINKER.downcallHandle(SYM_LOOKUP.find("init_handle").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));
var USE_HANDLES = LINKER.downcallHandle(SYM_LOOKUP.find("use_handles").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));

try (var arena = Arena.ofConfined()) {
    List<MemorySegment> handleList = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        var handle = arena.allocate(ADDRESS);
        INIT_HANDLE.invokeExact(handle);
        handleList.add(handle);
    }

    // ...

    var handlesHandle = arena.allocate(ADDRESS, handleList.size());
    for (int i = 0; i < handleList.size(); i++) {
        handlesHandle.setAtIndex(ADDRESS, i, handleList.get(i).get(ADDRESS, 0));
    }
    USE_HANDLES.invokeExact(handlesHandle.get(ADDRESS, 0)); // this is not working as expected
}

Solution

  • I had to add MemorySegment::address() instead of the MemorySegment itself:

    var LINKER = Linker.nativeLinker();
    var SYM_LOOKUP = SymbolLookup.loaderLookup().or(LINKER.defaultLookup());
    var INIT_HANDLE = LINKER.downcallHandle(SYM_LOOKUP.find("init_handle").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));
    var USE_HANDLES = LINKER.downcallHandle(SYM_LOOKUP.find("use_handles").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));
    
    try (var arena = Arena.ofConfined()) {
        List<MemorySegment> handleList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            var handle = arena.allocate(ADDRESS);
            INIT_HANDLE.invokeExact(handle);
            handleList.add(handle);
        }
    
        // ...
    
        var handlesHandle = arena.allocate(ADDRESS, handleList.size());
        for (int i = 0; i < handleList.size(); i++) {
            handlesHandle.setAtIndex(JAVA_LONG, i, handleList.get(i).address());
        }
        USE_HANDLES.invokeExact(handlesHandle.get(ADDRESS, 0)); // this is working as expected now
    }