jolt/test/integration/embedded-stdlib-test.janet
Yogthos 0e3584884f core: AOT context image — init-cached recovers the bootstrap cost across processes
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.
2026-06-10 13:57:37 -04:00

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!"))