Chez Phase 2 (inc M): dynamic var binding (jolt-2o7x)

Add the dynamic-binding cluster on the Chez RT: a per-thread binding stack
(host/chez/dyn-binding.ss) backing binding / with-bindings* / var-set /
thread-bound? / with-local-vars / with-redefs / bound-fn* /
get-thread-bindings / alter-var-root + the __local-var seam.

Frames are stored innermost-first as identity-keyed alists of mutable
(cell . value) pairs, so var-set updates the current binding in place. The
two var-read paths — var-deref (compiled code) and jolt-var-get (var-get /
deref on a cell) — are chained onto the stack so a `binding` frame is seen
by every read, with a fast path when the stack is empty. var-cells now hash
by ns/name so a var works as a map key (with-redefs builds (hash-map (var f)
v); get-thread-bindings returns a var-keyed map).

Fix a latent bug exposed once with-in-str could bind *in*: seq? didn't
recognize a lazy-seq. predicates.ss's jolt-seq? predates the lazyseq record,
and unlike the native-op dispatchers it's reached via var-deref, so the
patch must re-def-var! the var, not just set! the top-level binding.

Note: with-bindings* over a hash-map literal now returns the correct Clojure
value where the seed returns a stale one — the seed's PHM can't find a var
key (which is why its `binding` uses array-map); on Chez frames look up by
cell identity.

Prelude corpus parity 1972 -> 2000, floor raised. Gate: _dynbind 24/24,
prelude corpus 0 divergences, full jpm test, conformance 355x3.
This commit is contained in:
Yogthos 2026-06-18 18:29:55 -04:00
parent 737288bff5
commit fc6551f877
5 changed files with 238 additions and 1 deletions

View file

@ -188,8 +188,13 @@
# jolt-zikh (var def-time metadata — :def emit passes reader meta to
# def-var-with-meta!; (meta (var v)) is {:ns :name} + ^:private/^Type tag/
# docstring) 1972.
# jolt-2o7x (dynamic var binding — the per-thread binding stack +
# binding/with-bindings*/var-set/thread-bound?/with-local-vars/with-redefs/
# bound-fn*/get-thread-bindings/alter-var-root; var-deref + jolt-var-get chained
# onto the stack. Also fixed seq? to recognize a lazy-seq, which unblocked
# with-in-str/line-seq) 2000.
# Strided runs scale down.
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_PRELUDE_FLOOR") "1972")))
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_PRELUDE_FLOOR") "2000")))
(def floor (if (os/getenv "JOLT_CORPUS_LIMIT") 0 base-floor))
(when (or (> (length diverged) 0) (< pass floor))
(printf "REGRESSION: pass %d < floor %d or %d new divergence(s)" pass floor (length diverged)))