[foreign] programmatic access to native libraries w/o binder
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Nov 28 14:00:21 UTC 2018
Hi,
I took the patch at [1] for a spin with jshell. I wanted to see how easy
it was to call native functions using the SystemABI interface - e.g. w/o
binder and annotated interface. I think I'm pleasantly impressed! I did
some changes to the proposed patch as I wanted to put everything
SystemABI-specific in a public package (java.foreign) and I also added a
method on UpcallHandle to get a pointer. But overall these were minor
modification, mostly in order to be able to use this setup on jshell.
But let's dive on some code.
First, some setup:
$ jshell
| Welcome to JShell -- Version 12-internal
| For an introduction type: /help intro
jshell> import java.foreign.*
jshell> import java.foreign.memory.*
jshell> import java.lang.invoke.*
jshell> var abi = SystemABI.getInstance()
abi ==> jdk.internal.foreign.abi.sysv.x64.SysVx64ABI at 41cf53f9
Now that we have an ABI, let's try getpid:
jshell> var getpid =
abi.downcallHandle(Libraries.getDefaultLibrary().lookup("getpid"), new
NativeMethodType(NativeTypes.INT32))
getpid ==> MethodHandle()int
jshell> (int)getpid.invokeExact()
$6 ==> 20308
That was easy; let's try a function which actually takes some args:
jshell> var pow =
abi.downcallHandle(Libraries.getDefaultLibrary().lookup("pow"), new
NativeMethodType(NativeTypes.DOUBLE, NativeTypes.DOUBLE,
NativeTypes.DOUBLE))
pow ==> MethodHandle(double,double)double
jshell> (double)pow.invokeExact(2d, 3d)
$12 ==> 8.0
That works too. Finally, let's see if we can make qsort work - first
let's declare the comparison logic:
jshell> class Comp {
...> int comp(Pointer<Integer> p1, Pointer<Integer> p2) {
...> return p1.get() - p2.get();
...> }
...> }
| created class Comp
And allocate the stub:
jshell> var up = abi.upcallStub(abi.defaultCallingConvention(), new Comp(),
...> MethodHandles.lookup().findVirtual(Comp.class, "comp",
MethodType.methodType(int.class, Pointer.class, Pointer.class)),
...> new NativeMethodType(NativeTypes.INT32,
NativeTypes.INT.pointer(), NativeTypes.INT.pointer()));
up ==> jdk.internal.foreign.invokers.DirectUpcallHandle at dcf3e99
And finally, let's call qsort and print the results.
jshell> var qsort =
abi.downcallHandle(Libraries.getDefaultLibrary().lookup("qsort"),
...> new NativeMethodType(NativeTypes.VOID,
NativeTypes.INT.pointer(), NativeTypes.INT, NativeTypes.INT,
NativeTypes.VOID.pointer()));
qsort ==> MethodHandle(Pointer,int,int,Pointer)void
jshell> Scope sc = Scope.newNativeScope()
sc ==> jdk.internal.foreign.ScopeImpl$NativeScope at 5fdef03a
jshell> var arr = sc.allocateArray(NativeTypes.INT32, new int[] { 2, 6,
4, 8, 1, 10 });
arr ==> jdk.internal.foreign.memory.BoundedArray at 311d617d
jshell> qsort.invoke(arr.elementPointer(), 6, 4, up.entryPoint());
$13 ==> null
jshell> System.err.println(Arrays.toString(arr.toArray(int[]::new)));
[1, 2, 4, 6, 8, 10]
Cool! We have been able to do all this without using a single annotated
interface, which suggests that SystemABI might indeed be general enough
to build on top of it.
There are, I think, some hiccups in the above snippets which I found
annoying:
* having to create a NativeMethodType when I just want to pass the list
of layout types leads to more verbose code
* we might need NativeTypes.POINTER - doing NativeTypes.VOID.pointer()
is an explicit workaround, but a tad verbose
* as we already know, the upcallStub API point could use some
simplification: omit the receiver argument and directly return the
pointer; that will also simplify things
Maurizio
[1] -
https://cr.openjdk.java.net/~henryjen/panama/SystemABI/webrev.01/webrev/
More information about the panama-dev
mailing list