diff --git a/hosts/ocaml/lib/sx_vm.ml b/hosts/ocaml/lib/sx_vm.ml index bf29e066..4bfb456a 100644 --- a/hosts/ocaml/lib/sx_vm.ml +++ b/hosts/ocaml/lib/sx_vm.ml @@ -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 diff --git a/plans/sx-improvements.md b/plans/sx-improvements.md index e8de5c9a..dfa73688 100644 --- a/plans/sx-improvements.md +++ b/plans/sx-improvements.md @@ -181,7 +181,7 @@ these when operands are known numbers/lists. | Step | Status | Commit | |------|--------|--------| -| 1 — JIT combinator bug | [ ] | — | +| 1 — JIT combinator bug | [x] | 6297a380 | | 2 — letrec+resume | [ ] | — | | 3 — tokenizer :end/:line | [ ] | — | | 4 — parser spans complete | [ ] | — |