ReviewOS

zig-utils/zig-js

JIT: keep stable global builtin calls inside OSR regions

#1024
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Parent: #1016 Performance evidence: #473

Executed evidence

On main at a4d47ae, the real-GC ReleaseFast frozen representative_json attribution publishes two optimizer artifacts and preserves checksum 324952086. The scored cumulative runtime-operation histogram is exact and reconciles to the aggregate 1,440,643 callbacks:

  • load_var: 480,214
  • get_prop: 480,215
  • call_with_this: 480,214

The hot inner loop contains two matching chains per iteration: JSON.stringify(record) and JSON.parse(encoded). JIT-on reduces VM dispatch from 23,184,279 to 9,224,978, but these stable global/property/call chains remain runtime callbacks. OSR entries and deoptimizations are both 17,113; those residual exits are a separate regular-checkpoint/loop-exit concern and must not be hidden by this issue.

Scope

  • Guard and reuse stable global Environment reads for immutable observed bindings inside a selected OSR region.
  • Guard the corresponding own data property/shape for JSON.stringify and JSON.parse without bypassing ordinary mutation or accessor semantics.
  • Reuse the existing optimizer call-link protocol for the proven builtin target, preserving this, argument order, exceptions, steps, invalidation, and moving-GC roots.
  • Keep every miss on the canonical runtime-operation path and retain exact side-exit reconstruction.

Acceptance

  • A focused loop pins exact callback histograms before and after while proving identical result, steps, exception ordering, and mutation invalidation.
  • The frozen representative_json checksum remains 324952086 and the three callback counts materially fall without increasing VM dispatch or deoptimizations.
  • Required-VM/JIT differential, moving-GC, no-GIL, and unsuppressed TSan gates pass.
  • Exact-parent base/variant/control evidence shows no unrelated regression.

Guardrails

No workload/source recognition, global freezing, skipped observable lookups, disabled callbacks, changed thresholds, enlarged fixed scratch, or benchmark-only fast path.

9 days ago

Checkpoint landed in ef1c4d7 (perf(jit): read attributed property slots directly). The optimizer now distinguishes attrs-only cold metadata from observable accessors/exotics and reads exact shape-proved values from either inline or external slot storage. Frozen real-GC representative_json (jobs=2200): checksum 324952086 unchanged; get_prop callbacks 480,215 -> 1; aggregate runtime callbacks 1,440,643 -> 960,429; VM dispatches 9,224,978, OSR entries 17,113, and deopts 17,113 unchanged. Focused real-GC and unsuppressed-TSan attributed-property, inherited-cache, parallel-mode, and Thread.restrict tests pass. Next: guarded stable load_var.

9 days ago

Second checkpoint landed in 022ceb1 (perf(jit): read stable root globals directly). The first canonical load_var callback now release-publishes an artifact-owned, pointer-free root-global proof; later executions acquire it and guard isolated mode, exact root Environment identity, realm global identity, ordinary-object state, exact shape, and live external-slot storage before reading the current value. Shape/accessor/shared-mode misses retain the canonical callback. Publication uses an atomic first-writer claim.

Exact-parent ReleaseFast attribution used real zig-gc 0285ef8:

  • representative_json: checksum 324952086; load_var 480,214 -> 2; aggregate callbacks 960,429 -> 480,217; get_prop 1, call_with_this 480,214, VM dispatch 9,224,978, OSR/deopts 17,113/17,113 unchanged.
  • representative_json_variant: checksum 324952086; load_var 480,252 -> 2; aggregate callbacks 960,505 -> 480,255; VM dispatch 9,228,376, OSR/deopts 17,116/17,116 unchanged.
  • JIT-disabled parent/candidate control: checksum 324952086, VM dispatch 23,184,279, zero native runtime callbacks on both.

Focused real-collector and unsuppressed-TSan probes pass for direct-read callback elimination, exact step parity, live-value rebinding, shape invalidation, accessor replacement, shared-mode cache refusal, and the existing attributed-property paths. The attribution invocation also completed 50 collections plus moving compaction (448 cells / 34,496 bytes) with the frozen checksum.

Next: reuse the existing guarded optimizer call-link for the proven JSON.stringify / JSON.parse targets; call_with_this remains the only hot callback family.

9 days ago

Landed in b40da86 (perf(jit): link stable native builtin calls).

Guard model

  • The canonical runtime callback warms an artifact-owned call link with only the stable Zig native function address; it never retains a movable GC pointer.
  • Generated code checks isolated inline-cache mode and the published link, then the narrow callback revalidates descriptor/origin/deopt metadata, the fixed 128-slot input range, the live rooted callee object, canonical native-call branch eligibility, and exact function address.
  • Every pre-effect miss returns .fallback to the ordinary runtime operation. Once the native is invoked, value/throw/OOM/trap handling uses the existing operation status path and never retries.
  • The call itself uses the factored canonical native boundary, preserving stack guard, receiver/argument order, active-native data, direct-eval/new.target behavior, host accounting, reentrancy, and exception ordering.
  • Shared mode refuses warming and consumption. Proxy/accessor/rebinding mutations return to canonical semantics.
  • The fixed scratch ABI remains 128 slots; operation inputs remain stack-map roots and the link contains no managed pointer.

The adversarial full-unit run also exposed a real tuple-publication race in the pre-existing call-link seqlock. The final protocol places version and all tuple fields in one sequentially consistent order. The unfixed test failed by stress run 6; the fixed version passed 500 consecutive runs and unsuppressed TSan.

Exact-parent attribution

Real zig-gc 0285ef8, ReleaseFast, jobs=2200, one attribution invocation per binary:

modechecksumVM dispatchOSR/deoptcallbacks parent -> candidateload/get/call candidatecollectionsmoved
representative_json3249520869,224,97817,113/17,113480,217 -> 52/1/250448 cells / 34,496 B
variant3249520869,228,37617,116/17,116480,255 -> 52/1/250448 cells / 34,496 B
JIT off control32495208623,184,2790/00 -> 00/0/050122 cells / 13,632 B

Parent call_with_this counts were 480,214 (base) and 480,252 (variant). No timing is published because other machine workloads prevented a clean-process timing gate.

Correctness gates

  • New integrated native-link tests: 4/4 pass; moving-GC checkpoint pass; receiver/argument/result/step/exception/callback and proxy/accessor/shared-mode paths covered.
  • Affected test262: JSON 165, Proxy 311, Reflect 153, call 92, Function/prototype 309 = 1,030 pass, 0 fail.
  • Required-VM witness: four subtrees fully agree; call retains exactly the same three parent divergences (tco-call-args.js, tco-member-args.js, tco-non-eval-with.js).
  • Actual no-GIL unsuppressed-TSan corpus: shared-objects/property-add.js 1/1 pass, no report.
  • Focused unsuppressed TSan: native-link, moving-GC, and concurrent publication checks pass.
  • Full two-shard unit accounting exposed two independent issues rather than #1024 semantic regressions: test-order leakage in the primitive string-length optimizer test was fixed by owning/restoring shared-cache mode; the exact-parent Promise 256-byte slab regression remains tracked in #1026. The #1024 race and every affected focused test pass after the final fix.

Independent build-harness blocker: #1025. Independent parent GC allocation-class blocker: #1026.

Sign in to comment on this issue.