Superinstructions and a second, smaller interpreter loop
The interpreter runs common instruction pairs as one dispatch, pushes and pops the common frame inline, and runs simple functions and loops in a small second loop that keeps its state in registers.
The first attempt was reverted the same day. Dropping a discarded assignment's result copy whenever the JIT was off (330a9118) made a metered program charge different steps with the JIT off than with it on, and the CI-full test that pins that parity failed (98b4d769). A JIT-capable build compiles the same bytecode in both modes again, and interpreter-only rewrites now go into a copy of each function's code instead. That copy is b2b8f5ca's: adjacent pairs such as a loop bound's load and compare-branch, x + 1, or a counter step and its back-edge run as one superinstruction, while the original instructions stay in place for jumps, inline caches, the JIT and every recorder. 1b04c9bb pushes and pops the common frame inline, and af87a2c7 moved the choice of the copy past the native tiers, which had cost a JIT row about 7%.
702ad388 adds vm/lite.rs, a second interpreter loop small enough to keep its state in registers, for functions made only of loads, adds, compare-branches, calls and returns; it works on the real frames, so handing an instruction back to the main loop is free. 11c60356 then stopped re-checking the register file's live prefix on every read and write, a check the PC profile showed before each register write of fib. Later commits let the lite loop run loops with cached property and element access (d0a110be) and closures and Math methods (4c16fc70), and compiled it twice so a small copy keeps recursive integer functions fast (a2e02db3). In the commits' profile-guided measurements against Bellard's QuickJS 2026-06-04, the 18-row interpreter geomean went from 0.681× to 0.630× with the superinstructions and inline frames, and to 0.576× after the register-file change, faster on 16 of 18 rows; the expansion suite's entry explains why the held-out recipe's numbers are the ones to quote. Module namespaces also moved from SipHash to FxHash (16034c8c; module-hot-graph in 0.78× its previous time, interpreted).