3 ms·
My understanding comes from Erlang’s HiPE optimizer (which was AoT rather than a JIT), but I think you’ve nailed it. Most JITs can’t optimize across a native↔in
by derefr 5y ago
My understanding comes from Erlang’s HiPE optimizer (which was AoT rather than a JIT), but I think you’ve nailed it. Most JITs can’t optimize across a native↔interpreted boundary, any more than compilers can optimize across a dynamic-linkage (dlopen(2)) boundary. When all the code is interpreted, you get something that’s a lot more WPO-like.
IIRC, some very clever JITs do a waltz here:
1. replace the user’s “syscall” into the runtime, with emitted bytecode;
2. WPO the user’s bytecode together with the generated bytecode;
3. Find any pattern that still resembles the post-optimization form of part of the bytecode equivalent of the call into the runtime, and replace it back with a “syscall” to the runtime, for doing that partial step.
Maybe clearer with an example. Imagine there’s a platform-native function sha256(byte[]). The JIT would:
1. Replace the call to sha256(byte[]) with a bytecode loop over the buffer, plus a bunch of logic to actually do a sha256 to a fixed-size register;
2. WPO the code with that bytecode loop embedded;
3. Replace the core of the remnants of the sha256-to-a-fixed-size-register code, with a call to a platform-native sha256(register) function.