ReviewOS

zig-utils/zig-js

Runtime: reduce cold context startup and teardown cost

#479
Open chris opened this 9 days ago ·
9 days ago

Parent: #459 Depends on: #460, #461, #462

Goal

Reduce context/realm cold-start and teardown latency through owned immutable bootstrap artifacts and bounded reusable infrastructure, without hiding work outside the cold timing boundary or leaking state across realms.

Scope

  • Attribute allocator setup, global/builtin installation, shapes/atoms/strings, parser/compiler work, module registries, GC heap initialization, JIT owner/code pages, inspector/debugger tables, and teardown/finalization.
  • Share only immutable process/VM artifacts: generated tables, builtin source/bytecode/native templates, canonical atoms/shapes, and read-only metadata with explicit version/feature/options keys.
  • Add copy-on-write or per-realm mutable state where identity/prototype mutation requires isolation.
  • Reuse bounded allocator/code-page/scratch infrastructure only when it is outside context ownership by public design and included symmetrically in the documented benchmark model.
  • Make teardown proportional to owned live resources rather than historical capacity.

No-workaround rules

  • No hidden pre-created Context, unbounded realm pool, skipped builtin initialization, shared mutable globals/prototypes, delayed finalizers outside the timed lifecycle, or benchmark runner warmup in cold mode.

Acceptance

  • #460 cold rows include empty/minimal/full-feature contexts, source/module setup, first evaluation, destruction, peak RSS, retained process RSS, and finalizer counts.
  • Shared immutable artifacts have mutation-isolation, sibling-realm, GC lifetime, invalidation, thread-safety, and teardown tests.
  • Every cold-lifecycle speedup has exact-parent phase/RSS evidence and no warm steady-state regression.
  • Repeated create/destroy soak returns to a bounded process-memory plateau with all callbacks/finalizers exactly once.
  • Current #44 cold wins remain green.

Foundation

The current benchmark's process-wide thread-safe allocator model and timed cold boundary are documented in docs/benchmarks.md; lifecycle improvements must preserve that contract.

9 days ago

#553 removed one full lexer pass and one discarded token list from every cold production Module parse in 78dbd220. Exact-parent 1K/2K/4K evidence reports 33.6-34.4% fewer retired instructions, 20.6-20.7% fewer allocation requests, and 31.5-47.9% fewer allocated bytes with unchanged module semantics. Evidence. #479 remains open for whole-Context startup/teardown acceptance.

9 days ago

Opened #597 from the current production cold-lifecycle profile. Heap.headerForPayload leads active leaves at 1,951 samples because embedded realm-root Environment writes pass an unmanaged Context address through managed-owner classification. The child keeps the child barrier intact but routes the proven embedded owner through the existing ownerless remembered-target path; managed environments retain exact-owner barriers.

9 days ago

#597 landed in 8e211b2f. The production cold-lifecycle median improves 27.878 ms -> 13.114 ms (-52.96%) by eliminating 11,400 redundant slab ownership acquisitions during configuration. The former dominant headerForPayload leaf falls from 1,951 to 17 samples; checksums, allocation/execution counters, relevant test262, focused TSan, and the full unit plan remain exact.

9 days ago

Opened #598 from the post-#597 cold attribution. One single-owner precise-GC configuration still takes 31,242 Environment locks, including 27,289 root reads and 3,942 root writes. The child uses an immutable per-Environment policy fixed before publication; it explicitly retains locking for threads, parallel modes, and concurrent marking and does not revive the unsafe mutable process-global gate.

9 days ago

Child #598 is complete via 6c246bb6. It removes all 31,231 single-owner root binding-lock acquisitions from the measured configuration while preserving locks for shared/concurrent roots; full units, exact-parent test262, focused TSan/GC, and C-API sibling-realm witnesses are clean.

This is additive to #597: root writes now avoid both managed-owner classification and mutex acquisition. The remaining #479 work should be selected from a fresh exact-parent profile rather than inferred from these closed hotspots.

9 days ago

Fresh post-#598 profiling split the next bounded child into #599. Excluding the independent-lane join owned by the lifecycle workstream, managed string construction leads active engine leaves: 1,437 five-second samples map to the serial cached content hash, versus 318 in Shape lookup. #599 owns only deterministic cached hashing/classification and exact string semantics.

9 days ago

Child #599 is complete via 043f9788. The post-#598 dominant active engine leaf was removed: cached string hash/classification samples fall 1,437 → 859, and 21 exact-parent production cold pairs improve 12.938 ms → 10.423 ms (-19.44%) with identical runtime/allocation inventories and checksum. Full units, focused TSan/GC/C-API, and 7,870 exact-parent test262 cases are clean. The remaining #479 work should again start from a fresh current-main profile.

9 days ago

Opened #600 from the fresh post-#599 cold profile. The next bounded duplicate work is within managed string construction: separate surrogate-detection and classification scans account for 242 + 115 sampled leaves. #600 fuses only those scans and preserves exact canonicalization/ownership; lifecycle and jobs remain excluded.

9 days ago

#600 was measured and rejected with no code landed. The candidate showed a small cold-start signal (-0.802% across 101 alternating pairs) but was neutral on the dedicated strings workload (-0.010%, 5/9 wins) and did not materially reduce the sampled leaf work. Full evidence is recorded on #600.

9 days ago

Opened #601 from the current-main cold/string profile. It targets unconsumed eager XXH3 work in temporary uninterned strings without growing StringCell, adding process-global state, or touching lifecycle/jobs. Static/interned strings remain eager; runtime equality publishes a deterministic atomic cache on first use.

9 days ago

Child #601 is complete via 8dd7605d. Removing unconsumed eager hashes from uninterned runtime strings improves the exact-parent one-lane cold median 11.487458 ms -> 9.412959 ms (-18.06%) across 101 alternating pairs, with 101/101 wins and exact allocation/heap/execution inventories. No lifecycle or jobs surface changed.

9 days ago

Opened #602 for repeated cold availability probes: unresolved typeof already returns static undefined, while every resolved operand allocates/traces/finalizes an equivalent managed cell. The child removes only that fixed-result ownership work and does not touch lifecycle or jobs.

9 days ago

Child #602 is complete on main via e9d641d3. The runtime now reuses immutable static StringCells for resolved typeof results across tree-walker and bytecode paths. In the attributable 4,480-operation workload this removed 8,961 cumulative managed cells and 573,504 GC-cell bytes including warmup; 41 paired samples improved median time by 1.299% with identical work and checksum. Broad cold controls stayed mixed within -0.169% to +0.538%, so no general startup claim is made.

9 days ago

Opened #603 to remove repeat managed-string construction when DateTimeFormat reflects already validated native field/style enums. Current-main exact attribution is recorded against the existing 3,200-operation component-construction row. The child is limited to immutable enum projection and explicitly leaves dynamic strings plus all jobs/Worker surfaces unchanged.

9 days ago

Child #603 is complete on main via 10ac2f3d. Closed DateTimeFormat field/style enums now project through immutable static StringCells, removing exactly 2-7 managed cells per constructor + resolvedOptions() operation depending on the row. The component-heavy row removes 22,400 cells across 3,200 operations and improves 21-pair median time by 3.114%; controls remain within -0.280% to +0.307%, so no broad runtime claim is made.

9 days ago

Opened #604 to project validated finite NumberFormat option strings through immutable static cells in each fresh resolvedOptions() object. Current-main baselines are recorded for all four existing constructor rows; the child excludes dynamic strings and every user-owned jobs/Worker surface.

9 days ago

Child #604 is complete on main via b5dd6761. Fresh NumberFormat resolved-options objects no longer allocate cells for six ordinary validated choices (nine for currency+compact). Exact rows remove 19,200-28,800 managed cells per 3,200 operations with identical work/checksums; paired medians improve 3.523%-12.192%. Dynamic ownership paths and all jobs/Worker surfaces are unchanged.

9 days ago

Opened #605 for the remaining DisplayNames resolved-options enum allocations. Because there is no dedicated committed reflection row, this child begins with a benchmark-only commit that freezes formatter identities, every present field, checksums, and the timed boundary before changing the runtime.

9 days ago

Benchmark-first child #605 is complete via 103413d0 + 3b61ee05. Fresh DisplayNames resolved-options objects now reuse static cells for four closed enums while locale stays managed. Exact 6,400-operation allocation falls by 20,800 cells/backing allocations; paired timing is neutral, so no broad runtime claim is made.

9 days ago

Opened #606 for ListFormat/RelativeTimeFormat resolved-options enum allocations. The child starts with a combined benchmark-only commit and explicitly keeps dynamic locale/numbering ownership plus all jobs/Worker surfaces unchanged.

9 days ago

Benchmark-first child #606 is complete via 338b472b + 7f46c2dd. Fresh ListFormat/RelativeTimeFormat results now reuse four static enum cells per paired operation while locale/numbering remain managed. Exact allocation falls by 25,600 cells across 6,400 pairs; timing is neutral, so no broad runtime claim is made.

9 days ago

Opened #607 from the post-#606 current-main cold profile. The tree walker currently queries the debugger registry for expression and synthetic Program nodes that the parser can never publish as statement locations, churning the bounded negative cache even with no debugger attached. The child preserves every host-hook checkpoint and all late-attach/debugger/stack semantics; it removes only provably impossible registry probes.

9 days ago

Child #607 is complete via 506d8950. Provably impossible expression/Program debugger-registry probes are gone while every host checkpoint and actual debugger location remains intact. Exact attribution reduces cumulative misses 5,994 -> 354; the 101-pair exact-parent cold gate records 0.9897x retired instructions and 0.984x wall on the diagnostic host, with neutral RSS and exact checksums.

9 days ago

Opened related cold/frontend child #608. The lexer currently validates each ordinary/private IdentifierStart and then immediately revalidates the same first byte/code point in the name scanner. The child consumes the validated length once and is isolated from all jobs/Worker/lifecycle surfaces.

9 days ago

Related cold/frontend child #608 is complete in 4fe004e1. The duplicate IdentifierStart decode is removed without allocations or ownership changes. The formal 4K Unicode row records 0.9657x instructions and 0.970x diagnostic wall; control wall medians are mixed/noisy, so no broad startup claim is made.

9 days ago

Related cold/frontend child #609 is complete in 0d5eb7a0. Static reserved-binding classification removes repeated equality chains with 17.4%-23.1% stable instruction reductions on binding-heavy parser rows and no allocation/RSS trade. Private-name controls are neutral; no broad lifecycle claim is made.

9 days ago

Cold-lifecycle evidence child #661 is implemented in b815b3e7. V19 adds a separate non-scored profile for no-evaluation, first-source, first-module, and full-feature contexts with create/work/destroy phases, same-domain RSS, four soak checkpoints, and complete once-only GC finalizer reconciliation. The exact-parent collector now fails closed on options/checksum/retention drift and still requires quiet-host evidence before any #479 speed claim. This establishes the missing measurement boundary; it does not yet claim a lifecycle optimization.

9 days ago

Opened #662 from the fresh #661 lifecycle profile. Shape transition construction leads current engine leaves, while every Shape first-child publication independently calls secure entropy for a SipHash key. The child keeps the keyed attacker-resistant bound but derives unique per-map keys from one fail-closed realm secret; it excludes all stacks, queues, jobs, Promise, Worker, and Map/Set iterator surfaces.

9 days ago

Opened #663 from the post-#662 cold profile. Built-in/function/global initialization currently releases and reacquires property_lock between publishing a data value and its final attributes. The child introduces one failure-atomic descriptor publication transaction, with exact OOM rollback and no-GIL visibility coverage; it excludes all stacks, queues, jobs, Promise, Worker, and Map/Set iterator work.

9 days ago

#662 now has accepted exact-parent cold lifecycle evidence: 0.795x wall time, 0.887x instructions, 0.796x cycles, 0.843x process energy, neutral bounded RSS, and exact checksum/finalizer reconciliation across seven order-balanced pairs. Its required warm steady-state control remains open, so this records the cold half of the parent acceptance rule without overclaiming completion.

9 days ago

Symbol property-key recovery hardening is complete in #852 / ce1225a5. The per-Interpreter index now preserves exact Symbol identity and embedded-NUL encodings under keyed hashing, including registry recovery, reflection/Proxy, Intl fallback, and GC relocation. Exact-parent Test262 and required-bytecode inventories are 3,973/3,973 clean.

Sign in to comment on this issue.