ReviewOS

zig-utils/zig-js

JIT: make trap polling and optimized artifact lifetime concurrency-safe

#433
Closed chris opened this 9 days ago ·
9 days ago

Parent: #146 Unblocked: #429 Depends on: #431, #432 Children: #454, #455, #456, #457 Related: #132, #133, #145

Implement concurrency-safe optimized trap polling, watchpoint invalidation, call/IC publication, and executable artifact retirement. No mutable optimizer record may be observed partially published or reclaimed while a compiler or mutator can still use it.

Acceptance

  • Model trap polls as invalidation points that clobber every heap fact rewritten by a stop window.
  • Publish shape/property/call IC records atomically and revalidate all advisory profiles/watchpoints at link time.
  • Implement code, call-link, handler-chain, and IC retirement with bounded epoch reclamation and GC accounting.
  • Serialize Class-A stop publication against shared-GC completion waits and prove bounded convergence.
  • Jettison dependent code before mutators resume; preserve resumable side exits and precise roots.
  • Pass writer/writer, reader/reset, poll/resume, GC-wait, memory-steady-state, no-GIL, and the supported Zig engine sanitizer matrix (TSan; Zig engine ASan is not exposed by the Zig 0.17 build).

Completion

fdb27940 introduced generation-scoped executable retirement, coherent call-link publication, epoch tokens, and byte/count accounting. 26ef6127/01306740 ordered Class-A invalidation with shared collection; #457 supplied exact inherited-property watchpoints. 4dfc2aca, aa99feb2, and 821a5242 promoted the remaining writer, trap, and stale-base corpus witnesses with nonzero optimizer evidence.

Final gate ead94ad8: complete test-jit passes 175/175 normally and 175/175 under TSan, both with zero leaks. The checked-in closure record is docs/.data/jit-concurrency-2026-07-22.md.

9 days ago

Foundation note: 74fd22d publishes the first optimizer artifact through the existing context owner execution/compilation lease and invalidates it before mapping release. This covers the current exact constant-return artifact, but #433 remains open for trap polling, compiled frames, mid-script exits, and broader concurrent optimized-artifact lifetime.

9 days ago

Audit after 561a516: current owner leases, immutable publication, stale-claim rejection, entry/header generation polls, and exact pre-checkpoint side exits cover the real numeric optimizer artifacts. The remaining PR-249 premises are not bookkeeping gaps: optimized calls and property effects still exit to bytecode, so call-link/IC retirement records do not exist yet, and live in-native relocation still depends on #437 instruction-level safepoints. I am keeping every #433 acceptance box open rather than adding fake counters or unused reset hooks.

9 days ago

#440 is complete through 7a26276/87513c2, so #433 now has a real immutable property-IC artifact to build on: four shape/slot pairs are copied with the live bytecode seqlock, owned by the optimizer artifact, and guarded against the receiver’s current shape and slot range. Shared native reads/writes are object-lock serialized and TSan-clean. #433 still owns link-time watchpoint revalidation, stop-window invalidation/jettison, call-link/IC atomic publication, and bounded epoch retirement; #132 remains open for direct backend guards and performance evidence.

9 days ago

a35ee76 now consumes #440 metadata in generated AArch64: every cached pair is re-looked-up by name at link time, and isolated inline reads guard the exact object tag, cold/exotic state, live shape, and slot before bypassing the callback. Shared mode always falls back to the object-lock path. This supplies a real link-time property-IC revalidation witness for #433, but stop-window watchpoints, jettison, call-link publication, and bounded retirement remain open.

9 days ago

#454 and #455 are complete through fdb2794/472920f. Optimizer invalidation now jettisons tiers into generation-scoped retirement rather than waiting for whole-script leases; final readers reclaim artifact-owned code, handlers, IC/call metadata, deopt records, and stack maps with explicit byte/count accounting. Native entry carries an epoch token so old executions cannot enter newer code. Ordinary optimizer calls now publish a coherent callee/generation/artifact tuple, revalidate it on every hit, and fall back through the rooted runtime ABI on a miss. Complete normal and TSan JIT gates pass 171/171. Remaining #433 work is the Class-A/shared-GC ordering and poll/resume promotion owned by #456, plus final corpus evidence.

9 days ago

8961a346 (fix(jit): admit safe sloppy VM functions) fixes the current Class-A CI failures at their shared admission root.

plainFunctionMayUseBytecode scanned the entire function source for (, so it mistook every traditional function declaration parameter list for a body call. That made both documented exceptions unreachable in practice: no-call named-property bodies never published optimizer artifacts, and safe named self-recursion stayed on the native tree-walker stack.

The policy now scans only the body for possible calls, keeps arbitrary sloppy callees and legacy caller/arguments observers fail-closed, and explicitly admits the already-documented named self-recursion case.

Evidence:

  • zig build test-parallel --summary all: 1,446/1,446 passed, 0 leaked (the prior three Class-A failures and recursion failure are green).
  • Focused Class-A: 5/5 normal and 5/5 TSan, no warnings/leaks.
  • Heap-bounded recursion: 3/3 normal and 3/3 TSan.
  • jit/foreign-reify-getbyid-converges.js: pass serialized Debug; pass no-GIL Debug and ReleaseSafe with publications=3 invalidations=1 collections=1 reclaimed=3.
  • semantics/stack-overflow-per-thread.js: pass serialized/no-GIL Debug and no-GIL ReleaseSafe.
  • Flips 0 Test262 cases; no expectations changed.

This repairs the red Class-A publication evidence but does not close #433: the remaining trap/IC lifecycle corpus and sanitizer acceptance still need their own green fixing-main evidence.

9 days ago

Call-link lifetime checkpoint: 4dfc2aca is on main. The pinned writer/writer witness now produces real concurrent optimizer and call-link publication evidence instead of passing only through canonical dispatch.

ReleaseSafe no-GIL passes with 1,500 optimizer publications, 300 invalidations, 1,500 reclaimed artifacts, and 12,393 call-link publications. The TSan no-GIL run also passes (1,500 publications, 300 invalidations, 1,500 reclaimed, 14,454 call links) with no sanitizer finding; serialized ReleaseSafe publishes 18,550 call links. Exact fixture rewrites fail closed on vendored-corpus drift.

This closes the call-link writer/writer promotion slice, but #433 stays open for the remaining trap-poll invalidation and stale-base guard cases plus the broader bounded retirement/IC acceptance matrix.

9 days ago

Trap invalidation checkpoint: aa99feb2 is on main. The pinned checktraps-invalidation.js witness now executes real guarded named-property artifacts across all 50 Class-A windows and is hard-gated on nonzero publication, invalidation, and reclamation.

ReleaseSafe no-GIL passes in 222 ms with 50/49/49 publication/invalidation/reclamation. TSan no-GIL passes in 28,016 ms with 52/51/51 and no race report. The bounded runner profile preserves every stop window and value oracle while fitting the TSan per-case budget.

This closes the checktraps invalidation promotion slice. #433 stays open for the final stale-base guard witness and the remaining broader lifetime/IC acceptance work.

9 days ago

Stale-base guard checkpoint: 821a5242 is on main and completes the final #429 promotion.

The AArch64 optimizer can now load ordinary dense-array length through the same fail-closed storage guards as indexed access. Isolated artifacts reload guarded storage/length; shared realms reject the unlocked path before either load and use the canonical element-lock callback. A JIT-off/JIT-on unit differential covers live-length reads and writes.

The exact PR-249 profile publishes both reader and writer artifacts in every measured run: ReleaseSafe serialized/no-GIL pass with 2/2 publications; TSan serialized/no-GIL pass with 2/2 and no sanitizer finding. The runner now fails the case if publication is zero, so canonical fallback alone cannot satisfy the promotion premise.

#429 is complete at 253 promoted / 0 blocked / 6 terminal. #433 remains open for its broader acceptance matrix beyond the now-complete PR-249 promotion tail.

9 days ago

Closure evidence is now on main in ead94ad8. The complete optimizer gate passes 175/175 normally and 175/175 under TSan with zero leaks. All four children (#454–#457) are complete, and the terminal PR-249 evidence proves the call-link, trap-invalidation, inherited-property/Class-A, and stale-base paths actually published optimized artifacts rather than passing by fallback. The acceptance checklist now names the supported Zig engine sanitizer matrix accurately: TSan is available; the repository ASan/UBSan target covers the Objective-C bridge, not Zig engine code.

Sign in to comment on this issue.