Conversion between Java objects and native pointers

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Fri Dec 2 17:02:46 UTC 2022


On 02/12/2022 16:44, Gregory Klyushnikov wrote:
> But since you say the decision to not allow native Java object handles 
> was intentional, I'll try it.

Some background: if we start allowing Java instances being passed to 
native function, then we have to start worrying about the same class 
"spoofing" issues that JNI suffers from.

That is, you can crete an handle for Foo in one class loader, then the 
handle is stored by the native code, and passed again to Java code in 
_another_ class loader, thus violating classloader constraints (maybe 
the class definition for Foo in that second class loader is different).

For these reasons, JNI restricted library loading to a _single_ class 
loader. This restriction solves the spoofing issues, but comes at a 
price: any attempt to load same library from two loaders will fail. 
Frameworks have in the past resorted to various "tricks" (such as 
renaming libraries) to workaround this limitation.

Since Panama doesn't allow passing Java objects _directly_ to native 
functions (you can pass memory segments, but they are either passed by 
reference - a long - or deconstructed into multiple primitive values 
which are then passed separately), it is not subject to same library 
loading limitations. That is, if you load a library with 
SymbolLookup::libraryLookup you can load it as many times as you like, 
from _any_ classloader you like. Which is nice to have.

Of course I understand where you are coming from with this use case: you 
want to store an object pointer in the native code. We have considered 
APIs to allow developers to do that (e.g. temporarily turn a Java object 
into a native memory segment, controlled by a given memory session). 
But, as shown above, there are some safety consideration when going down 
that path.

Now, in some cases, but not all, you can achieve a similar effect with 
the new scoped value feature:

https://openjdk.org/jeps/429

E.g. you could "bind" a ScopedValue object before the native call takes 
place, so that the receiver class is set to some known instance. The 
method handle you upcall to would read the ScopedValue, fetch the 
receiver instance, and dispatch to that.

This would be more efficient than using a Map (as ScopedValues have 
caches) - but your usage has to be "structured" for ScopedValue to be 
usable.

Anyway, I thought I'd mention the connection, in case it's useful (if 
not for this use case, for others).

Cheers
Maurizio





More information about the panama-dev mailing list