init in compile mode is ~2.4 s (tier loading, analyzer self-compile, macro recompilation), paid by every process that builds a ctx from source — each jpm-test file, embedders, workers. init-cached marshals the built ctx to a disk image (same root-env dicts as snapshot/fork) and later processes unmarshal it in ~5 ms, any process: nothing from the baking process is needed at load. The cache key fingerprints the embedded .clj stdlib (which covers jolt-core: analyzer, IR, core tiers), the .janet seed sources next to the module, the janet version, the init opts, and the env knobs that shape a ctx (JOLT_PATH/ MUTABLE/AOT_CORE/FEATURES) — any change rebuilds. Corrupt or non-ctx images fall back to a rebuild (unmarshal of garbage can 'succeed' with a scalar, so the shape is checked, not just the throw). Writes are atomic (tmp + rename) so racing cold starts never publish a torn image. JOLT_NO_IMAGE_CACHE=1 opts out; JOLT_IMAGE_CACHE_DIR overrides the location (default TMPDIR). Test consumers switch to init-cached (harness, suite-worker, conformance, the behavioral unit/integration tests); tests that validate the bootstrap itself (bootstrap-fixpoint, staged-bootstrap, aot round-trip, direct-linking) and the deps tests (tmp-dir :paths would fragment the key) keep real init. Full jpm test: 2:46 -> 1:58 (~29%). New ctx-image-test covers cold/warm, cross-process load (subprocess runs defn/redef/macros/protocols/multimethods off the baked image), per-opts keying, and corrupt-image fallback.
33 lines
1.5 KiB
Text
33 lines
1.5 KiB
Text
# The .clj stdlib (clojure.string, clojure.set, jolt.interop, …) is baked into the
|
|
# image at build time, so it loads even when the files aren't on disk. We simulate
|
|
# the shipped-binary-elsewhere case by clearing the filesystem source roots, so a
|
|
# require can only be satisfied by the embedded copy.
|
|
|
|
(use ../../src/jolt/api)
|
|
(use ../../src/jolt/types)
|
|
|
|
(def ctx (init-cached))
|
|
(ctx-set-current-ns ctx "user")
|
|
(put (ctx :env) :source-paths @[]) # no FS roots — embedded fallback only
|
|
|
|
(var fails 0)
|
|
(defn check [label expr expected]
|
|
(let [r (protect (eval-string ctx expr))
|
|
got (if (r 0) (normalize-pvecs (r 1)) (string "ERR " (r 1)))]
|
|
(if (= got expected) (print " ok " label)
|
|
(do (++ fails) (printf " FAIL %s: want %q, got %q" label expected got)))))
|
|
|
|
(assert (> (length (get (ctx :env) :embedded-sources)) 0) "embedded-sources should be populated")
|
|
|
|
(check "clojure.string from embedded"
|
|
"(do (require (quote [clojure.string :as s])) (s/upper-case \"hi\"))" "HI")
|
|
(check "clojure.set from embedded"
|
|
"(do (require (quote [clojure.set :as set])) (vec (set/union #{1} #{2})))" [2 1])
|
|
(check "clojure.walk from embedded"
|
|
"(do (require (quote [clojure.walk :as w])) (w/keywordize-keys {\"a\" 1}))" {:a 1})
|
|
(check "jolt.interop from embedded"
|
|
"(do (require (quote [jolt.interop :as j])) (j/janet-type 1))" :number)
|
|
|
|
(if (> fails 0)
|
|
(error (string "embedded-stdlib-test: " fails " failing check(s)"))
|
|
(print "\nAll embedded-stdlib tests passed!"))
|