Panama and Swing/AWT support

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon May 29 08:40:59 UTC 2023


On 28/05/2023 20:50, Clayton Walker wrote:
> I've had success calling jni and awt functions via panama and 
> jextract-generated bindings. A few notes and questions below.
>
> First off I noticed a bug in jextract, it appears that in an anonymous 
> union the location will be dumped into the name field, which is 
> invalid on windows. The backslashes need to be escaped.
> .withName("union (anonymous at 
> C:\Users\Clayton\.jdks\openjdk-20.0.1\include\win32\jawt_md.h:42:5)"),
> I came across this when generating bindings to jawt on windows. Not 
> sure if it makes sense to include that path or not but I was able to 
> get around it by adding a Utils.quote call to Constants.java#340, like 
> so append(".withName(\"" + Utils.quote(l.name 
> <https://urldefense.com/v3/__http://l.name__;!!ACWV5N9M2RV99hQ!NZzKVdwoqGo5oDo6E4dLPZ7wZ5GFmFyiaSyGJk4cnIuOIOLfZ5PJL3wOxRylvOSOK-dvRUbJ2aHvsD1hLpnVPww8NZZmWkOH4w$>().get()) 
> + "\")");
That seems indeeed a bug - thanks
>
> Secondly, when using jextract does it make sense to call jextract 
> once? For example, there are jni functions that come from jni.dll, but 
> there are also awt functions that come from jawt.dll. Some of these 
> functions share definitions. Certain functions need jni loaded, and 
> certain ones need jawt. It doesn't necessarily make sense to load jawt 
> if only jni functions are going to be called, but in my case it's 
> fine. Is it expected for developers to call jextract twice, once per 
> library, or to perhaps create a meta-header that references both?

I think creating the meta-header which includes both and passing that to 
jextract is a fine approach here. Note that you can also use the options 
for printing all symbols and then filtering them, as explained here:

https://github.com/openjdk/jextract#filtering-symbols

>
> Also related to the above question, there are platform-specific 
> headers, jni_md.h and jawt_md.h that differ depending on the platform. 
> How are developers encouraged to share code in this place? Generate 
> all platform definitions at once, or once per platform then merge the 
> definitions, or once per platform and keep their jextract-extracted 
> source separate?

I think the last option you mention is the most frequent I've seen used. 
Jextract itself does something different when interacting with libclang, 
as libclang is written in portable C (so e.g. uses "long long" instead 
of "long") and all layouts ends up being ok across platforms, so that we 
don't really need different versions. My feeling is that jni itself 
should be portable (after all, JNI types are modelled after _Java_ 
types, whose sizes are known), I don't know about jawt. But it is 
possible that the differences are related to functions you don't care 
about? (in which case, extracting a mininum common denominator wouldn't 
be too bad?)

Maurizio

>
>
> On Wed, May 24, 2023 at 3:08 PM Maurizio Cimadamore 
> <maurizio.cimadamore at oracle.com> wrote:
>
>
>     On 24/05/2023 20:36, Clayton Walker wrote:
>>     Hi Maurizio,
>>     thanks for the detailed response!
>>
>>     I believe I understood this for the most part, but a quick
>>     question related to the jni references. Do we need to use
>>     NewGlobalRef so that we can exit the native jni function and not
>>     have their jni reference freed?
>     Yes, the global ref is required given that we go in and out of JNI
>     functions. Are you worried about the cost of creating global
>     references? (Trying to understand more about the use case)
>>
>>     Also would it make more sense to go this route than to expose a
>>     new function called (e.g.) getDrawingSurface method to the awt
>>     Component class which returns a MemorySegment that we can free?
>>     Presumably to avoid cluttering up awt/swing with additional
>>     native function calls, or perhaps avoid leaking implementation
>>     details to the java standard library?
>
>     I'm not an expert in AWT/Swing - but it would seem that, at a
>     glance, the Component class doesn't have much in terms of
>     low-level capabilities. So exposing a method which returns a
>     segment (or a ByteBuffer) would look a bit odd, I think.
>
>     Cheers
>     Maurizio
>
>>
>>     On Wed, May 24, 2023 at 12:22 PM Maurizio Cimadamore
>>     <maurizio.cimadamore at oracle.com> wrote:
>>
>>         Hi Clayton
>>         interacting with JNI code has few issues:
>>
>>         1. you need a JNIEnv* segment
>>         2. you need to be able to wrap Java objects as JNI references
>>         (so that they can be passed as pointers to native calls)
>>         3. expose some way to map method names into JNI mangled names
>>         (so that we can look those up using a symbol lookup)
>>
>>         This is something on our radar and we will like to address
>>         this use case at some point (but it is possible this might be
>>         addressed _after_ the FFM API is finalized). Two possible
>>         approaches are:
>>
>>         * a set of static helper functions which allow to obtain
>>         JNIEnv segment, as well as create, dereference and destroy
>>         JNI refs. We might even expose JNI functions here (think of a
>>         JNIUtils class)
>>         * a true JNILinker <: Linker - this might allow a tighter
>>         coupling with JNI functions (as the JNIEnv will be passed
>>         automatically)
>>
>>         I think the former approach is quite attractive in terms of
>>         bang for bucks. It doesn't add a lot of complexity to the
>>         API, and adds the minimum functionality that is required in
>>         order to allow the native linker to deal with JNI functions
>>         as well (even though developers will need to take some extra
>>         care when doing so).
>>
>>         In the meantime, I think it might be possible to define a
>>         small JNI library which takes care of the missing
>>         functionalities - e.g. it could return/accept JNI references
>>         as "jlong" (an hack, I know) so, something like this:
>>
>>         native long makeGlobalRef(Object o) // call NewGlobalRef,
>>         cast result to jlong and return
>>         native void destroyGlobalRef(long ref) // cast to jobject,
>>         then call DeleteGlobalRef
>>         native Object readGlobalRef(long ref) // cast to jobject, return
>>         native long getEnv(); // cast env parameter to jlong and return
>>
>>         I've tried something along those lines and it seems to work
>>         as expected. But I agree that it would be convenient if this
>>         "just worked" out of the box.
>>
>>         Cheers
>>         Maurizio
>>
>>
>>
>>         On 24/05/2023 18:28, Clayton Walker wrote:
>>>         I am working on a project with one of the goals being able
>>>         to use a swing component as a render target. From the
>>>         documentation here
>>>         <https://docs.oracle.com/javase/8/docs/technotes/guides/awt/AWT_Native_Interface.html> I
>>>         assume we need jni in order to access the native
>>>         PlatformInfo struct. My question is the same as asked in
>>>         this stackoverflow question
>>>         <https://urldefense.com/v3/__https://stackoverflow.com/questions/75620948/how-do-i-get-the-hwnd-of-a-canvas-using-panama__;!!ACWV5N9M2RV99hQ!Pq0tFxFIxoDHgX_vezwj24Kuk4wsYvPXLMS09T7SYv_UyIpO7nN_Sc1jmNWMzwSORL6P3_hbxJIXfK4h2FNcd_LAkn4CRaOc8w$>,
>>>         is it possible to use panama to get the HWND of a swing window?
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20230529/7d53d9ae/attachment-0001.htm>


More information about the panama-dev mailing list