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