[foreign] programmatic access to native libraries w/o binder

Jorn Vernee jbvernee at xs4all.nl
Wed Nov 28 15:27:23 UTC 2018


Looking good!

> * 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

Reading through the code, I prefer both of these actually, since it 
makes the code more visually explicit as to what's happening. The `new 
NativeType(...)` call also gives a visual grouping to the arguments. 
Though I admit, I like being very descriptive when writing code.

Tbh, I mostly expect the NativeMethodType to be constructed 
automatically, e.g. by deriving the signature from a mangled symbol 
name, so I'm not sure how much verbosity will be a problem in practice.

To save on characters I'd suggest using `import static NativeTypes.*`, 
and perhaps we could add a convenience overload of upcallStub which 
doesn't take the target MethodHandle, and instead tries to infer it from 
the passed receiver object?

     default UpcallHandle upcallStub(Object receiver, NativeMethodType 
nmt) {
         Method m = receiver.getClass().getDeclaredMethods()[0]; // you 
get the gist
         return upcallStub(cc, receiver, publicLookup().unreflect(m), 
nmt);
     }

Btw, now that we're starting to have NativeTypes and NativeMethodType 
maybe we should consider renaming LayoutType to NativeType as well?

Jorn

Maurizio Cimadamore schreef op 2018-11-28 15:00:
> 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