working with JNR

667 views
Skip to first unread message

John Rose

unread,
Aug 22, 2013, 8:16:05 PM8/22/13
to jvm...@googlegroups.com
I've worked with a lot of FFIs (starting with Common Lisp in the '80s), and I've written a few, such as:
https://blogs.oracle.com/jrose/resource/esh/RoseMullerIX.html

That said, I think JNR is the best such thing yet for Java. The libffi under it is amazingly portable. Charlie's presentation at the JVM Language Summit was compelling.

So JNR makes an unusually good starting point for a standards discussion.

I also think there are ways to improve JNR to make it even more useful. (For its natural use cases, putting that question aside for the moment.)

Here is a brief four-point sketch of possible areas for adjustment.

A. [layering] Clearly distinguish three APIs: The end-user API, the metadata API, and the JVM-facing API. (Currently, metadata is "interpretively" entangled with at least some end-user objects, such as data structs.)

The JVM-facing API is the peeks and pokes; Unsafe is designed to be this (the jffi is within epsilon of the missing bit there).

The metadata API should do most of its work before making a single native call or data access. (More later.)

The end-user API should be easy to use from Java code, wrappable, reasonably well typed, etc., etc.

B. [interfaces] Use interfaces for data as well as functions. (Current JNR uses concrete classes.)

By abstracting data accesses we can do various useful games, such as redirecting accesses to other processes or core files. We can also wrap big invariants around data accesses, such as "allow safepoints here but only if managed pointers are handle-ized".

C. [metadata] Generate metadata, for both functions and data, from a header file scanner. Run the user layer from this metadata, not from classes the user wrote to ape the contents of a C header file.

libclang appears to be an ideal starting point for the frontend. (I did it once with yacc, and Ken Russell and I did it once with swig. Having a real front end would be refreshing.)

D. [optimizability] Calls and data structure accesses from Java should JIT-compile to about the same code as the C compiler emits for it's own accesses.

Getting the layering right will make this possible. The metadata has to be something "static" that the JIT can consult while it processes native access points in Java code. The JVM-facing API (Unsafe+jffi) has to be built from metadata driven intrinsics that the compiler can fold up to C-like code.

This is presently the case for Unsafe-based data accesses, but getting the JIT to understand the jffi view of things will be tricky, because of the "interpretive" orientation of the jffi/libffi stuff.

Big cheers,
— John

mr...@roos.com

unread,
Aug 22, 2013, 10:34:56 PM8/22/13
to jvm...@googlegroups.com
How about generating code on the fly (llvm jit) and linking it in via jnr and method handles or something similar?

mark

John Rose

unread,
Aug 22, 2013, 11:05:14 PM8/22/13
to mr...@roos.com, jvm...@googlegroups.com
On Aug 22, 2013, at 7:34 PM, mr...@roos.com wrote:

How about generating code on the fly (llvm jit) and linking it in via jnr and method handles or something similar?

Something like that.

JVMs have a code generator; it is usually not the llvm jit but it could be.  And the JIT typically has at least some capability to call C code, since JVM JITs (probably) call runtime support routines coded in C.

With the right JIT logic, the native calls to the C code can be a natural consequence of JIT compilation, rather than a special code generation mode.

HotSpot's JIT can handle typical C calling convention shapes, though nowhere near the repertoire of libffi (the magic under JNA).  But the typical shapes are enough to funnel all the edge cases through JNA.

Perhaps a specially marked "native" method handle will be useful; not sure yet.

— John

Rémi Forax

unread,
Aug 23, 2013, 5:02:39 AM8/23/13
to jvm...@googlegroups.com


On Friday, August 23, 2013 2:16:05 AM UTC+2, John Rose wrote:
I've worked with a lot of FFIs (starting with Common Lisp in the '80s), and I've written a few, such as:
  https://blogs.oracle.com/jrose/resource/esh/RoseMullerIX.html

That said, I think JNR is the best such thing yet for Java.  The libffi under it is amazingly portable.  Charlie's presentation at the JVM Language Summit was compelling.

So JNR makes an unusually good starting point for a standards discussion.

I also think there are ways to improve JNR to make it even more useful.  (For its natural use cases, putting that question aside for the moment.)

Here is a brief four-point sketch of possible areas for adjustment.

A. [layering] Clearly distinguish three APIs:  The end-user API, the metadata API, and the JVM-facing API.  (Currently, metadata is "interpretively" entangled with at least some end-user objects, such as data structs.)

The JVM-facing API is the peeks and pokes; Unsafe is designed to be this (the jffi is within epsilon of the missing bit there).

The metadata API should do most of its work before making a single native call or data access.  (More later.)

The end-user API should be easy to use from Java code, wrappable, reasonably well typed, etc., etc.

B. [interfaces] Use interfaces for data as well as functions.  (Current JNR uses concrete classes.)

By abstracting data accesses we can do various useful games, such as redirecting accesses to other processes or core files.  We can also wrap big invariants around data accesses, such as "allow safepoints here but only if managed pointers are handle-ized".

yes, data access should be done through interfaces, it's more flexible and allows to change the implementation bits whenever we want.
There is still the issue of C primitive types that do not exist in Java or not map well with a primitive Java type,
unsigned long by example.
 

C. [metadata] Generate metadata, for both functions and data, from a header file scanner.  Run the user layer from this metadata, not from classes the user wrote to ape the contents of a C header file.

libclang appears to be an ideal starting point for the frontend.  (I did it once with yacc, and Ken Russell and I did it once with swig.  Having a real front end would be refreshing.)

Having the frontend integrated with javac is in my opinion something we should study.
And given that libclang is written in C++, it's a nice test case for eating our own dog food :)

But the metadata API should be normalized enough to let user write it's own mapping if he wants.
 

D. [optimizability] Calls and data structure accesses from Java should JIT-compile to about the same code as the C compiler emits for it's own accesses.

Getting the layering right will make this possible.  The metadata has to be something "static" that the JIT can consult while it processes native access points in Java code.  The JVM-facing API (Unsafe+jffi) has to be built from metadata driven intrinsics that the compiler can fold up to C-like code.

This is presently the case for Unsafe-based data accesses, but getting the JIT to understand the jffi view of things will be tricky, because of the "interpretive" orientation of the jffi/libffi stuff.

From the implementation perspective, I dream about an implementation (implementation of the interface corresponding to the function and the data) doing no bytecode generation but using only method handles.
 

Big cheers,
— John


cheers,
Rémi
 

Jeroen Frijters

unread,
Aug 23, 2013, 5:36:08 AM8/23/13
to jvm...@googlegroups.com
> B. [interfaces] Use interfaces for data as well as functions.
> (Current JNR uses concrete classes.)

I don't like the idea of having to use interfaces for data. It makes things more complicated and more verbose and I don't buy that the VM needs the extra flexibility.

The fact that both JNR and .NET use concrete types here should count as significant evidence against using interfaces in my opinion.

Regards,
Jeroen

Remi Forax

unread,
Aug 23, 2013, 8:52:27 AM8/23/13
to jvm...@googlegroups.com
Hi Jeroen,
Not sure, one advantage I see to interface is that you can fake access
without exposing the underlying concept into the language.
By example, C has struct (as C#) but not Java. With an interface, you
can teach the JIT how to access an array of structs without
incluing the struct concept in Java (and avoid the unsafe Memory object
of JNR).

>
> Regards,
> Jeroen
>

cheers,
R�mi

Jeroen Frijters

unread,
Aug 23, 2013, 9:14:08 AM8/23/13
to Remi Forax, jvm...@googlegroups.com
Hi Rémi,

> Not sure, one advantage I see to interface is that you can fake access
> without exposing the underlying concept into the language.

That's true, but it breaks down (or at least becomes as complex as doing it manually) for complex structures.

In .NET you also have to fall back to manual marshaling for complex structs, but it is really nice for the common case to be simple.

I guess it depends on how much typical scenarios you can cover with just the basic stuff. It might be worthwhile to study some JNI and JNR code. My hunch is that you can get pretty far by supporting just the Java types (if you accept the fact that Strings and arrays require copying). For advanced use cases there will need to be an Unsafe like API anyway.

Regards,
Jeroen

mr...@roos.com

unread,
Aug 23, 2013, 4:27:08 PM8/23/13
to jvm...@googlegroups.com
So in Smalltalk creating a methodHandle to a C api (SocketsDLL  bind) looks like this:

bind:aHandle name:aStruct nameSize:aInt3
        "Private - bind a name  to the socket"
    <api: BIND long struct long long>
    ^self invalidArgument

Where  api: is the calling convention ( c in this case) then an array of conversion types.  
Since this is C the conversions are nicely limited.  The code after the api line is executed on 
a failure in the call.  Arguments from the top line are applied in order to the C call.  
This approach has allowed us to call any available C function without any additional work.

Other api types are pascal and 16/32/64 bit calls.  And structures ( actually byteArrays ) can
be on the heap or off the heap.

It would be nice to have something as simple as this.

Simon Ochsenreither

unread,
Aug 25, 2013, 8:31:29 AM8/25/13
to jvm...@googlegroups.com, Remi Forax
Hi,


> Not sure, one advantage I see to interface is that you can fake access
> without exposing the underlying concept into the language.

support for structs-by-interface will just mean that as soon as this feature ships, tons of people will start converting their JVM classes to JNR-backed value types (including me).
I'm pretty sure that's not the way you want to introduce value types to the platform.


That's true, but it breaks down (or at least becomes as complex as doing it manually) for complex structures.

In .NET you also have to fall back to manual marshaling for complex structs, but it is really nice for the common case to be simple.

I agree with Jeroen here.
One might argue that .NET hasn't gone far enough with their marshaling support, but making a conscious decision to not even try ship with a reasonable feature set would be worse than not shipping anything.

If there is a new FFI library, it should have reasonable support for the majority of use-cases (e. g. including structs and unions).
Having yet-another-API which only works for passing a severely restricted set of primitive types is next to pointless.

It might be the best to post-pone JNR until the JVM has a non-embarrassing support story for value types, so that people are not stuck with an under-developed and over-specified FFI for the rest of the JVM's life.

Bye,

Simon

mark roos

unread,
Aug 25, 2013, 4:54:57 PM8/25/13
to jvm...@googlegroups.com
I would like to see a simple low level implementation (jvm level not java) to support value types since
I see this as a major use case.   At the lowest level I could see restrictions on the api similar
to those imposed on intrinsics.  Simple conversions from Java primitives could be via lambda form
like constructs.

Having value types that are byteArrays ( on heap or off ) and the ability to generate intrinsics to support
them would be a nice support feature for my language experiments.  Rather than depending on TaggedArrays
I could try my own types.

Improving the current use cases for JNI is an admirable goal,  but there are ways to handle that use
case today.  Enabling efficient value types would be a new addition

mark


Jeroen Frijters

unread,
Aug 26, 2013, 2:48:18 AM8/26/13
to Simon Ochsenreither, jvm...@googlegroups.com, Remi Forax
Simon Ochsenreither wrote:
> It might be the best to post-pone JNR until the JVM has a non-
> embarrassing support story for value types, so that people are not stuck
> with an under-developed and over-specified FFI for the rest of the JVM's
> life.

I'm tempted to agree. The counter point is that it might take a while to get value types and other desirable features.

I also think that by-reference parameters would be really nice to add to the JVM, in general and in particular relating to value types and FFI. Having these two features are important if you want to make it possible to avoid memory allocations.

Regards,
Jeroen

Christoph Engelbert

unread,
Aug 26, 2013, 4:23:38 AM8/26/13
to jvm...@googlegroups.com, Simon Ochsenreither, Remi Forax
Hi Simon

Am Montag, 26. August 2013 08:48:18 UTC+2 schrieb jeroen:
Simon Ochsenreither wrote:
I also think that by-reference parameters would be really nice to add to the JVM, in general and in particular relating to value types and FFI. Having these two features are important if you want to make it possible to avoid memory allocations.


I don't like the idea of introducing by-reference parameters. This will bring Java a lot of complexity that isn't available by just having by-value references.

Chris
 
Regards,
Jeroen

William Leslie

unread,
Aug 26, 2013, 8:37:06 AM8/26/13
to jvm...@googlegroups.com
On Saturday, August 24, 2013 6:27:08 AM UTC+10, mark roos wrote:
bind:aHandle name:aStruct nameSize:aInt3
        "Private - bind a name  to the socket"
    <api: BIND long struct long long>
    ^self invalidArgument

It would be nice to have something as simple as this.

There are a number of angles that someone using an FFI might come from.  Wrapping an ABI in this style is one thing and sometimes it works, but there will also be those working with unweildly, forever changing header files - having to maintain their translation into a ctypes-style interface definition is prohibitive, but there probably is no reason to drive such users to the JNI. There is also a middle ground, signatures that could easily be declared explicitly, but that have some declared discipline around who is responsible for cleaning up the arguments or return value, or contracts that otherwise affect the lifetime of a value; or even whether the result is mutable when a function can return a const pointer.

Perhaps a good example of the other extreme is http://cffi.readthedocs.org/en/release-0.7/#examples

John Cowan

unread,
Aug 26, 2013, 11:15:19 AM8/26/13
to William Leslie, jvm...@googlegroups.com



On Mon, Aug 26, 2013 at 8:37 AM, William Leslie
 
There are a number of angles that someone using an FFI might come from.  Wrapping an ABI in this style is one thing and sometimes it works, but there will also be those working with unweildly, forever changing header files - having to maintain their translation into a ctypes-style interface definition is prohibitive, but there probably is no reason to drive such users to the JNI.

C header file translators aren't really that difficult to write, if they don't have to be 100% perfect.  (C++ is another matter.) 

-- 
GMail doesn't have rotating .sigs, but you can see mine at http://www.ccil.org/~cowan/signatures

Kevin Burton

unread,
Aug 26, 2013, 1:12:22 PM8/26/13
to jvm...@googlegroups.com


On Thursday, August 22, 2013 5:16:05 PM UTC-7, John Rose wrote:
I've worked with a lot of FFIs (starting with Common Lisp in the '80s), and I've written a few, such as:
  https://blogs.oracle.com/jrose/resource/esh/RoseMullerIX.html

That said, I think JNR is the best such thing yet for Java.  The libffi under it is amazingly portable.  Charlie's presentation at the JVM Language Summit was compelling.


Is there a video of this anywhere? 

Patrick Wright

unread,
Aug 26, 2013, 3:39:14 PM8/26/13
to jvm...@googlegroups.com
Just a note re: value types, there are some ideas and proposals kicking around, including a project by Gil Tene and Martin Thompson to introduce a mechanism using normal Java classes which could be optimized in future JVMs - 

and discussion when it was introduced a few weeks ago

I mention this just to note that there are related conversations going on in the community that might inform the discussion here.

Regards
Patrick

Simon Ochsenreither

unread,
Aug 27, 2013, 8:30:57 AM8/27/13
to jvm...@googlegroups.com
See also “Value Objects” http://openjdk.java.net/jeps/169 and “Packed Objects” https://groups.google.com/forum/#!topic/mechanical-sympathy/2m7oafpSauA.

I know all of these proposals. If this is the best thing Java people can come up with, then it might be more honest to just freeze Java and the JVM completely, and tell people who are looking for a runtime not stuck in 1980 to go looking somewhere else.

Charles Oliver Nutter

unread,
Aug 27, 2013, 1:26:42 PM8/27/13
to Jeroen Frijters, jvm...@googlegroups.com
I tend to agree with Jeroen here, mostly because I've learned that
hoping for the JVM to eventually optimize something is a trail of
tears.

It's certainly possible that at some point the JVM will be able to
optimize interface-fronted data objects as well as straight-up value
types, but we're not there right now. Also, I don't require any
proposals for real value types in the JVM to support interfaces.

That said...I also agree that not using interfaces may make it harder
for different JVMs to optimize those objects in their own way. A JVM
may want to back an object with real native memory or some internal
value type, and if it has to behave like a normal class or object
(constructible, specific concrete type, reflectable object layout...)
the JVM's options are more limited.

- Charlie

Charles Oliver Nutter

unread,
Aug 27, 2013, 1:33:57 PM8/27/13
to mr...@roos.com, jvm...@googlegroups.com
There are a number of examples of Ruby's FFI here, in Rubinius's
implementation of the "socket" library:
https://github.com/rubinius/rubinius/blob/master/lib/19/socket.rb#L298

The Ruby FFI API was originally designed by Evan Phoenix, and later
expanded and implemented for C Ruby and JRuby by Wayne. I think it's
about as simple as you can get.

I'll make another post with some information on various FFI libraries and tools.

- Charlie
> --
> You received this message because you are subscribed to the Google Groups
> "jvm-ffi" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to jvm-ffi+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Christoph Engelbert

unread,
Aug 28, 2013, 3:03:09 AM8/28/13
to jvm...@googlegroups.com, mr...@roos.com
Maybe it would be sufficient to make the support for by-reference
parameters just available to the bytecode level. In that case
bytecode-generators will have the chance to optimize calls to FFI
and for Java on language level just make an annotation as @OUT which
will be handled by the compiler and is just available in context of
FFI calls.
I would not give Java itself the possibility to make by-reference
calls, it would make the general language way harder to understand
and break the best feature: simplicity.

Christoph Engelbert

unread,
Sep 30, 2013, 1:34:45 PM9/30/13
to jvm...@googlegroups.com, mr...@roos.com
Is the discussion dead or have I missed a new position?

Chris
Reply all
Reply to author
Forward
0 new messages