RFR: 7903437: Improve translation strategy for function pointers

Maurizio Cimadamore mcimadamore at openjdk.org
Fri Feb 17 15:55:20 UTC 2023


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.

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

Commit messages:
 - Remove redundant import
 - Initial push

Changes: https://git.openjdk.org/jextract/pull/109/files
 Webrev: https://webrevs.openjdk.org/?repo=jextract&pr=109&range=00
  Issue: https://bugs.openjdk.org/browse/CODETOOLS-7903437
  Stats: 41 lines in 4 files changed: 28 ins; 2 del; 11 mod
  Patch: https://git.openjdk.org/jextract/pull/109.diff
  Fetch: git fetch https://git.openjdk.org/jextract pull/109/head:pull/109

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


More information about the jextract-dev mailing list