Java object as a void*

Manuel Bleichenbacher manuel.bleichenbacher at gmail.com
Wed Feb 15 07:34:35 UTC 2023


Hi Maurizio

Thanks for the prompt answer.

I can understand that you are reluctant to introduce a new concept for a
use cases that isn't particularly frequent.

>From what I read about ScopedValues, I doubt they will be helpful. In many
of the use cases I'm dealing with, the void* parameter is used in a
cross-thread context and has a lifetime, which is not aligned with a
function call or a similar scope. A thread-local variable is not helpful
for my use cases. Doesn't this imply that ScopedValues won't help either?

Regarding JNI handles and resurrection I don't have sufficient insight into
the implementation to comment on this. Since it is already possible to bind
an object to a method handle, create an upcall stub for it and passed it
around in native code, it would seem to me that part of the challenges have
already been solved.

Regards
Manuel

Am Mi., 15. Feb. 2023 um 00:21 Uhr schrieb Maurizio Cimadamore <
maurizio.cimadamore at oracle.com>:

> Hi Manuel,
> in principle, it would be doable to expose an API which creates a JNI
> handle out of a Java object and exposes it as a MemorySegment so that it
> can be passed to native functions. One thing to consider is that if we
> started passing Java objects around to native code, then we'd also have
> to start worrying about the same objects being "resurrected" in
> unexpected places (e.g. created by one classloader, accessed by
> another). Some of these issues are the very reasons behind the
> classloader restrictions behind System::loadLibrary [1]. Perhaps here,
> since the API doing the access is a Java API, it might be possible to
> insert some kind of class loader check.
>
> That said, one of the main reason we did not add any special support for
> JNI handles is that, in addition to the workarounds you mention, a new
> and more powerful workaround is/will be possible from Java 20:
> ScopedValues [2]. That is, you can set up a scoped value, and "bind" it
> before the upcall runs (e.g. before you call the corresponding
> downcall). The bound value would then be in scope (as a sort of implicit
> parameter) inside the upcall code as well. Retrieving a scoped value is
> also quite fast (compared e.g. to a ThreadLocal).
>
> For this reason we'd like to see how using ScopedValues goes before
> thinking about adding more ad-hoc machinery to expose JNI handles in
> Panama.
>
> Cheers
> Maurizio
>
> [1] -
>
> https://docs.oracle.com/javase/7/docs/technotes/guides/jni/jni-12.html#libmanage
> [2] - https://openjdk.org/jeps/429
>
>
> On 14/02/2023 18:39, Manuel Bleichenbacher wrote:
> > Hi all
> >
> > Many native SDKs allow the caller to pass a void* or long as an
> > additional parameter. This parameter is then later provided as a
> > reference to the original call, either in the context of a callback
> > function call or as an attribute of an operating system object. The
> > native SDK will not interpret the parameter in any way, neither as a
> > number nor as a pointer. It's up to the caller to know what it
> represents.
> >
> > Examples are:
> >
> > lParam in Windows' SendMessage() -
> >
> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage
> >
> > dwNewLong in Windows' SetClassLongPtr() -
> >
> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongptrw
> >
> > arg in POSIX's pthread_create() -
> >
> https://pubs.opengroup.org/onlinepubs/000095399/functions/pthread_create.html
> >
> > refcon in macOS' WritePipeAsync() -
> >
> https://developer.apple.com/documentation/iokit/iousbinterfaceinterface800/1639539-writepipeasync
> >
> > Is there a way to use this from Java for Java objects, i.e. to pass a
> > Java object as a void* and later convert the void* back to the Java
> > object?
> >
> > Since the FFM API exposes void* as MemorySegments, it would probably
> > mean that a MemorySegment could be created encapsulating a reference
> > to a Java object, and that the Java object can later be retrieved from
> > this MemorySegment.
> >
> > I am aware of two workarounds:
> >
> > - In the context of a callback function, the Java callback function
> > can be extended with an additional parameter and then the Java object
> > can be bound to it. This function is then used to create the up call
> > stub. Since the callback function already contains the reference, the
> > void* parameter is no longer needed and can be passed
> > MemorySegment.NULL. In my context (I/O processing with several
> > thousand functions calls per second), it likely is rather inefficient
> > as several thousand upcall stubs will need to be generated by second.
> >
> > - Instead of the Java object, a generated integer key could be passed
> > as the void*. The link between the key and the Java object would need
> > to be managed in a hash map. Possible, but more of a workaround.
> >
> > Regards
> > Manuel
> >
> >
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20230215/cd72740b/attachment-0001.htm>


More information about the panama-dev mailing list