Skip to content

Defer typecheck driver translation to first typecheck (halve warm boot)#29

Merged
pyrex41 merged 3 commits into
mainfrom
claude/shen-lua-kernel-boot-y3s671
Jul 1, 2026
Merged

Defer typecheck driver translation to first typecheck (halve warm boot)#29
pyrex41 merged 3 commits into
mainfrom
claude/shen-lua-kernel-boot-y3s671

Conversation

@pyrex41

@pyrex41 pyrex41 commented Jul 1, 2026

Copy link
Copy Markdown
Owner

typecheck_native.install did ~47ms of work on every boot — the single
biggest cost in load_kernel — translating the 16 t-star.kl typecheck
driver defuns through the KL->Lua prolog compiler and loadstring'ing
the result. A plain boot never typechecks anything, so none of that is
needed until the first (shen.typecheck ...) call.

Move the parse+translate (the ~32ms CPU cost, plus install_handports)
into a memoized ensure_drivers() that typecheck_dispatch calls on the
first typecheck. The t-star.kl source READ stays eager: read_kl resolves
against the relative P.KLDIR, and a caller can chdir between boot and its
first typecheck (run-kernel-tests does exactly this), so a deferred read
could fail to find the file — we slurp the string now and defer only the
cwd-insensitive work. Harvest and the declare/destroy wrappers also stay
eager since they must observe kernel declares issued by initialise().

Warm cached boot drops ~0.10s -> ~0.045s; cold ~0.95s -> ~0.73s. The
first typecheck absorbs the deferred ~40ms once. Port specs (453) and
the kernel certification suite (35 reports, 100%) stay green.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01Fp6poWsabXMkruseeVihxx

claude and others added 3 commits July 1, 2026 02:30
typecheck_native.install did ~47ms of work on every boot — the single
biggest cost in load_kernel — translating the 16 t-star.kl typecheck
driver defuns through the KL->Lua prolog compiler and loadstring'ing
the result. A plain boot never typechecks anything, so none of that is
needed until the first (shen.typecheck ...) call.

Move the parse+translate (the ~32ms CPU cost, plus install_handports)
into a memoized ensure_drivers() that typecheck_dispatch calls on the
first typecheck. The t-star.kl source READ stays eager: read_kl resolves
against the relative P.KLDIR, and a caller can chdir between boot and its
first typecheck (run-kernel-tests does exactly this), so a deferred read
could fail to find the file — we slurp the string now and defer only the
cwd-insensitive work. Harvest and the declare/destroy wrappers also stay
eager since they must observe kernel declares issued by initialise().

Warm cached boot drops ~0.10s -> ~0.045s; cold ~0.95s -> ~0.73s. The
first typecheck absorbs the deferred ~40ms once. Port specs (453) and
the kernel certification suite (35 reports, 100%) stay green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fp6poWsabXMkruseeVihxx
initialise() spends ~19ms running the KL environment/lambda-form/signed-
func setup cold (one-shot, so the JIT can't amortize it). Profiling shows
it calls `hash` ~800 times — every `put` into the property vector hashes
its symbol key — and the compiled-KL hash is expensive per call: explode
the key into a character list, map string->n over it, then fold with
shen.prodbutzero via KL recursion.

Add a native `hash` in install_native_stdlib that folds the key's bytes
directly (symbols by name, strings by content; both are byte-based here),
reproducing prodbutzero's multiply-then-add-past-1e10 overflow guard and
the mod-0->1 rule exactly. Verified identical to the compiled-KL hash over
every kernel F-name x 5 bounds plus edge strings (empty, embedded NUL,
UTF-8, overflow-triggering lengths): 0 mismatches. Non-symbol/-string
values delegate to the original so their printed form is untouched.

initialise ~17ms -> ~10ms; warm cached boot ~0.045s -> ~0.037s. Because
hash underlies get/put and the whole property system, runtime dict-heavy
code (types, source lookup) benefits too. Adds golden-value hash tests
pinning the native fold to the kernel semantics. Port specs (459) and the
kernel certification suite (35 reports, 100%) stay green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fp6poWsabXMkruseeVihxx
Addresses a review of the lazy-translation change:

- Guard the exported entry: M.native_typecheck now calls ensure_drivers()
  before native_typecheck, so a direct caller (embedder/test) that reaches it
  before any typecheck dispatch translates the drivers instead of reading nil
  predicates out of NP and crashing. The internal dispatch path is unchanged
  (it already calls ensure_drivers and uses the raw local).

- Make ensure_drivers commit-at-end: translate into fresh accumulators and set
  drivers_ready (and the n_ok/n_fail the dispatch consults) only after the full
  pass AND install_handports() succeed. If R.read_all or an unexpected
  translator error throws partway, drivers_ready stays false so the next
  typecheck retries cleanly rather than dispatching over a half-filled NP.
  Re-running is safe: the driver source is fixed (idempotent NP writes) and the
  counters are local, not accumulated across attempts.

- Add test/typecheck_lazy_spec.lua: asserts drivers are deferred at boot
  (n_ok == 0), the direct native entry is guarded (no crash, triggers
  translation), and drivers are translated exactly once. Wired into
  scripts/run-tests.lua.

Full port suite green: 467 pass, 0 fail across 12 specs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pyrex41 pyrex41 merged commit 0a78832 into main Jul 1, 2026
2 checks passed
@pyrex41 pyrex41 deleted the claude/shen-lua-kernel-boot-y3s671 branch July 1, 2026 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants