javamemorynativeunsatisfiedlinkerror

JDK 17 Foreign memory API throws exception - Method threw 'java.lang.UnsatisfiedLinkError' exception


I'm trying to execute the following code using JDK 17.0.1. I have ensured the JDK 17 is on the class path.

Here is the code i'm executing:

import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryHandles;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;


import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;

public class PanamaMain {
    public static void main (String[] args) {
        MemoryAddress address = MemorySegment.allocateNative(4, ResourceScope.newImplicitScope()).address();

        VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());

        int value = (int) handle.get(address); //This line throws the exception mentioned above.

        System.out.println("Memory Value: " + value);
    }
}

The cause of the exception is: java.lang.UnsatisfiedLinkError: 'java.lang.Object java.lang.invoke.VarHandle.get(java.lang.Object[])'

Exception Details
enter image description here

I saw some replies on a similar exception suggesting using the java.library.path system property but I got an error that the java.library.path is an invalid flag.

I would appreciate your help/tips on this issue! Thank you in advance for your time!


Solution

  • The VarHandle.get method is expecting a MemorySegment (not MemoryAddress) and offset in bytes within the segment. The layouts of standard C types are found in CLinker.C_XXX so you don't need to hardcode byte size of int as 4.

    Assuming that your PATH is correct for launching JDK17 then this should work:

    MemorySegment segment = MemorySegment.allocateNative(CLinker.C_INT, ResourceScope.newImplicitScope());
    VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());
    handle.set(segment, 0, 4567);
    int value = (int)handle.get(segment, 0);
    System.out.println("Memory Value: " + value + " = 0x"+Integer.toHexString(value));
    

    Prints:

    Memory Value: 4567 = 0x11d7
    

    In JDK17 you can also use MemoryAccess to set or get values from allocated MemorySegment. , and could change to:

    MemorySegment segment = MemorySegment.allocateNative(CLinker.C_INT, ResourceScope.newImplicitScope());
    MemoryAccess.setInt(segment, -1234);
    int value = MemoryAccess.getInt(segment);
    System.out.println("Memory Value: " + value + " = 0x"+Integer.toHexString(value));
    

    Prints

    Memory Value: -1234 = 0xfffffb2e
    

    Note that the API has changed, so the equivalent code in JDK18+ will be different.