Funneling Objects through void*
Jorn Vernee
jorn.vernee at oracle.com
Thu Jun 15 19:04:20 UTC 2023
Hey Johannes,
Some thoughts:
> Of course it is trivial to write such functionally using a counter
and a ConcurrentHashMap, but that is not the only possible implementation.
> In fact the JNI functions `newGlobalRef` and `deleteGlobalRef` would
provide an adequate implementation.
I'll note that newGlobalRef/deleteGlobalRef is implemented with a global
store (look e.g. for OopStorage::allocate [1]), and the object handle is
a pointer into that store. I.e. it is not too different from having a
global Map<Long, Object> somewhere, then passing the `long` (analogous
to the JNI handle) around through native code, and 'resolving' it
through Map::get when getting back into Java. Global refs are also a
generically applicable mechanism, and I suspect that most use cases
would benefit from a more custom tailored solution for that particular
use case. Though, I agree that the problem exists (and it's something
we've run into as well [2])
I think we mostly discussed adding direct support for Object -> JNI
handle conversions in order to interoperate with native functions that
depend on JNI (such as the native AWT API from that SO question you linked).
> Currently I have to create a new upcall stub for every invocation
What is the problem with doing this? Is it cumbersome? Or does it seem
wasteful? WRT the latter, we still have some options for making upcall
stub allocation with the same FunctionDescriptor share the same VM stub
(mostly). Though, we already share the Java wrapper class at the moment.
In both of these cases, I wonder if the best solution we can provide is
a more intuitive/convenient way of addressing these use cases, rather
than something which necessarily has a better implementation than what a
user can do today.
Jorn
[1]:
https://github.com/openjdk/jdk/blob/3e0bbd290c534b0f9729c54cd45308d505907797/src/hotspot/share/gc/shared/oopStorage.cpp#L436
[2]:
https://github.com/openjdk/jextract/blob/cf3afe9ca71592c8ebb32f219707285dd1d5b28a/src/main/java/org/openjdk/jextract/clang/Cursor.java#L194
On 15/06/2023 18:05, Johannes Kuhn wrote:
> When trying to help this StackOverflow question[1], I tried to use
> `EnumWindows`[2]. EnumWindows takes a callback and a void* parameter
> and invokes the callback using the toplevel HWND & the passed void*
> parameter.
>
> Currently I have to create a new upcall stub for every invocation, but
> if I could funnel some java.lang.Object through the void* parameter, I
> would only need to create a single upcall, where I retrieve the
> object, cast it and call some method on it.
>
> Example (pseudo) code:
>
> public interface EnumWindowsCallback {
> int callback(long hwnd);
> }
> private static int enumWindowsUpcall(long hwnd, MemoryAddress obj) {
> return (int) ((EnumWindowsCallback)
> toObject(obj)).callback(hwnd);
> }
>
> public static int enumWindows(EnumWindowsCallback cb) throws
> Throwable {
> try (Arena arena = Arena.ofConfined()) {
> return (int)
> ENUM_WINDOWS_MH.invokeExact(ENUM_WINDOWS_UPCALL, toPointer(arena, cb));
> }
> }
>
> One problem is that the arena is not accessible within the callback.
>
>
> Of course it is trivial to write such functionally using a counter and
> a ConcurrentHashMap, but that is not the only possible implementation.
>
> In fact the JNI functions `newGlobalRef` and `deleteGlobalRef` would
> provide an adequate implementation.
>
> - Johannes
>
> [1]:
> https://stackoverflow.com/questions/75620948/how-do-i-get-the-hwnd-of-a-canvas-using-panama/
> [2]:
> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumwindows
More information about the panama-dev
mailing list