Hi jextract team I've been playing with the upcoming GraalVM 25 and its support for FFM. But I've run into an issue with code generated by jextract related to function pointers: it always instantiates both the downcall and upcall method handles, independent of which one is actually used. In my case, I would only need the downcall handle. The unnecessary upcall handle depends on another method ("apply") that GraalVM has correctly identified to never be called and is thus omitted from the native image. As a result, the application crashes at run-time. It wouldn't be such a problem if I was dealing with one or two function pointers. Then I would manually create the required FFM code with downcall handles only. However, I'm dealing with COM interfaces and the macOS IOKit version thereof: *typedef* *struct* IOUSBInterfaceStruct942 { IUNKNOWN_C_GUTS; IOReturn (*CreateInterfaceAsyncEventSource)(*void* **self*, CFRunLoopSourceRef *source); CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(*void* **self*); IOReturn (*CreateInterfaceAsyncPort)(*void* **self*, mach_port_t *port); mach_port_t (*GetInterfaceAsyncPort)(*void* **self*); IOReturn (*USBInterfaceOpen)(*void* **self*); IOReturn (*USBInterfaceClose)(*void* **self*); IOReturn (*GetInterfaceClass)(*void* **self*, UInt8 *intfClass); IOReturn (*GetInterfaceSubClass)(*void* **self*, UInt8 *intfSubClass); IOReturn (*GetInterfaceProtocol)(*void* **self*, UInt8 *intfProtocol); IOReturn (*GetDeviceVendor)(*void* **self*, UInt16 *devVendor); ... These are structs that almost exclusively consist of function pointers. In the case of IOKit, the two main ones consist of 40 and 50 function pointers. Am I correct that there is currently no way to suppress the generation of upcall method handles? Are there any plans to to make the jextract generated code work well with GraalVM? Regards Manuel
Seems related to this? https://git.openjdk.org/jextract/pull/287 It would be very helpful if you could try the option in that PR (you would need to build jextract manually) and see if that improves the situation. Cheers Maurizio On 10/09/2025 12:46, Manuel Bleichenbacher wrote:
Hi jextract team
I've been playing with the upcoming GraalVM 25 and its support for FFM. But I've run into an issue with code generated by jextract related to function pointers: it always instantiates both the downcall and upcall method handles, independent of which one is actually used. In my case, I would only need the downcall handle. The unnecessary upcall handle depends on another method ("apply") that GraalVM has correctly identified to never be called and is thus omitted from the native image. As a result, the application crashes at run-time.
It wouldn't be such a problem if I was dealing with one or two function pointers. Then I would manually create the required FFM code with downcall handles only. However, I'm dealing with COM interfaces and the macOS IOKit version thereof:
*typedef**struct*IOUSBInterfaceStruct942{
IUNKNOWN_C_GUTS;
IOReturn (*CreateInterfaceAsyncEventSource)(*void* **self*, CFRunLoopSourceRef *source);
CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(*void* **self*);
IOReturn (*CreateInterfaceAsyncPort)(*void* **self*, mach_port_t *port);
mach_port_t (*GetInterfaceAsyncPort)(*void* **self*);
IOReturn (*USBInterfaceOpen)(*void* **self*);
IOReturn (*USBInterfaceClose)(*void* **self*);
IOReturn (*GetInterfaceClass)(*void* **self*, UInt8 *intfClass);
IOReturn (*GetInterfaceSubClass)(*void* **self*, UInt8 *intfSubClass);
IOReturn (*GetInterfaceProtocol)(*void* **self*, UInt8 *intfProtocol);
IOReturn (*GetDeviceVendor)(*void* **self*, UInt16 *devVendor);
...
These are structs that almost exclusively consist of function pointers. In the case of IOKit, the two main ones consist of 40 and 50 function pointers.
Am I correct that there is currently no way to suppress the generation of upcall method handles?
Are there any plans to to make the jextract generated code work well with GraalVM?
Regards Manuel
Hi Maurizio The pull request solves something different. It simplifies invoking function pointers that are part of a struct. For COM interfaces and similar constructs, this is quite useful. However, the code for the upcall and downcall handle hasn't changed. They are still static fields of an inner class. So they will always be instantiated as a pair. But it might be useful to go one step further with this pull request and not emit the upcall (method handle, function interface, "apply" method) if the "functional" option is specified. Or even consider emitting code like my Windows API Generator does for COM interfaces (see https://github.com/manuelbl/WindowsApiGenerator/blob/main/docs/com_interface...). It doesn't create an interface for each function pointer, but a single one for the entire struct, separate implementation classes for downcalls (calling a COM interface) and upcalls (implementing COM interfaces). By the way: the current pull request has a further problem. I generates code that doesn't compile. Depending on the arguments of the function pointer, the setter and the invoker method have the same arguments and clash. Regards Manuel Am Mi., 10. Sept. 2025 um 14:25 Uhr schrieb Maurizio Cimadamore < maurizio.cimadamore@oracle.com>:
Seems related to this?
https://git.openjdk.org/jextract/pull/287
It would be very helpful if you could try the option in that PR (you would need to build jextract manually) and see if that improves the situation.
Cheers Maurizio On 10/09/2025 12:46, Manuel Bleichenbacher wrote:
Hi jextract team
I've been playing with the upcoming GraalVM 25 and its support for FFM. But I've run into an issue with code generated by jextract related to function pointers: it always instantiates both the downcall and upcall method handles, independent of which one is actually used. In my case, I would only need the downcall handle. The unnecessary upcall handle depends on another method ("apply") that GraalVM has correctly identified to never be called and is thus omitted from the native image. As a result, the application crashes at run-time.
It wouldn't be such a problem if I was dealing with one or two function pointers. Then I would manually create the required FFM code with downcall handles only. However, I'm dealing with COM interfaces and the macOS IOKit version thereof:
*typedef* *struct* IOUSBInterfaceStruct942 {
IUNKNOWN_C_GUTS;
IOReturn (*CreateInterfaceAsyncEventSource)(*void* **self*, CFRunLoopSourceRef *source);
CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(*void* **self*);
IOReturn (*CreateInterfaceAsyncPort)(*void* **self*, mach_port_t *port);
mach_port_t (*GetInterfaceAsyncPort)(*void* **self*);
IOReturn (*USBInterfaceOpen)(*void* **self*);
IOReturn (*USBInterfaceClose)(*void* **self*);
IOReturn (*GetInterfaceClass)(*void* **self*, UInt8 *intfClass);
IOReturn (*GetInterfaceSubClass)(*void* **self*, UInt8 *intfSubClass);
IOReturn (*GetInterfaceProtocol)(*void* **self*, UInt8 *intfProtocol);
IOReturn (*GetDeviceVendor)(*void* **self*, UInt16 *devVendor);
...
These are structs that almost exclusively consist of function pointers. In the case of IOKit, the two main ones consist of 40 and 50 function pointers.
Am I correct that there is currently no way to suppress the generation of upcall method handles?
Are there any plans to to make the jextract generated code work well with GraalVM?
Regards Manuel
On 10/09/2025 14:12, Manuel Bleichenbacher wrote:
Hi Maurizio
The pull request solves something different. It simplifies invoking function pointers that are part of a struct. For COM interfaces and similar constructs, this is quite useful.
However, the code for the upcall and downcall handle hasn't changed. They are still static fields of an inner class. So they will always be instantiated as a pair.
But it might be useful to go one step further with this pull request and not emit the upcall (method handle, function interface, "apply" method) if the "functional" option is specified.
Apologies -- that is what I assumed the changes in the PR did. I believe it should be possible to at least enhance the PR that way and then try things out. @Nizar could you please look into this? I did something like this in our jextract/ONNX/Babylon experiment https://github.com/openjdk/babylon/blob/code-reflection/cr-examples/onnx/src... (as you can see there's no upcall handles there, as they were not needed).
Or even consider emitting code like my Windows API Generator does for COM interfaces (see https://github.com/manuelbl/WindowsApiGenerator/blob/main/docs/com_interface... <https://urldefense.com/v3/__https://github.com/manuelbl/WindowsApiGenerator/blob/main/docs/com_interfaces.md__;!!ACWV5N9M2RV99hQ!IvvUYfukc401IJY8ml05l3Br5O2zP9NNaFN0JHeYgLetR8-G3vGu2SasWYB1phslKRoYTjaelHHiU5OcLIcPmfi7f8dQsqzrow$>). It doesn't create an interface for each function pointer, but a single one for the entire struct, separate implementation classes for downcalls (calling a COM interface) and upcalls (implementing COM interfaces).
I _think_ I did something like this in our jextract/ONNX/Babylon experiment https://github.com/openjdk/babylon/blob/code-reflection/cr-examples/onnx/src... (as you can see there's no interfaces and no upcall handles there, as they were not needed). Is that similar to what you had in mind? Maurizio
By the way: the current pull request has a further problem. I generates code that doesn't compile. Depending on the arguments of the function pointer, the setter and the invoker method have the same arguments and clash.
Regards Manuel
Am Mi., 10. Sept. 2025 um 14:25 Uhr schrieb Maurizio Cimadamore <maurizio.cimadamore@oracle.com>:
Seems related to this?
https://git.openjdk.org/jextract/pull/287
It would be very helpful if you could try the option in that PR (you would need to build jextract manually) and see if that improves the situation.
Cheers Maurizio
On 10/09/2025 12:46, Manuel Bleichenbacher wrote:
Hi jextract team
I've been playing with the upcoming GraalVM 25 and its support for FFM. But I've run into an issue with code generated by jextract related to function pointers: it always instantiates both the downcall and upcall method handles, independent of which one is actually used. In my case, I would only need the downcall handle. The unnecessary upcall handle depends on another method ("apply") that GraalVM has correctly identified to never be called and is thus omitted from the native image. As a result, the application crashes at run-time.
It wouldn't be such a problem if I was dealing with one or two function pointers. Then I would manually create the required FFM code with downcall handles only. However, I'm dealing with COM interfaces and the macOS IOKit version thereof:
*typedef**struct*IOUSBInterfaceStruct942{
IUNKNOWN_C_GUTS;
IOReturn (*CreateInterfaceAsyncEventSource)(*void* **self*, CFRunLoopSourceRef *source);
CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(*void* **self*);
IOReturn (*CreateInterfaceAsyncPort)(*void* **self*, mach_port_t *port);
mach_port_t (*GetInterfaceAsyncPort)(*void* **self*);
IOReturn (*USBInterfaceOpen)(*void* **self*);
IOReturn (*USBInterfaceClose)(*void* **self*);
IOReturn (*GetInterfaceClass)(*void* **self*, UInt8 *intfClass);
IOReturn (*GetInterfaceSubClass)(*void* **self*, UInt8 *intfSubClass);
IOReturn (*GetInterfaceProtocol)(*void* **self*, UInt8 *intfProtocol);
IOReturn (*GetDeviceVendor)(*void* **self*, UInt16 *devVendor);
...
These are structs that almost exclusively consist of function pointers. In the case of IOKit, the two main ones consist of 40 and 50 function pointers.
Am I correct that there is currently no way to suppress the generation of upcall method handles?
Are there any plans to to make the jextract generated code work well with GraalVM?
Regards Manuel
Hi Maurizio Yes, your experiment code is exactly what would be needed. It has the simple static invoker method (as proposed by the pull requests) and it does not generate code for getter, setter and upcalls. It's probably all that is needed for the "functional struct" use case. Regards Manuel Am Mi., 10. Sept. 2025 um 17:50 Uhr schrieb Maurizio Cimadamore < maurizio.cimadamore@oracle.com>:
On 10/09/2025 14:12, Manuel Bleichenbacher wrote:
Hi Maurizio
The pull request solves something different. It simplifies invoking function pointers that are part of a struct. For COM interfaces and similar constructs, this is quite useful.
However, the code for the upcall and downcall handle hasn't changed. They are still static fields of an inner class. So they will always be instantiated as a pair.
But it might be useful to go one step further with this pull request and not emit the upcall (method handle, function interface, "apply" method) if the "functional" option is specified.
Apologies -- that is what I assumed the changes in the PR did. I believe it should be possible to at least enhance the PR that way and then try things out. @Nizar could you please look into this?
I did something like this in our jextract/ONNX/Babylon experiment
https://github.com/openjdk/babylon/blob/code-reflection/cr-examples/onnx/src...
(as you can see there's no upcall handles there, as they were not needed).
Or even consider emitting code like my Windows API Generator does for COM interfaces (see https://github.com/manuelbl/WindowsApiGenerator/blob/main/docs/com_interface... <https://urldefense.com/v3/__https://github.com/manuelbl/WindowsApiGenerator/blob/main/docs/com_interfaces.md__;!!ACWV5N9M2RV99hQ!IvvUYfukc401IJY8ml05l3Br5O2zP9NNaFN0JHeYgLetR8-G3vGu2SasWYB1phslKRoYTjaelHHiU5OcLIcPmfi7f8dQsqzrow$>). It doesn't create an interface for each function pointer, but a single one for the entire struct, separate implementation classes for downcalls (calling a COM interface) and upcalls (implementing COM interfaces).
I _think_ I did something like this in our jextract/ONNX/Babylon experiment
https://github.com/openjdk/babylon/blob/code-reflection/cr-examples/onnx/src...
(as you can see there's no interfaces and no upcall handles there, as they were not needed).
Is that similar to what you had in mind?
Maurizio
By the way: the current pull request has a further problem. I generates code that doesn't compile. Depending on the arguments of the function pointer, the setter and the invoker method have the same arguments and clash.
Regards Manuel
Am Mi., 10. Sept. 2025 um 14:25 Uhr schrieb Maurizio Cimadamore < maurizio.cimadamore@oracle.com>:
Seems related to this?
https://git.openjdk.org/jextract/pull/287
It would be very helpful if you could try the option in that PR (you would need to build jextract manually) and see if that improves the situation.
Cheers Maurizio On 10/09/2025 12:46, Manuel Bleichenbacher wrote:
Hi jextract team
I've been playing with the upcoming GraalVM 25 and its support for FFM. But I've run into an issue with code generated by jextract related to function pointers: it always instantiates both the downcall and upcall method handles, independent of which one is actually used. In my case, I would only need the downcall handle. The unnecessary upcall handle depends on another method ("apply") that GraalVM has correctly identified to never be called and is thus omitted from the native image. As a result, the application crashes at run-time.
It wouldn't be such a problem if I was dealing with one or two function pointers. Then I would manually create the required FFM code with downcall handles only. However, I'm dealing with COM interfaces and the macOS IOKit version thereof:
*typedef* *struct* IOUSBInterfaceStruct942 {
IUNKNOWN_C_GUTS;
IOReturn (*CreateInterfaceAsyncEventSource)(*void* **self*, CFRunLoopSourceRef *source);
CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(*void* **self*);
IOReturn (*CreateInterfaceAsyncPort)(*void* **self*, mach_port_t *port);
mach_port_t (*GetInterfaceAsyncPort)(*void* **self*);
IOReturn (*USBInterfaceOpen)(*void* **self*);
IOReturn (*USBInterfaceClose)(*void* **self*);
IOReturn (*GetInterfaceClass)(*void* **self*, UInt8 *intfClass);
IOReturn (*GetInterfaceSubClass)(*void* **self*, UInt8 *intfSubClass);
IOReturn (*GetInterfaceProtocol)(*void* **self*, UInt8 *intfProtocol);
IOReturn (*GetDeviceVendor)(*void* **self*, UInt16 *devVendor);
...
These are structs that almost exclusively consist of function pointers. In the case of IOKit, the two main ones consist of 40 and 50 function pointers.
Am I correct that there is currently no way to suppress the generation of upcall method handles?
Are there any plans to to make the jextract generated code work well with GraalVM?
Regards Manuel
participants (2)
-
Manuel Bleichenbacher
-
Maurizio Cimadamore