vars: add per-var generation counter, bumped on root change
Foundation for the linking-mode work (jolt-5ed). Every var cell carries a :gen that bumps on bind-root / var-set(root) / alter-var-root — i.e. on redefinition. Behavior-neutral on its own; it's the substrate the upcoming work needs: direct-linked (sealed) call sites can detect staleness, and redefinition-aware dispatch caches can invalidate per-var (only a redefined var's callers miss, not a global flush). Full suite green, conformance 218/218 in all three modes.
This commit is contained in:
parent
28ef15ea4b
commit
a2805c4f51
2 changed files with 29 additions and 4 deletions
|
|
@ -86,6 +86,10 @@
|
|||
:name name
|
||||
:root init-val
|
||||
:meta m
|
||||
# Generation: bumped on every root change (redefinition). Call
|
||||
# sites / dispatch caches keyed on this can detect a redef and
|
||||
# invalidate; direct-linked (sealed) sites can detect staleness.
|
||||
:gen 0
|
||||
:dynamic (if meta (get meta :dynamic) false)
|
||||
:macro (if meta (get meta :macro) false)
|
||||
:ns (if meta (get meta :ns) nil)}]
|
||||
|
|
@ -152,14 +156,16 @@
|
|||
(if (not (nil? (get frame v)))
|
||||
(do (put bs i (merge frame {v val})) (set done true))
|
||||
(-- i))))
|
||||
(unless done (put v :root val))
|
||||
(unless done (do (put v :root val) (put v :gen (+ 1 (or (v :gen) 0)))))
|
||||
val)
|
||||
|
||||
(defn alter-var-root
|
||||
"Atomically alter the root binding of v by applying f to current value plus args."
|
||||
[v f & args]
|
||||
(let [new-val (f (v :root) ;args)]
|
||||
(put v :root new-val)))
|
||||
(put v :root new-val)
|
||||
(put v :gen (+ 1 (or (v :gen) 0)))
|
||||
new-val))
|
||||
|
||||
(defn alter-meta!
|
||||
"Atomically update a var's metadata via (apply f args)."
|
||||
|
|
@ -244,14 +250,18 @@
|
|||
:name (v :name)
|
||||
:root (v :root)
|
||||
:meta new-meta
|
||||
:gen (or (v :gen) 0)
|
||||
:dynamic (v :dynamic)
|
||||
:macro (v :macro)
|
||||
:ns (v :ns)}))
|
||||
|
||||
(defn bind-root
|
||||
"Set the root binding (internal, same as var-set)."
|
||||
"Set the root binding and bump the var's generation (the redefinition
|
||||
chokepoint: def, ns-intern-with-val, and the root-set paths all route here)."
|
||||
[v val]
|
||||
(put v :root val))
|
||||
(put v :root val)
|
||||
(put v :gen (+ 1 (or (v :gen) 0)))
|
||||
val)
|
||||
|
||||
# ============================================================
|
||||
# Namespace
|
||||
|
|
|
|||
|
|
@ -40,6 +40,21 @@
|
|||
(assert (deep= {:name 'x :private true} (var-meta v2)) "with-meta merges meta")
|
||||
(assert (= 42 (var-get v2)) "with-meta preserves root binding"))
|
||||
|
||||
# generation counter — bumps on every root change (substrate for direct-link
|
||||
# staleness detection and redefinition-aware dispatch caches)
|
||||
(let [v (make-var 'g 1)]
|
||||
(assert (= 0 (v :gen)) "fresh var starts at generation 0")
|
||||
(bind-root v 2)
|
||||
(assert (= 1 (v :gen)) "bind-root bumps generation")
|
||||
(var-set v 3)
|
||||
(assert (= 2 (v :gen)) "var-set (root) bumps generation")
|
||||
(alter-var-root v inc)
|
||||
(assert (= 3 (v :gen)) "alter-var-root bumps generation")
|
||||
(assert (= 4 (var-get v)) "value still tracks through gen bumps"))
|
||||
(let [v (make-var 'g 1)
|
||||
v2 (with-meta v {:doc "x"})]
|
||||
(assert (= (v :gen) (v2 :gen)) "with-meta carries generation"))
|
||||
|
||||
# var with namespace
|
||||
(let [ns (make-ns 'my.ns)
|
||||
v (make-var 'my.ns/x 1 {:ns ns})]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue