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
|
:name name
|
||||||
:root init-val
|
:root init-val
|
||||||
:meta m
|
: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)
|
:dynamic (if meta (get meta :dynamic) false)
|
||||||
:macro (if meta (get meta :macro) false)
|
:macro (if meta (get meta :macro) false)
|
||||||
:ns (if meta (get meta :ns) nil)}]
|
:ns (if meta (get meta :ns) nil)}]
|
||||||
|
|
@ -152,14 +156,16 @@
|
||||||
(if (not (nil? (get frame v)))
|
(if (not (nil? (get frame v)))
|
||||||
(do (put bs i (merge frame {v val})) (set done true))
|
(do (put bs i (merge frame {v val})) (set done true))
|
||||||
(-- i))))
|
(-- i))))
|
||||||
(unless done (put v :root val))
|
(unless done (do (put v :root val) (put v :gen (+ 1 (or (v :gen) 0)))))
|
||||||
val)
|
val)
|
||||||
|
|
||||||
(defn alter-var-root
|
(defn alter-var-root
|
||||||
"Atomically alter the root binding of v by applying f to current value plus args."
|
"Atomically alter the root binding of v by applying f to current value plus args."
|
||||||
[v f & args]
|
[v f & args]
|
||||||
(let [new-val (f (v :root) ;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!
|
(defn alter-meta!
|
||||||
"Atomically update a var's metadata via (apply f args)."
|
"Atomically update a var's metadata via (apply f args)."
|
||||||
|
|
@ -244,14 +250,18 @@
|
||||||
:name (v :name)
|
:name (v :name)
|
||||||
:root (v :root)
|
:root (v :root)
|
||||||
:meta new-meta
|
:meta new-meta
|
||||||
|
:gen (or (v :gen) 0)
|
||||||
:dynamic (v :dynamic)
|
:dynamic (v :dynamic)
|
||||||
:macro (v :macro)
|
:macro (v :macro)
|
||||||
:ns (v :ns)}))
|
:ns (v :ns)}))
|
||||||
|
|
||||||
(defn bind-root
|
(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]
|
[v val]
|
||||||
(put v :root val))
|
(put v :root val)
|
||||||
|
(put v :gen (+ 1 (or (v :gen) 0)))
|
||||||
|
val)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Namespace
|
# Namespace
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,21 @@
|
||||||
(assert (deep= {:name 'x :private true} (var-meta v2)) "with-meta merges meta")
|
(assert (deep= {:name 'x :private true} (var-meta v2)) "with-meta merges meta")
|
||||||
(assert (= 42 (var-get v2)) "with-meta preserves root binding"))
|
(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
|
# var with namespace
|
||||||
(let [ns (make-ns 'my.ns)
|
(let [ns (make-ns 'my.ns)
|
||||||
v (make-var 'my.ns/x 1 {:ns ns})]
|
v (make-var 'my.ns/x 1 {:ns ns})]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue