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