The trio the author decided on 2026-09-20 is now all built: def is CL's defparameter — its initialiser runs on every daemon re-run, unguarded, so an edited initialiser repaints the same storage on C-c C-c plus re-run — defonce (Clojure's name for CL's defvar, per the author) initialises once behind the .init~once. flag, and defconst stays the image. One parse arm reads both forms; the difference is Ast.reinit, carried to Tast.global's grerun. Emit.startup_plan gives a def no guard flag, and Check.check_global lifts every def initialiser — zero and literal included — into global/<n>, so the host's startup reaches it through the function cell and a re-evaluated def swaps it (Session's def_inits; Emit.redefinition declares the cell for a non-sibling target). The old defvar spelling is refused with the rename and both compiling spellings, and every program, test, doc and editor list is swept — except sand.flan, the author's live WIP, whose seven defvar lines are flagged in FIX.org and keep its three dependent tests red on this branch.
67 lines
3.1 KiB
Plaintext
67 lines
3.1 KiB
Plaintext
;;;; The allocation registry — NEXT.md, "a dev-build allocation registry".
|
|
;;;;
|
|
;;;; A Flan struct is exactly its C layout with no header and no tag word, so
|
|
;;;; nothing at run time can say what is at an address. The registry sidesteps
|
|
;;;; that: the allocator's *caller* knew the type, and a dev build writes it
|
|
;;;; down. What is asserted here is the consequence a program can see without
|
|
;;;; an inspector — whether an address is still live — and the two ways
|
|
;;;; storage dies underneath one.
|
|
;;;;
|
|
;;;; This program is deliberately readable in a release build too, and prints
|
|
;;;; a different and equally correct answer there: nothing is recorded, so
|
|
;;;; every question about an address comes back 0. The two expectations sit
|
|
;;;; side by side in the acceptance table, which is the honest way to assert
|
|
;;;; "a release build carries none of it".
|
|
|
|
(declare-c reg-on [] i32 "flan_dev_reg_enabled")
|
|
(declare-c reg-live [p (Ptr i32)] i32 "flan_dev_reg_live")
|
|
(declare-c reg-count [live i32] i64 "flan_dev_reg_count")
|
|
|
|
(defonce frame Allocator)
|
|
|
|
(defn main [] i32
|
|
;; Armed by a constructor in a dev build and never in a release one.
|
|
(println (reg-on))
|
|
|
|
;; 1. The heap tier. A pointer into a Vec's storage is live while the Vec is,
|
|
;; and the free that releases it is seen — which is the whole of "use
|
|
;; after free that names what died", minus the naming, which needs the
|
|
;; inspector to read it back.
|
|
(let [v (vec-new i32)]
|
|
(push v 7)
|
|
(push v 8)
|
|
(let [p (addr (at v 1))]
|
|
(println (reg-live p)) ; dev: 1
|
|
(free v)
|
|
(println (reg-live p)))) ; 0 either way
|
|
|
|
;; 2. The arena tier, and the hole test_valgrind.ml measures. free-all is
|
|
;; retain-capacity: the pages stay mapped and the bytes stay readable, so
|
|
;; memcheck is never told anything died and a later read of stale bytes
|
|
;; goes unnoticed. This does not tell memcheck. It tells the registry, so
|
|
;; that the same read is at least *answerable*.
|
|
(set frame (arena-new 4096))
|
|
(let [w (vec-new i32 frame)]
|
|
(push w 3)
|
|
(let [q (addr (at w 0))]
|
|
(println (reg-live q)) ; dev: 1
|
|
(free-all frame)
|
|
(println (reg-live q)))) ; 0 either way
|
|
|
|
;; 3. (bytes s) allocates — the copy is a block the registry sees, exactly
|
|
;; as a Vec's is, where the old zero-cost reinterpret was invisible to
|
|
;; every memory diagnostic because there was nothing to record. Nothing
|
|
;; else is live by here — sections 1 and 2 both released — so the live
|
|
;; count *is* the copy's block, and free-all takes it back to zero.
|
|
(let [b (bytes "copy" frame)]
|
|
(println (len b)) ; 4 — the string's length
|
|
(println (reg-count 1)) ; dev: 1 — the copy's block
|
|
(free-all frame)
|
|
(println (reg-count 1))) ; 0 either way
|
|
|
|
;; Nothing is live by now except whatever the arena's own destroy leaves, so
|
|
;; the count is a statement about the table rather than about one address.
|
|
(arena-destroy frame)
|
|
(println (reg-count 1)) ; 0 either way
|
|
0)
|