ReviewOS

zig-utils/zig-js

VM: quicken monomorphic Number arithmetic sites

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

Parents: #498, #461 Related: #481, #493, #659

Problem

Ordinary bytecode already computes Number/Number binary operations inline, but every execution still merges instruction-local optimizer profile atomics, rechecks the full operand-kind decision, and enters one large generic opcode switch. A stable numeric site never publishes a VM-owned specialized dispatch state, while the generated quickening inventory therefore correctly keeps arithmetic-dispatch unsupported. On restricted hosts this cost remains permanent because no native tier can replace the site.

Scope

  • Freeze explicit single-context no-JIT/required-bytecode benchmark and attribution modes; native publication must remain provably zero.
  • Add representative stable Number arithmetic rows covering add/subtract/multiply/divide/remainder/power, relational/equality, bitwise, and shifts, plus BigInt, string-concatenation, object-coercion, exceptional, and Number-to-polymorphic controls.
  • Add one instruction-indexed, race-free adaptive arithmetic state table owned by each immutable Chunk. Stable Number sites may publish a Number-specialized state after a bounded observation threshold; unsupported/polymorphic sites publish an explicit generic state.
  • Preserve bytecode immutability. A specialized miss must execute the exact ordinary operation once, record the changed operand kinds, and dequicken without replaying coercions or effects.
  • Preserve Number edge cases, BigInt mixing errors, ToPrimitive ordering, string concatenation, Symbol errors, shifts, NaN/signed zero/infinity, debugger/step/watchdog accounting, exception/finally resumption, moving GC, OOM, and optimizer guard correctness.
  • Keep metadata bounded at one compact atomic state per instruction and expose exact hit/miss/dequickening counters for tests and attribution.

No-workaround rules

No source/workload recognizer, benchmark-only branch, disabled profiling globally, mutable bytecode rewriting under shared execution, assumed Number inputs, skipped coercions, cached results, hidden warmup, executable mappings in no-JIT mode, or tree-walker callback presented as quickening. No stacks, queues, jobs, Promise, microtask, Worker-lifecycle, or Map/Set iterator changes.

Acceptance

  • Benchmark-first rows preserve exact checksums, bytecode admission, opcode counts, and allocation replay with native publication zero.
  • Stable Number sites quicken after the declared threshold; polymorphic/unsupported sites remain generic and one miss dequickens exactly once without effect replay.
  • Forced tree-walker, ordinary VM, quickening-off, and quickening-on results match across every operator/control, including exceptions, steps, debugger, OOM, and termination.
  • Per-site state publication is race-free under no-GIL/TSan, bounded under attacker-sized bytecode, and reset by Chunk teardown.
  • Full units, focused TSan/threadfuzz, relevant arithmetic/coercion Test262, docs/inventory gates, and exact before -> after accounting pass.
  • Exact-parent no-JIT evidence demonstrates reduced dispatch/profile work without regressing polymorphic controls or claiming native-tier throughput.
9 days ago

Benchmark-first foundation landed in 7d69d613 (bench(vm): add no-jit arithmetic witnesses (#734)).

What is now frozen:

  • explicit single_no_jit and attribution_no_jit modes create a GC-enabled Context with native tiers disabled and required-bytecode admission;
  • stable Number, stable BigInt, Number/string/BigInt/object polymorphic, and observable coercion/exception rows at 100 and 10,000 jobs;
  • exact quick/full checksums: Number 606036 / 5236590351, BigInt 5412345 / 630334997, polymorphic 29422 / 28806122, coercion 101766 / 10176362;
  • full-work VM dispatch baselines: 3,020,460 / 900,541 / 1,180,600 / 810,659 respectively;
  • every full row has 28 VM entries, nonzero compiler admissions, zero tree-walker entries, zero baseline/optimizer publications, and zero generated-code bytes;
  • two consecutive attribution replays per row produced identical admission and Context-backing/GC-cell allocation inventories.

Local gates: comparison runner build; complete benchmark-comparison harness; V20 manifest validation; 33/33 structural rejection tests; 50-page docs render with pinned output manifest; 277-file offline link audit; all eight checksum replays and all four attribution contracts.

This is structural benchmark evidence only. The host is on battery with a competing Home build, so no timing was retained and no performance claim is being made. I am leaving the acceptance box open until the implementation exact-parent A/B proves the intended dispatch/profile reduction while preserving the controls.

9 days ago

Implementation landed in 7006c058 (perf(vm): quicken monomorphic Number sites (#734)).

Implemented contract:

  • one byte-sized acquire/release QuickBinaryState per immutable instruction, arena-owned by the Chunk;
  • Number publication after exactly eight Number/Number observations;
  • terminal generic publication after any dynamic observation;
  • specialized misses record changed operand kinds, atomically dequicken once, and invoke the canonical operation exactly once with no prior coercion;
  • exact Context-owned Number hit, miss, and dequickening attribution, with a test-only quickening-off differential and no production disable option.

Full 10,000-job attribution replay:

  • Number: checksum 5236590351, 28 VM entries, 3020460 dispatches, 919643 quick hits, 0 misses, 0 dequickenings;
  • BigInt control: checksum 630334997, 28 VM entries, 900541 dispatches, 79982 quick hits, 0 misses, 0 dequickenings;
  • polymorphic control: checksum 28806122, 28 VM entries, 1180600 dispatches, 164905 quick hits, 0 misses, 0 dequickenings;
  • coercion/exception control: checksum 10176362, 28 VM entries, 810659 dispatches, 157437 quick hits, 0 misses, 0 dequickenings.

Every row retains zero tree-walker entries, baseline/optimizer publications, and generated-code bytes. vm_quick_kernel_hits exactly equals the Context quick-hit count. Before to after Chunk backing changes are 24 / 36 / 24 / 24 bytes across the four rows; all checksums, admissions, dispatches, and GC-cell inventories remain exact.

Semantic and concurrency evidence:

  • tree-walker vs required VM quickening-off vs quickening-on matches every arithmetic, comparison, bitwise, shift, and in operator, plus signed zero, NaN/infinity, BigInt mixing, string concatenation, Symbol failure, and observable coercion;
  • on/off VM dispatch counts are exact, and three deliberately specialized dynamic misses produce exactly three misses and three dequickenings;
  • 802 -> 802 Test262 passes across 21 relevant expression subtrees, 0 flips;
  • full Debug units: 1870 passed, 1 skipped, 0 failed/leaked;
  • full TSan units: 1868 passed, 2 skipped, 0 failed/leaked; the added all-operator differential also passes focused TSan;
  • default and TSan threadfuzz: 400 seeded programs each, 0 failures;
  • benchmark harness, V21 manifest, 39/39 fail-closed matrix mutations, quickening inventory/self-test, 277-file link audit, and 50-page docs manifest all pass.

No timing claim is being made. The host became AC-powered, but a user-owned Zig build and system indexing saturated it, so exact-parent order-balanced timing was not retained. I am keeping #734 open only for that quiet-reference A/B and will not publish a throughput result from contaminated samples.

9 days ago

The audited collection path is now ready in a6e83039:

  • tools/exact-parent-regression.ts now preserves the frozen single_no_jit mode identity and has a structural argument-contract test.
  • representative matrix V22 hash-inherits every V21 scored row/profile and re-pins only that collector change.
  • zig build benchmark-comparison-test passed all 32 steps and 4 tests; matrix structural tests remain 39/39.
  • flips 0 Test262 cases (tooling/docs only).

The actual 7006c058 versus exact parent 7d69d613 measurement remains open. I rejected collection on the current host because it is drawing from battery and a separate conformance process is consuming CPU; those conditions violate the issue's quiet-reference AC acceptance boundary. No contaminated ratio will be published.

9 days ago

Frozen binary preparation is now complete for the remaining exact-parent run:

  • parent 7d69d613abb29a7fd7220150afbe844fd5bfb738: cb13e5f888e6f461d975d5a4287e581bfec9f94c1f6d41f926fadfb9c9f2238d
  • candidate 7006c058e7348598627b5d230a70910d9b0a4a04: 4c1d5d929c9388bf5d1a5b5e714caf9f12386b50b1f15db7ab2f5ad9bcd1b693
  • Zig: 0.17.0-dev.1441+d5181a9c9, ReleaseFast
  • arithmetic source is byte-identical on both sides: 970e58bec6ab9978335e6f908219bf23154c9ec9ff96ccefc6a94f2917d77fa8
  • the frozen 100-job single_no_jit stable-Number contract returns checksum 606036 on both binaries.

Those checksum probes are validation only: the host is still on battery and a persistent BunPress development server is active, so their elapsed/counter values are discarded. Seven-pair quiet-reference AC collection for the stable Number row and the BigInt/polymorphic/coercion controls remains pending; no performance ratio is claimed here.

9 days ago

CI follow-up landed in 8b00e5bc (docs(site): refresh BunPress output manifest (#734)).

The first V22 push's docs-link step passed, but docs:build correctly rejected the stale BunPress 0.2.13 output manifest after the owner-maintained renderer advanced to 0.2.14. I rendered the same current docs with both revisions before accepting the change:

  • all 50 HTML pages differ only by the upstream code-block foreground/alignment CSS fix;
  • the search index retains the exact same 366-entry multiset, now deterministically ordered;
  • the regenerated manifest covers 54 outputs;
  • the checked BunPress 0.2.14 build succeeds with 50 pages.

Flips 0 Test262 cases. The exact-parent performance collection remains separately gated on quiet AC power.

9 days ago

CI follow-up landed in eee03429: the dependency inventory now classifies docs/.data/representative-benchmark-matrix-v22.json as an audited caller of tools/exact-parent-regression.ts.

The exact failing gate now passes locally: zig build dependency-audit reports 16 classified dependency edges, 0 migration targets, and 62 classified repository tools. Flips 0 Test262 cases.

9 days ago

Landed ci(docs): pin BunPress 0.2.14 (#734).

The failed docs job was comparing the checked v0.2.14 render manifest against CI's stale immutable v0.2.13 checkout. The commit advances both CI and every audited dependency pin to BunPress v0.2.14 (226414abe51a3c539aa27db79c3c7c3bb23fa34f).

Validated locally:

  • zig build dependency-audit: 16 classified edges, 0 migration targets, 62 classified repository tools
  • BunPress v0.2.14: 50 pages match docs/.data/bunpress-output-v1.json
  • zig build docs-link-check: 277 files, all links resolve
  • test262 flips: 0
9 days ago

Rebuilt the exact ReleaseFast runners after the earlier temporary binaries expired:

  • parent 7d69d613abb29a7fd7220150afbe844fd5bfb738: 0478d4da19c54c704cb017e99a440988ad12825ef33dddb18f5d43e78746ae4e
  • candidate 7006c058e7348598627b5d230a70910d9b0a4a04: 18506bcc5d483caa4aab090147db8f884c9adb5193c706fa41f11b582dadabc7
  • zig-gc: 89b6652c81ba892119b7b9ce3b0d07fc78a009ff
  • zig-regex: 87e9ca28fa14194dd1e8b4cae7461e179331efca
  • Zig: 0.17.0-dev.1441+d5181a9c9; source SHA-256 remains 970e58bec6ab9978335e6f908219bf23154c9ec9ff96ccefc6a94f2917d77fa8
  • both 100-job validation probes retain checksum 606036.

The first 10,000-job quiet-reference collection attempt was rejected on its first parent process because measured whole-process CPU occupancy was 50.0%, below the audited 60% floor. The collector created no JSON/Markdown artifact, so no sample was retained, discarded, or used for a ratio. A separate Home Zig checker sequence is again consuming the machine; collection remains paused until the process-quality guard is genuinely clear.

9 days ago

The required benchmark harness itself now has a CI-duration defect tracked in #765. On CI 32890815195, its self-tests progressed through instrumentation-overhead, then the job was automatically cancelled at the gate matrix's exact 60-minute limit while all 52 other required jobs were green. #765 requires attribution and a within-budget structural fix; timeout inflation or omitted validators is explicitly excluded.

9 days ago

Completed and pushed directly to main:

Exact-parent result for fd6747c6 versus first parent 9333b985, seven alternating quiet-reference AC pairs, required bytecode, native tiers disabled:

  • stable Number: wall 389.271 -> 370.190 ms (0.951x), instructions 0.9493x, cycles 0.9548x, process energy 0.9396x, exact allocation replay;
  • polymorphic and observable-coercion controls: pass with stable efficiency evidence and no material regression;
  • BigInt control: wall remains explicitly inconclusive_noise at 5.96% / 12.98% RSD, while instructions/cycles/energy are each stable and within 0.28% of the parent; the collector records no publication block.

Semantic/concurrency validation: current Test262 arithmetic/comparison/bitwise/shift differential 837 -> 837 across the historical 21 subtrees, 0 failures/flips; full Debug units 2236 passed, 1 skipped; focused TSan quickening tests; default and TSan threadfuzz 400 seeded programs each; benchmark harness 18/18; matrix mutations 70/70; 313-file docs link audit; checked 50-page docs build.

Remote main is verified at 4d347739524d44fd1f4ae64096f2e9a786a20c22. All #734 acceptance items are complete.

Sign in to comment on this issue.