From 3049ff92e4cd04033e9e8a24e634b4edd88fbf7e Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 28 Jun 2026 16:32:17 +0000 Subject: [PATCH] vm-ext: document CL call/cc-caller exclusion in plan Co-Authored-By: Claude Opus 4.8 (1M context) --- plans/jit-bytecode-correctness.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/plans/jit-bytecode-correctness.md b/plans/jit-bytecode-correctness.md index a6298074..8d90c690 100644 --- a/plans/jit-bytecode-correctness.md +++ b/plans/jit-bytecode-correctness.md @@ -203,3 +203,34 @@ general fix is propagate-don't-rerun (run_tests' hook semantics) but that surfaces genuine mid-run miscompiles as errors and must land with fixing/ excluding those — deferred (shared CEK/VM change). The default-OFF gate makes all of this opt-in, so nothing regresses by default. + +--- + +## common-lisp residual resolved — call/cc-caller exclusion (2026-06-28) + +Investigated the 6 CL opt-in-JIT failures. Findings: +- **geometry / mop-trace (0/0) are NOT JIT regressions** — they error "Undefined + symbol: refl-class-chain-depth-with" on BOTH CEK and JIT (the CLOS suites in + conformance.sh don't preload lib/guest/reflective/class-chain.sx). Pre-existing + harness gap; not counted in the 6. +- The **6 real failures** (parse-recover 4, interactive-debugger 2) were all + condition-system continuation escape. cl-restart-case/cl-handler-case/ + cl-handler-bind wrap their body in call/cc. When an SX function driving the + condition system (parse-numbers, make-policy-debugger) is JIT-compiled, the + call/cc form runs in a NESTED cek-run where invoking the captured continuation + runs-to-completion-and-returns instead of escaping → restart fails to abort, + body falls through. Seen as accumulation ((1 3 0 3) vs (1 3)) and no-abort + (999 sentinel). Also produced a +3 double-execution over-count (490 vs 487). + +Fix: a third interpret-only signal beyond name/prefix and PUSH_HANDLER — +`jit-exclude-callers-of!` registers call/cc-establishing/invoking form names; +`jit_compile_lambda` skips any function whose constant pool (recursively) +references one (`code_refs_escaping_caller`). Guarded so it's a no-op for guests +that don't register. CL registers cl-restart-case/cl-handler-case/cl-handler-bind +(establish) + cl-invoke-restart/cl-invoke-debugger/cl-signal/cl-error-with-debugger +(invoke). Result: **CL under SX_SERVING_JIT=1 = 487/0, exactly matching CEK.** + +The three interpret-only signals now: (1) name / "ns-*" prefix [jit-exclude!], +(2) PUSH_HANDLER in bytecode [guard users, structural], (3) references a +registered escaping form [call/cc-establishing callers]. Together they cover the +continuation-unsafe surface without a deep VM continuation rewrite.