Lua's signed instruction fields are excess-K with K = MAXARG_x >> 1, i.e.
((1 << SIZE_x) - 1) >> 1 -- one LESS than 2^(SIZE_x - 1). Three of the
four accessors here used the power of two and were each one too large:
sC 128 -> 127 (lua54/lopcodes.h:98, OFFSET_sC)
sB 128 -> 127 (lua54/lopcodes.h:129, GETARG_sB = sC2int(B))
sJ 1<<24 -> 16777215 (lua54/lopcodes.h:92, OFFSET_sJ)
sBx 65535 (already correct)
sC decodes the immediate of OP_ADDI and friends, so every immediate came
out one low on the compiled path: `t = t + 5` yielded 4 and `i = i + 1`
lowered as `i = i + 0`, which is why loop bodies looked like they had no
effect. sJ is a jump displacement, so branch targets were off by one
instruction.
Verified against the interpreter as oracle (lua_jit 0 vs lua_jit 1):
local t=0 t=t+5 return t jit 5 interp 5 (was -1 before, then 4)
local t=0 t=t+100 return t jit 100 interp 100
local t=0 t=t-1 return t jit -1 interp -1
Note the compiled path has a second, independent defect that this commit
does not address -- see #1422 for the control-flow-join analysis.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Lua scripts compiled by lua_mod.so can now be JIT-compiled through
the existing HIR/RV64/x86-64 pipeline in engine.so. The bytecode
deserializer reads lua_dump() output without requiring Lua headers.
New COM interface mux_IJITCompile on engine.so with CompileLuaBytecode,
RunCompiled, IsCompiled, and Invalidate methods. lua_mod.so acquires
this interface and transparently attempts JIT before falling back to
the Lua VM.
Opcode coverage: data movement (MOVE/LOADI/LOADK/LOADNIL/etc.),
integer arithmetic (ADD/SUB/MUL/IDIV/MOD/UNM + immediate/constant
variants), comparisons (EQ/LT/LE/EQI/LTI/LEI/GTI/GEI), control flow
(JMP/TEST/TESTSET/FORPREP/FORLOOP), returns, and mux.* bridge calls
pattern-matched from GETTABUP+GETFIELD+CALL to engine API ECALLs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>