vm-ext: enable JIT in epoch serving mode (Smalltalk 847/847, Datalog 356/356)
register_jit_hook is now installed in the persistent (epoch) serving-mode branch of sx_server.ml, not just --http/cli/site. Smalltalk-on-SX conformance under JIT is 847/847 — identical to the no-JIT baseline; Datalog 356/356. run_tests --jit/no-jit are byte-identical before/after (no regression). Five distinct root causes fixed (not one "miscompile"): 1. Serving mode never loaded lib/compiler.sx, so JIT used the native Sx_compiler.compile stub (arity-0 bytecode, params as GLOBAL_GET → "VM undefined: <param>"). Server-mode branch now loads compiler.sx before registering the hook, matching http/cli/site. 2. compile-cond / compile-case-clauses / compile-guard-clauses only treated keyword :else and true as the catch-all, not the bare symbol `else` that the CEK's is-else-clause? accepts → GLOBAL_GET "else". (lib/compiler.sx) 3. OP_DIV produced a float for non-divisible Integer/Integer (1/2 → 0.5) instead of the exact Rational the "/" primitive returns. Now delegates to the primitive, matching CEK. (sx_vm.ml) 4. OP_EQ / _fast_eq lacked Rational/ListRef cases that the "=" primitive's safe_eq has → (= 1/2 1/2) false under JIT. OP_EQ now delegates non-scalars to the "=" primitive; _fast_eq gained rational + ListRef. (sx_vm.ml, sx_runtime.ml) 5. Continuation-based control flow (Smalltalk ^expr non-local return, block escape, exceptions via call/cc) can't run in the stack VM. New data-driven exclusion set Sx_types.jit_excluded + `jit-exclude!` primitive, consulted in jit_compile_lambda (covers both the CEK hook and vm_call's tiered path). lib/smalltalk/eval.sx self-declares its continuation dispatch core interpret-only; pure helpers still JIT. The SUnit suite-runner test helper pharo-test-class miscompiles mid-loop and is excluded in tests/tokenize.sx. Also adds SX_JIT_DENY / SX_JIT_ONLY env-var bisection filters to the serving hook. Known residual documented in plans/jit-bytecode-correctness.md: the hook re-runs a failed VM execution via CEK (correct result, possible duplicate side effects); adopting run_tests' propagate-don't-rerun semantics is deferred to avoid changing shared VM/CEK behavior under this loop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1475,3 +1475,22 @@
|
||||
(get ast :temps)))
|
||||
(smalltalk-eval-ast ast frame)))))))
|
||||
(begin (dict-set! cell :active false) result)))))
|
||||
|
||||
;; ── JIT interpret-only boundary ──────────────────────────────────────────
|
||||
;; The Smalltalk evaluator implements non-local return (^expr), block escape,
|
||||
;; and exception unwinding via first-class continuations (call/cc). A stack
|
||||
;; bytecode VM cannot transfer control through a CEK continuation, so any of
|
||||
;; these dispatch-core functions, if JIT-compiled, would be an un-escapable
|
||||
;; VM frame on the stack between a `call/cc` capture and its `(k v)` invocation
|
||||
;; — failing at runtime and (before this guard) re-running with duplicated
|
||||
;; side effects. Declaring them interpret-only keeps them on the CEK while the
|
||||
;; pure leaf helpers (parsing, ident/ivar lookup, formatting, predicates,
|
||||
;; arithmetic) still JIT. See Sx_types.jit_excluded / `jit-exclude!`.
|
||||
(jit-exclude!
|
||||
"smalltalk-eval" "smalltalk-eval-program" "smalltalk-load"
|
||||
"smalltalk-eval-ast" "st-eval-seq" "st-eval-send" "st-eval-send-dispatch"
|
||||
"st-eval-cascade" "st-try-intrinsify" "st-send" "st-invoke" "st-dnu"
|
||||
"st-super-send" "st-primitive-send" "st-num-send" "st-bool-send"
|
||||
"st-string-send" "st-array-send" "st-nil-send" "st-class-side-send"
|
||||
"st-block-apply" "st-block-dispatch" "st-block-while" "st-block-ensure"
|
||||
"st-block-if-curtailed" "st-block-on-do" "st-block-value-selector?")
|
||||
|
||||
Reference in New Issue
Block a user