Chez Phase 3 inc9a: self-contained Chez bootstrap (no Janet in the loop)
Makes the inc8 fixpoint the actual build. host/chez/bootstrap.ss loads a seed
(prelude, image) pair and rebuilds the clojure.core prelude + compiler image from
source via the on-Chez compiler — read/analyze/emit all on Chez, zero Janet.
The seed (host/chez/seed/{prelude,image}.ss) is the checked-in bootstrap
compiler, minted once via the fixpoint (driver/mint-chez-seed* iterates
bootstrap.ss from the Janet-emitted pair to a joint byte-fixpoint). It's a joint
fixpoint: rebuilding from an up-to-date seed reproduces it exactly. So a fresh
checkout + Chez (no Janet) yields a working jolt.
test/chez/bootstrap-test.janet spawns only chez, asserts the rebuilt artifacts
match the seed byte-for-byte and compile+run real cases. Drift (seed sources
changed) fails the test with a re-mint pointer; host/chez/seed/README documents
re-minting.
This commit is contained in:
parent
81e587b2d7
commit
2c74476aed
6 changed files with 1490 additions and 0 deletions
42
host/chez/bootstrap.ss
Normal file
42
host/chez/bootstrap.ss
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
;; bootstrap.ss (jolt-9phg, Phase 3 inc9a) — the pure-Chez self-build.
|
||||
;;
|
||||
;; This is the zero-Janet build step. Given a SEED (prelude, image) pair — the
|
||||
;; bootstrap compiler, minted once via the inc8 fixpoint and checked in under
|
||||
;; host/chez/seed/ — it loads them, then rebuilds the clojure.core prelude AND the
|
||||
;; compiler image from the .clj/.ss sources using the ON-CHEZ compiler (emit-image.ss),
|
||||
;; writing fresh artifacts. No Janet is invoked: read -> analyze -> emit all run on
|
||||
;; Chez. The seed is a JOINT fixpoint, so a rebuild from an up-to-date seed
|
||||
;; reproduces it byte-for-byte (test/chez/bootstrap-test.janet checks this); when
|
||||
;; the sources change, run it twice to reconverge and re-mint the seed.
|
||||
;;
|
||||
;; Run from the repo root:
|
||||
;; chez --script host/chez/bootstrap.ss SEED-PRELUDE SEED-IMAGE OUT-PRELUDE OUT-IMAGE
|
||||
(import (chezscheme))
|
||||
|
||||
(define bs-args (cdr (command-line))) ; drop the script name
|
||||
(when (< (length bs-args) 4)
|
||||
(display "usage: bootstrap.ss SEED-PRELUDE SEED-IMAGE OUT-PRELUDE OUT-IMAGE\n")
|
||||
(exit 2))
|
||||
(define bs-seed-prelude (list-ref bs-args 0))
|
||||
(define bs-seed-image (list-ref bs-args 1))
|
||||
(define bs-out-prelude (list-ref bs-args 2))
|
||||
(define bs-out-image (list-ref bs-args 3))
|
||||
|
||||
;; Load the runtime + the SEED compiler (prelude for macros, image for the
|
||||
;; analyzer/emitter), exactly as the zero-Janet spine assembles a program.
|
||||
(load "host/chez/rt.ss")
|
||||
(set-chez-ns! "clojure.core")
|
||||
(load bs-seed-prelude)
|
||||
(load "host/chez/post-prelude.ss")
|
||||
(set-chez-ns! "user")
|
||||
(load "host/chez/host-contract.ss")
|
||||
(load bs-seed-image)
|
||||
(load "host/chez/compile-eval.ss")
|
||||
(load "host/chez/emit-image.ss")
|
||||
|
||||
;; Rebuild both artifacts from source ON CHEZ and write them out.
|
||||
(let ((p (open-output-file bs-out-prelude 'replace)))
|
||||
(put-string p (jolt-emit-prelude)) (close-port p))
|
||||
(let ((p (open-output-file bs-out-image 'replace)))
|
||||
(put-string p (jolt-emit-image)) (close-port p))
|
||||
(display "bootstrap: rebuilt prelude + compiler image on Chez (no Janet)\n")
|
||||
|
|
@ -409,6 +409,61 @@
|
|||
(def code (os/proc-wait proc))
|
||||
[code (string/trim (string out err))])
|
||||
|
||||
# --- pure-Chez self-build (jolt-9phg, inc9a) ----------------------------------
|
||||
# host/chez/bootstrap.ss rebuilds the prelude + compiler image from source ON
|
||||
# CHEZ given a seed (prelude, image) pair. run-bootstrap drives ONE bootstrap.ss
|
||||
# pass (no Janet in the compile path — Janet only spawns chez). mint-chez-seed
|
||||
# iterates it from the Janet seed to the joint fixpoint and writes the checked-in
|
||||
# bootstrap seed under host/chez/seed/.
|
||||
|
||||
(defn run-bootstrap
|
||||
"Run one pure-Chez bootstrap pass: load (seed-prelude, seed-image), rebuild the
|
||||
prelude + image from source on Chez, write them to (out-prelude, out-image).
|
||||
Returns [code stdout stderr]. The compilation is 100% Chez; Janet only spawns
|
||||
the process."
|
||||
[seed-prelude seed-image out-prelude out-image]
|
||||
(def proc (os/spawn ["chez" "--script" "host/chez/bootstrap.ss"
|
||||
seed-prelude seed-image out-prelude out-image]
|
||||
:p {:out :pipe :err :pipe}))
|
||||
(def out (drain (proc :out)))
|
||||
(def err (drain (proc :err)))
|
||||
(def code (os/proc-wait proc))
|
||||
[code (string/trim out) (string/trim err)])
|
||||
|
||||
(defn mint-chez-seed*
|
||||
"Mint the checked-in bootstrap seed. Takes the Janet-emitted starting pair
|
||||
(janet-prelude + janet-image, e.g. from jolt-chez/ensure-prelude +
|
||||
ensure-compiler-image) and iterates bootstrap.ss to the joint byte-fixpoint, then
|
||||
writes the converged pair to seed-prelude/seed-image. Run once (and whenever the
|
||||
seed sources change) to refresh the checked-in seed. Returns iteration count."
|
||||
[janet-prelude janet-image seed-prelude seed-image &opt max-iter]
|
||||
(default max-iter 8)
|
||||
(defn b= [a b] (= (string (slurp a)) (string (slurp b))))
|
||||
(def tmp (or (os/getenv "TMPDIR") "/tmp"))
|
||||
(var cur-pre janet-prelude)
|
||||
(var cur-img janet-image)
|
||||
(var converged false)
|
||||
(var iters 0)
|
||||
(for i 0 max-iter
|
||||
(def npre (string tmp "/mint-pre-" i ".ss"))
|
||||
(def nimg (string tmp "/mint-img-" i ".ss"))
|
||||
(def [code _ err] (run-bootstrap cur-pre cur-img npre nimg))
|
||||
(unless (zero? code) (errorf "bootstrap pass %d failed: %s" i err))
|
||||
(set iters (inc i))
|
||||
# A pass is a fixpoint once its output equals its input AND the input is no
|
||||
# longer the Janet seed (the Janet prelude/image differ only in gensym ids).
|
||||
(when (and (not= cur-pre janet-prelude)
|
||||
(b= cur-pre npre) (b= cur-img nimg))
|
||||
(set converged true)
|
||||
(set cur-pre npre) (set cur-img nimg)
|
||||
(break))
|
||||
(set cur-pre npre) (set cur-img nimg))
|
||||
(unless converged (errorf "seed did not converge in %d iterations" max-iter))
|
||||
(os/mkdir (string/slice seed-prelude 0 (last (string/find-all "/" seed-prelude))))
|
||||
(spit seed-prelude (slurp cur-pre))
|
||||
(spit seed-image (slurp cur-img))
|
||||
iters)
|
||||
|
||||
# --- batched zero-Janet corpus runner (jolt-qjr0, inc7) -----------------------
|
||||
# eval-zero-janet spawns a fresh chez per case, each reloading rt.ss + the prelude
|
||||
# (~282KB) + the compiler image (~89KB) from source — ~0.5s of pure reload per
|
||||
|
|
|
|||
39
host/chez/seed/README.md
Normal file
39
host/chez/seed/README.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Chez bootstrap seed
|
||||
|
||||
These two files are the **bootstrap compiler** for jolt-on-Chez — the seed that
|
||||
makes the build self-hosting with no Janet in the loop:
|
||||
|
||||
- `prelude.ss` — the `clojure.core` prelude (all tiers + clojure.string/walk/
|
||||
template/edn/set/pprint) as Scheme `def-var!` forms.
|
||||
- `image.ss` — the compiler image (`jolt.ir` + `jolt.analyzer` +
|
||||
`jolt.backend-scheme`) as Scheme `def-var!` forms.
|
||||
|
||||
Both are **generated**, not hand-written. They are checked in because a fresh
|
||||
checkout must be able to build jolt-on-Chez using only Chez: `host/chez/bootstrap.ss`
|
||||
loads this seed, then rebuilds the prelude + image from the `.clj`/`.ss` sources via
|
||||
the on-Chez compiler (read → analyze → emit, all on Chez). The seed is a **joint
|
||||
byte-fixpoint**: rebuilding from an up-to-date seed reproduces it exactly
|
||||
(`test/chez/bootstrap-test.janet` verifies this).
|
||||
|
||||
Janet was used once, historically, to mint the very first seed (the Janet analyzer/
|
||||
emitter cross-compiled the sources, then the on-Chez compiler iterated to the
|
||||
fixpoint — see `test/chez/fixpoint-test.janet`). After that, Janet is never needed
|
||||
to build or run jolt-on-Chez.
|
||||
|
||||
## Re-minting
|
||||
|
||||
When the seed sources change (the core tiers, the compiler namespaces, the host
|
||||
contract, the reader, `emit-image.ss`), the seed drifts and `bootstrap-test`
|
||||
fails. Re-mint it:
|
||||
|
||||
```janet
|
||||
(import host/chez/driver :as d)
|
||||
(import host/chez/jolt-chez :as jc)
|
||||
(def ctx (d/make-ctx))
|
||||
(d/mint-chez-seed* (jc/ensure-prelude ctx)
|
||||
(d/ensure-compiler-image ctx "/tmp/stage1.ss")
|
||||
"host/chez/seed/prelude.ss"
|
||||
"host/chez/seed/image.ss")
|
||||
```
|
||||
|
||||
Then commit the refreshed `prelude.ss` / `image.ss`.
|
||||
174
host/chez/seed/image.ss
Normal file
174
host/chez/seed/image.ss
Normal file
File diff suppressed because one or more lines are too long
1108
host/chez/seed/prelude.ss
Normal file
1108
host/chez/seed/prelude.ss
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue