RFR: 7903437: Improve translation strategy for function pointers

Jorn Vernee jvernee at openjdk.org
Fri Feb 17 22:01:48 UTC 2023


On Fri, 17 Feb 2023 15:32:53 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:

> The current translation stragegy for function pointers is not very efficient. Every time a lambda expression is turned into an upcall stub, a new method handle lookup is performed, which is quite a slow operation.
> 
> This patch improves the translation strategy so that the lookup is only performed once. For instance, considering the following `typedef`:
> 
> 
> typedef void (*cb)(int, int);
> 
> 
> jextract will generate the following functional interface:
> 
> 
> import static java.lang.foreign.ValueLayout.*;
> /**
>  * {@snippet :
>  * void (*cb)(int,int);
>  * }
>  */
> public interface cb {
> 
>     void apply(int _x0, int _x1);
>     static MemorySegment allocate(cb fi, Arena scope) {
>         return RuntimeHelper.upcallStub(constants$0.cb_UP$MH, fi, constants$0.cb$FUNC, scope);
>     }
>     static cb ofAddress(MemorySegment addr, Arena arena) {
>         MemorySegment symbol = addr.reinterpret(arena.scope(), null);
>         return (int __x0, int __x1) -> {
>             try {
>                 constants$0.cb_DOWN$MH.invokeExact(symbol, __x0, __x1);
>             } catch (Throwable ex$) {
>                 throw new AssertionError("should not reach here", ex$);
>             }
>         };
>     }
> }
> 
> 
> Where the constants are defined as follows:
> 
> 
>     static final FunctionDescriptor cb$FUNC = FunctionDescriptor.ofVoid(
>         Constants$root.C_INT$LAYOUT,
>         Constants$root.C_INT$LAYOUT
>     );
>     
>     static final FunctionDescriptor cb_UP$FUNC = FunctionDescriptor.ofVoid(
>         Constants$root.C_INT$LAYOUT,
>         Constants$root.C_INT$LAYOUT
>     );
>     
>     static final MethodHandle cb_UP$MH = RuntimeHelper.upcallHandle(cb.class, "apply", constants$0.cb_UP$FUNC);
>     
>     static final FunctionDescriptor cb_DOWN$FUNC = FunctionDescriptor.ofVoid(
>         Constants$root.C_INT$LAYOUT,
>         Constants$root.C_INT$LAYOUT
>     );
>     
>     static final MethodHandle cb_DOWN$MH = RuntimeHelper.downcallHandle(
>         constants$0.cb_DOWN$FUNC
>     );
> 
> 
> And, where `RuntimeHelper::upcallHandler` is defined as follows:
> 
> 
> static MethodHandle upcallHandle(Class<?> fi, String name, FunctionDescriptor fdesc) {
>         try {
>             return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType());
>         } catch (Throwable ex) {
>             throw new AssertionError(ex);
>         }
>     }
> 
> 
> This allows to perform the method handle lookup only once. This means that when creating an upcall stub, we only have to `bind` the functional interface instance to the method handle, and then create an upcall stub with the resulting handle. Both operations should be fast after the first time, because of caching.

> > Should we generate the clang bindings with this new translation strategy as well?
> 
> Yes, but I think it would be better to do that separately, as that adds some noise (also because of other changes caused by the API update).

Good point.

-------------

Marked as reviewed by jvernee (no project role).

PR: https://git.openjdk.org/jextract/pull/109


More information about the jextract-dev mailing list