import java.lang.foreign.*;
import java.lang.invoke.*;
import static java.lang.foreign.ValueLayout.*;

public class FfmUpcallDemo {
    static int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) throws Throwable {
        Linker linker = Linker.nativeLinker();
        MethodHandle add = MethodHandles.lookup().findStatic(
                FfmUpcallDemo.class, "add",
                MethodType.methodType(int.class, int.class, int.class));

        FunctionDescriptor descriptor =
                FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT);

        try (Arena arena = Arena.ofConfined()) {
            MemorySegment stub = linker.upcallStub(add, descriptor, arena);
            MethodHandle caller = linker.downcallHandle(stub, descriptor);
            int result = (int) caller.invokeExact(20, 22);
            System.out.println("upcall result=" + result);
        }
    }
}
