Both native machines (JffiNativeMachine and the Panama NativeMachine) compile their ABI trampolines in the constructor, i.e. once per instance:
try (var bridge = new CraneliftBridge()) { // Instance.builder(Cranelift.load())...build()
bridge.init(RedlineTarget.detectHost()...triple());
var trampolines = bridge.compileTrampolines(compiledCode, funcTypesByBody, importTypes, importStubAddrs, ...);
CraneliftBridge() instantiates the Cranelift compiler (the 2.5 MB cranelift_bridge.wasm, on the bytecode compiler) every time. The build-time output (NativeCodeSerializer) only contains the function bodies, no trampolines. Measured with quickjs4j (Endive 1.1.0, javy module): 0.8–2.9 s and ~+26 MB RSS per Instance, versus ~0.1 s for the build-time compiled bytecode. Anything that creates instances regularly (camel-quickjs recycles an engine every few thousand evaluations) is dominated by this.
Expected design: everything is precomputed at build time. The runners only load and link, and redline-bridge-experimental (the Cranelift compiler) must not be a runtime dependency of redline-runner-experimental / redline-runner-jffi-experimental at all; today both declare it in compile scope.
Concretely:
- the build-time compiler emits the entry trampolines, import trampolines, internal stub trampolines and memmove/memset trampolines next to the function bodies (one set per target), in the
.native payload;
- the per-instance addresses they embed today (import closure stubs, watchdog/memgrow stubs, memmove/memset) are either read indirectly from the ctx buffer / function table, so the trampolines are position-independent, or patched at load time through a small relocation table in the payload;
- the runners drop the dependency on the bridge; the bridge stays a build-time-only artifact.
🤖 Generated with Claude Code
Both native machines (
JffiNativeMachineand the PanamaNativeMachine) compile their ABI trampolines in the constructor, i.e. once per instance:CraneliftBridge()instantiates the Cranelift compiler (the 2.5 MBcranelift_bridge.wasm, on the bytecode compiler) every time. The build-time output (NativeCodeSerializer) only contains the function bodies, no trampolines. Measured with quickjs4j (Endive 1.1.0, javy module): 0.8–2.9 s and ~+26 MB RSS perInstance, versus ~0.1 s for the build-time compiled bytecode. Anything that creates instances regularly (camel-quickjs recycles an engine every few thousand evaluations) is dominated by this.Expected design: everything is precomputed at build time. The runners only load and link, and
redline-bridge-experimental(the Cranelift compiler) must not be a runtime dependency ofredline-runner-experimental/redline-runner-jffi-experimentalat all; today both declare it incompilescope.Concretely:
.nativepayload;🤖 Generated with Claude Code