Java object as a void*

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Feb 14 23:21:18 UTC 2023


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
>
>
>
>


More information about the panama-dev mailing list