vm-ext: fix common-lisp condition-system JIT residual (call/cc-caller exclusion)
The 6 common-lisp opt-in-JIT failures were all condition-system continuation escape: cl-restart-case/cl-handler-case/cl-handler-bind wrap their body in call/cc (restarts + non-local handler exit). When an SX function that drives the condition system (the parse-recover / interactive-debugger fixtures, e.g. 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 — so a restart fails to abort and the body falls through. Observed as result accumulation (got (1 3 0 3) vs (1 3)) and no-abort (restart returns the 999 sentinel). These callers are arbitrary user/fixture code, not a fixed namespace, so they can't be prefix-excluded. New data-driven mechanism: - jit-exclude-callers-of! registers call/cc-establishing form names in Sx_types.jit_excluded_caller_names. - jit_compile_lambda skips any function whose constant pool (recursively, incl. nested closures) references a registered name — code_refs_escaping_caller. Guarded by Hashtbl.length > 0 so it's a no-op for every guest that doesn't register (zero effect outside CL). - lib/common-lisp/runtime.sx registers the establish side (cl-restart-case, cl-handler-case, cl-handler-bind) and the invoke side (cl-invoke-restart, cl-invoke-debugger, cl-signal, cl-error-with-debugger). Result: CL conformance under SX_SERVING_JIT=1 = 487/0, EXACTLY matching the CEK baseline (was 484/6 with a +3 double-execution over-count). parse-recover 3/4 -> 6/0, interactive-debugger 7/2 -> 7/0. Note: the geometry/mop-trace suites report 0/0 on BOTH CEK and JIT — they error "Undefined symbol: refl-class-chain-depth-with" (the CLOS suites don't preload lib/guest/reflective/class-chain.sx). Pre-existing conformance-harness gap, not a JIT issue; left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -764,3 +764,17 @@
|
||||
;; a compiled frame can't transfer control through a CEK continuation. Exclude
|
||||
;; the cl-/clos- namespaces from JIT. See Sx_types.jit_excluded_prefixes.
|
||||
(jit-exclude! "cl-*" "clos-*")
|
||||
|
||||
;; cl-restart-case / cl-handler-case / cl-handler-bind wrap their body in
|
||||
;; call/cc (restarts + non-local handler exit). Any function that CALLS one of
|
||||
;; these (e.g. SX fixtures driving the condition system: parse-recover,
|
||||
;; interactive-debugger) must also be interpret-only: JIT'ing such a caller
|
||||
;; forces the call/cc form into a nested cek-run where the captured
|
||||
;; continuation runs-to-completion-and-returns instead of escaping, so a
|
||||
;; restart fails to abort and the body falls through (accumulation/no-abort).
|
||||
(jit-exclude-callers-of! "cl-restart-case" "cl-handler-case" "cl-handler-bind")
|
||||
;; Also the INVOKE side: cl-invoke-restart / cl-invoke-debugger / cl-signal
|
||||
;; trigger the continuation escape; a JIT'd caller can't let the escape
|
||||
;; propagate out of its frame (e.g. make-policy-debugger building a debugger
|
||||
;; hook that invokes a restart). Mark their callers interpret-only too.
|
||||
(jit-exclude-callers-of! "cl-invoke-restart" "cl-invoke-debugger" "cl-signal" "cl-error-with-debugger")
|
||||
|
||||
Reference in New Issue
Block a user