sx: step 1 — fix JIT call_closure_reuse for closure returns
In `call_closure_reuse`, the success path used a bare `pop vm` that relied on OP_RETURN having left the stack at exactly `saved_sp + 1`. When the callee returns a closure (or hits the bytecode-exhausted fallback path), `vm.sp` can end up inconsistent with the parent frame's expected layout, corrupting intermediate values such as parser combinator state in `parse-bind`/`many`/ `seq`. Fix: read the result at the expected slot, then explicitly reset `vm.sp <- saved_sp` before returning so the parent frame sees a clean stack regardless of what the callee left behind. OCaml run_tests baseline: 4525/5864 unchanged. WASM kernel tests: 24/29 unchanged. No regressions.
This commit is contained in:
@@ -327,7 +327,18 @@ and call_closure_reuse cl args =
|
||||
vm.sp <- saved_sp;
|
||||
raise e);
|
||||
vm.frames <- saved_frames;
|
||||
pop vm
|
||||
(* Snapshot/restore sp around the popped result.
|
||||
OP_RETURN normally leaves sp = saved_sp + 1, but the bytecode-exhausted
|
||||
path (or a callee that returns a closure whose own RETURN leaves extra
|
||||
stack residue) can leave sp inconsistent. Read the result at the
|
||||
expected slot and reset sp explicitly so the parent frame's
|
||||
intermediate values are not corrupted. *)
|
||||
let result =
|
||||
if vm.sp > saved_sp then vm.stack.(vm.sp - 1)
|
||||
else Nil
|
||||
in
|
||||
vm.sp <- saved_sp;
|
||||
result
|
||||
| None ->
|
||||
call_closure cl args cl.vm_env_ref
|
||||
|
||||
|
||||
Reference in New Issue
Block a user