jextract looses type safety in generated bindings

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Apr 7 10:57:45 UTC 2021


On 07/04/2021 11:13, Michael Böckling wrote:
> Hi!
>
> I'm currently evaluating the different FFI options on the JVM. I have
> noticed that the Java type signatures emitted by jextract are somewhat
> lossy. I'll provide an example:
>
> radar_processor.h:
>      void process_radar(t_radar_measurement* in, t_radar_decision* out);
>
> maps to:
>
> public final class radar_processor_h  {
>      public static void create_radar_measurement ( Addressable measurement)
> { ... }
> }
>
> Contrast this with JNAerator, which generates the following binding:
>
> public static void create_radar_measurement(Pointer<t_radar_measurement >
> measurement) { ... }

So, to make things clear, JNAerator supports two backends, JNA and 
BridJ. JNA itself doesn't support generic pointers, right?

https://java-native-access.github.io/jna/4.2.1/com/sun/jna/Pointer.html

So, it seems to me that the code you are quoting probably depends on the 
BridJ backend which defines its own Pointer class that has generics:

http://nativelibs4java.sourceforge.net/bridj/api/development/org/bridj/Pointer.html

Is this correct?

>
> Notice how the t_radar_measurement* type has been erased with a generic
> Addressable in the case of jextract.
> What I want to do is determine function argument types of generated java
> bindings via reflection and auto-instantiate the mapped structs. This works
> fine in JNAerator, due to the way the bindings are generated, but not with
> jextract. Is there a specific reason to use generic types like Addressable
> instead of the known, more specific one like t_radar_measurement*?

The main goal of jextract (at least for now) is to autogenerate bindings 
based on the Foreign Memory Access and Foreign Linker API in a way so 
that as little overhead as possible (ideally zero) is introduced.

All abstractions, such as the Pointer abstraction above introduce some 
kind of overhead, depending on many factors, the main one being how 
strict type checks are. For instance, when looking at BridJ's Pointer 
API, I see generics, but I also see things like getBooleanAtIndex: does 
it mean that I can call getBooleanAtIndex on a Pointer<foo> ? Or is 
there some dynamic check going on (as seem suggested by the cast(Type) 
method) ?

If the latter, we had an API similar to that in an earlier iteration of 
the Panama project (another Pointer-like API); while this API was 
enough, from an expressiveness perspective, to support jextract use 
cases, it also added noticeable overhead to basic operation like pointer 
dereference.

Nothing is written in stone of course, and the situation is fluid; I 
believe that once some of the Valhalla improvements will be ready, and 
when the VM will be able to "trust" instance final fields more, we might 
be in a position to write an efficient pointer class wrapper; with the 
VM we have now, we are forced to pick between expressiveness and 
performance. We decided for the latter, as it is always possible to add 
expressiveness later. In that sense, jextract is not, strictly speaking, 
a full JNAerator/BridJ replacement (but it is probably more similar to 
JNAerator/JNA).

Maurizio

>
> Best regards,
> Michael


More information about the panama-dev mailing list