c: vm restores cur_code across CALL/RETURN, fixing JIT named-let hang
Five-line fix that ends the F1 hang in foxhop.net ecdsa/tests/unit/probe-c-confirm.lsp. Symptom — under --fast, a defined function whose body is a tail-recursive named-let that calls another user-defined function per iteration loops forever at 100 percent CPU. Trace pins the bytecode dispatch: walk1.body: PUSHE MKCLO DUP BIND LOOKUP TCALL ->loop loop: LOOKUP NULL? JIF LOOKUP CALL ->always-true always-true: CONST RET (returns #t) always-true (!): JIF LOOKUP CDR STAIL -> ip=0 of always-true (!) loop forever cur_code was the call-frame-local register holding the currently executing CodeObj. OP_CALL updated it on entry but neither OP_RETURN nor the builtin-fallback restore path in OP_TAIL_CALL put it back on return. Subsequent OP_SELF_TAIL_CALL read cur_code->self_params from the still-stale callee proc (NULL for always-true since it has no named-let), guard skipped the env rebind, then set ip=0 — without ever updating the loop variable. Loop variable stayed pinned at the initial list and our walk never reached its base case. Fix — VMFrame gains a cur_code field. Three frame-push sites save it on entry (OP_CALL, OP_TAIL_CALL builtin fallback frame-restore, OP_CALL_CC compiled-proc entry); two frame-pop sites restore it on return (OP_RETURN, OP_TAIL_CALL builtin fallback). Verified inside foxhop.net's ecdsa QEMU guest: - foxhop.net/ecdsa/tests/unit/probe-c-confirm.lsp F1..F4 — all pass - foxhop.net/ecdsa/tests/unit/test-sim.lsp under --fast — 21/21 pass - foxhop.net/ecdsa/lumbda/main.lsp under --fast — 6 shots, score 18, byte-identical with our Python tier - make functional-test — 205/205 on Python and C tiers - make regression-named-let-leak — 4/4 across Python, tree-walker, and --fast JIT c/TODO-named-let-bytecode.md can stop applying its `(define (iter ...))` workaround once this lands.
This commit is contained in:
parent
88c4b05032
commit
45a90b84e9
2 changed files with 5 additions and 0 deletions
|
|
@ -478,6 +478,7 @@ typedef struct VMFrame {
|
|||
Value *stack;
|
||||
int stack_len;
|
||||
int stack_cap;
|
||||
CodeObj *cur_code; /* saved so RET restores it — needed for SELF_TAIL_CALL after a nested call */
|
||||
} VMFrame;
|
||||
|
||||
typedef struct FullCont {
|
||||
|
|
|
|||
4
c/vm.c
4
c/vm.c
|
|
@ -798,6 +798,7 @@ Value vm_exec(CodeObj *code, Env *env) {
|
|||
f->instrs = instrs; f->ip = ip; f->n_instrs = n_instrs;
|
||||
f->env = env;
|
||||
f->stack = stack.data; f->stack_len = stack.len; f->stack_cap = stack.cap;
|
||||
f->cur_code = cur_code;
|
||||
|
||||
env = env_child(cp->env, cp->params, cp->nparams, cp->rest, args_arr, nargs);
|
||||
cur_code = cp->code;
|
||||
|
|
@ -848,6 +849,7 @@ Value vm_exec(CodeObj *code, Env *env) {
|
|||
env = f->env;
|
||||
ul_free(stack.data);
|
||||
stack.data = f->stack; stack.len = f->stack_len; stack.cap = f->stack_cap;
|
||||
cur_code = f->cur_code;
|
||||
vs_push(&stack, ret);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -862,6 +864,7 @@ Value vm_exec(CodeObj *code, Env *env) {
|
|||
env = f->env;
|
||||
ul_free(stack.data);
|
||||
stack.data = f->stack; stack.len = f->stack_len; stack.cap = f->stack_cap;
|
||||
cur_code = f->cur_code;
|
||||
vs_push(&stack, ret);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -915,6 +918,7 @@ Value vm_exec(CodeObj *code, Env *env) {
|
|||
f->instrs = instrs; f->ip = ip; f->n_instrs = n_instrs;
|
||||
f->env = env;
|
||||
f->stack = stack.data; f->stack_len = stack.len; f->stack_cap = stack.cap;
|
||||
f->cur_code = cur_code;
|
||||
Value kargs[1] = {cont_val};
|
||||
env = env_child(cp->env, cp->params, cp->nparams, cp->rest, kargs, 1);
|
||||
cur_code = cp->code;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue