ReviewOS

zig-utils/zig-js

Perf: publish warmed fixed-shape literals in one inline-slot initialization

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

Parent: #62

The post-c4f4682 object_churn profile shows that the general 61-op loop quickening removed most dispatch cost, exposing repeated generic literal-transition work as the next avoidable bottleneck.

Fresh evidence on main:

  • 20 standard-size warmed samples, exact checksum 1030552128
  • 5-second symbolized sample top-of-stack counts: Object.appendSlot 397, Object.applyLiteralTransition 381, canonicalIndex 176, versus vm.runChunk 635
  • young-GC work remains separate and must not be bypassed

Scope:

  • add a reusable Object helper that can publish a proven fixed shape and up to the inline-slot capacity in one operation
  • require a fresh unpublished ordinary object, an exact contiguous root-to-final shape chain, non-index property names, matching slot/count metadata, and no accessor/attribute/key-order state
  • preserve insertion barriers for object-valued slots and retain real GC allocation/finalization
  • use it from the structurally recognized object-allocation loop only after its warmed literal transitions validate; otherwise fall back to ordinary bytecode
  • keep synchronized/no-GIL execution on the existing generic path

Acceptance:

  • focused tests compare optimized and ordinary execution results and exact step accounting
  • tests cover object-valued slot barrier semantics or the generic helper directly, plus rejection/fallback guards
  • full unit and benchmark-harness suites pass once after the focused checks
  • pinned clean A/B shows a repeatable object_churn improvement with identical checksums
  • compare a fresh candidate against JSC and record the remaining gap on #62
  • commit references this issue and is pushed as Chris without coauthors
9 days ago

Implemented and pushed to main in 1821c8a.

What landed:

  • reusable Object.initializeInlineLiteralShape helper for fresh exclusively-owned objects
  • complete root-to-final shape-chain validation before mutation
  • inline-slot publication with object-value insertion barriers retained
  • rejection of non-empty receivers, indexed names, stale/mismatched shapes, accessor/attribute/key-order state, and non-extensible objects
  • object_churn quickening now resolves the same warmed literal chain but publishes its three numeric slots in one operation
  • synchronized/no-GIL execution remains on ordinary bytecode

Post-change profile:

  • Object.applyLiteralTransition disappeared from the hot list
  • Object.appendSlot fell from 397 top-of-stack samples to 11
  • the next costs are VM checkpoint/dispatch and nursery collection, so those remain separate optimization work

Validation:

  • focused tests: 3/3 passed
  • full unit suite: 756/756 passed, no leaks
  • benchmark harness: 7/7 passed
  • zig fmt --check and git diff --check passed

Pinned c4f4682 vs 1821c8a A/B:

  • seven alternating process pairs, three timed samples per process
  • baseline median of process medians: 297.381125 ms
  • candidate median of process medians: 275.998917 ms
  • candidate won all 7 pairs
  • elapsed reduction: 7.19%; throughput gain: 1.077x
  • checksum 1030552128 in all 42 timed samples

Fresh candidate vs JavaScriptCore with the same seven-pair/three-sample protocol:

  • zig-js: 328.118250 ms
  • JavaScriptCore: 125.704833 ms
  • remaining elapsed gap: 2.610x
  • checksum 1030552128 in all 42 timed samples

The host had substantial unrelated background CPU load, so the paired A/B is the reliable optimization signal; the absolute JSC ratio is recorded as a fresh checkpoint, not a publication-quality report.

Sign in to comment on this issue.