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.
145 lines
6.2 KiB
Plaintext
145 lines
6.2 KiB
Plaintext
;;;; (filled b) and (dead-beef), the two byte fills, read back as bytes.
|
|
;;;;
|
|
;;;; The whole point of this program is that every row is a *byte* and not a
|
|
;;;; value: the pattern fill's contract is "a hex dump reads the pattern left
|
|
;;;; to right", which is a claim about which byte lands at which address, and
|
|
;;;; only reading the bytes back in address order can check it. The u32 rows
|
|
;;;; are the same claim from the other side — a little-endian load of
|
|
;;;; DE AD BE EF is 0xEFBEADDE, which is 4022250974, so a backend that wrote
|
|
;;;; the word the other way round would print 3735928559 here and be caught.
|
|
;;;;
|
|
;;;; The lengths are chosen for the tail. 8 is a whole number of patterns, 9
|
|
;;;; ends on DE, 6 ends on DE AD, and 7 ends on DE AD BE — the three truncated
|
|
;;;; endings and the one that is not truncated at all.
|
|
;;;;
|
|
;;;; The rows that matter most are the last group: a pattern that is *not* a
|
|
;;;; literal, over a length that is not a multiple of four. That is the case a
|
|
;;;; constant-only implementation would pass by accident — the word reaches
|
|
;;;; the loop in a register and the tail bytes have to be shifted out of it
|
|
;;;; rather than folded, on both backends.
|
|
(defstruct Words [a u32 b u32])
|
|
|
|
;;;; A computed global initialiser: a fill is never a constant the linker can
|
|
;;;; write, so this one goes through the startup function on both backends.
|
|
(defonce gfill [4 u8] (filled 0x41))
|
|
(defonce gsent [5 u8])
|
|
|
|
(defn bytes4 [b [4 u8]] ()
|
|
(dotimes [i 4] (print (at b i)) (print " ")))
|
|
|
|
;;;; A u32 that no literal rule can see through: (u32 0xBAADF00D) will not do,
|
|
;;;; because the cast checks its operand as an i32 first and 0xBAADF00D is not
|
|
;;;; one. A parameter's declared type is what makes the literal a u32, and it
|
|
;;;; is also what stops the checker folding it at the fill.
|
|
(defn u32of [x u32] u32 x)
|
|
|
|
;;;; The pattern crosses a call boundary, so nothing can fold it at the fill.
|
|
(defn beef7 [pat u32] ()
|
|
(let [a (array 7 u8)]
|
|
(set a (dead-beef pat))
|
|
(dotimes [i 7] (print (at a i)) (print " "))
|
|
(println "")))
|
|
|
|
(defn main [] i32
|
|
;; One byte, repeated. 0xFF is the -1 fill a debug allocator wants.
|
|
(let [a (array 4 u8)]
|
|
(set a (filled 0xFF))
|
|
(bytes4 a) (println "")) ; 255 255 255 255
|
|
|
|
;; The byte is an expression, not a literal: this is a memset with the
|
|
;; operand in a register, and the register path is the one a constant would
|
|
;; otherwise hide.
|
|
(let [v (u8 7)
|
|
a (array 4 u8)]
|
|
(set a (filled v))
|
|
(bytes4 a) (println "")) ; 7 7 7 7
|
|
|
|
;; (filled 0) is (zeroed), byte for byte, and saying so here is what keeps
|
|
;; the two from drifting.
|
|
(let [a (array 4 u8)]
|
|
(set a (filled 0))
|
|
(bytes4 a) (println "")) ; 0 0 0 0
|
|
|
|
;; Four bytes, ascending, with nothing truncated.
|
|
(let [a (array 8 u8)]
|
|
(set a (dead-beef))
|
|
(dotimes [i 8] (print (at a i)) (print " "))
|
|
(println "")) ; 222 173 190 239 x2
|
|
|
|
;; The bare form is the spelled-out default, and this is the row that says
|
|
;; so: the same eight bytes from (dead-beef 0xDEADBEEF).
|
|
(let [a (array 8 u8)]
|
|
(set a (dead-beef 0xDEADBEEF))
|
|
(dotimes [i 8] (print (at a i)) (print " "))
|
|
(println "")) ; identical to the row above
|
|
|
|
;; The three truncated tails.
|
|
(let [a (array 9 u8)]
|
|
(set a (dead-beef))
|
|
(dotimes [i 9] (print (at a i)) (print " "))
|
|
(println "")) ; ... ends on 222
|
|
|
|
(let [a (array 6 u8)]
|
|
(set a (dead-beef))
|
|
(dotimes [i 6] (print (at a i)) (print " "))
|
|
(println "")) ; ... ends on 222 173
|
|
|
|
(let [a (array 7 u8)]
|
|
(set a (dead-beef))
|
|
(dotimes [i 7] (print (at a i)) (print " "))
|
|
(println "")) ; ... ends on 222 173 190
|
|
|
|
;; A pattern of the program's own choosing, laid down left to right the same
|
|
;; way: 0xBAADF00D is BA AD F0 0D, which is 186 173 240 13.
|
|
(let [a (array 6 u8)]
|
|
(set a (dead-beef 0xBAADF00D))
|
|
(dotimes [i 6] (print (at a i)) (print " "))
|
|
(println "")) ; 186 173 240 13 186 173
|
|
|
|
;; The same pattern read as words rather than as bytes, which is what says
|
|
;; which end the DE is at.
|
|
(let [w (Words {})]
|
|
(set w (dead-beef))
|
|
(print (.a w)) (print " ") (print (.b w)) (println ""))
|
|
|
|
(let [w (Words {})]
|
|
(set w (dead-beef 0xBAADF00D))
|
|
(print (.a w)) (print " ") (print (.b w)) (println ""))
|
|
|
|
;; A nested aggregate: a fixed array of structs is plain data all the way
|
|
;; down, so the fill reaches every byte of it.
|
|
(let [g (array 2 Words)]
|
|
(set g (filled 0xFF))
|
|
(print (.a (at g 0))) (print " ") (print (.b (at g 1))) (println ""))
|
|
|
|
;; The globals. [gfill] was filled before main ran; [gsent] is filled here.
|
|
(dotimes [i 4] (print (at gfill i)) (print " "))
|
|
(println "") ; 65 65 65 65
|
|
(set gsent (dead-beef))
|
|
(dotimes [i 5] (print (at gsent i)) (print " "))
|
|
(println "") ; 222 173 190 239 222
|
|
|
|
;; A fill in value position rather than as the value of a [set]: the same
|
|
;; bytes, reached through a temporary instead of through the place.
|
|
(bytes4 (filled 0xFF)) (println "") ; 255 255 255 255
|
|
|
|
;; ── The computed pattern ──────────────────────────────────────────
|
|
;; None of these can be folded: the pattern is a parameter, or arithmetic
|
|
;; the checker does not evaluate. Seven bytes is one whole pattern and a
|
|
;; three-byte tail, so the tail bytes have to come out of the register the
|
|
;; word is in rather than out of a constant.
|
|
(beef7 0xDEADBEEF) ; 222 173 190 239 222 173 190
|
|
(beef7 0xBAADF00D) ; 186 173 240 13 186 173 240
|
|
(let [p (u32of 0xBAADF00D)
|
|
a (array 6 u8)]
|
|
(set a (dead-beef p))
|
|
(dotimes [i 6] (print (at a i)) (print " "))
|
|
(println "")) ; 186 173 240 13 186 173
|
|
;; A pattern that is genuinely computed, not merely held in a slot, and read
|
|
;; back as a word so the byte order of the runtime path is pinned too.
|
|
(let [p (u32of 0xBAAD0000)
|
|
w (Words {})]
|
|
(set w (dead-beef (bit-or p (u32of 0xF00D))))
|
|
(print (.a w)) (print " ") (print (.b w)) (println ""))
|
|
0)
|