ReviewOS

zig-utils/zig-js

Perf: hoist immutable literal-shape validation out of allocation loops

#74
Closed chris opened this 10 days ago ·
10 days ago

Parent: #62 Follows: #73 / 1821c8a

The post-#73 profile confirms the generic transition work is gone, but the new safe initializer validates the same immutable root-to-final shape chain and compares its property names on every object allocation. The symbolized sample attributes 237 top-of-stack samples (about 5% of the 5-second capture) to the equality routine used by those repeated checks.

Scope:

  • introduce a reusable prepared inline-literal-shape descriptor
  • validate the complete root-to-final chain, slot/count sequence, distinct non-index names, and inline capacity once when preparing the descriptor
  • keep per-object guards for a fresh empty inline-slot receiver and matching value count
  • publish values with the existing insertion barriers and final shape
  • prepare the descriptor only after the quick loop resolves its warmed immutable transitions
  • retain ordinary bytecode fallback and leave synchronized/no-GIL execution unchanged

Acceptance:

  • direct tests prove valid preparation/publication and rejection of indexed, duplicate, wrong-root, wrong-count, occupied, accessor/attribute/key-order, and non-extensible cases
  • VM optimized/ordinary exact result and step coverage stays green
  • post-change profile removes repeated name equality from the allocation hot path
  • pinned 1821c8a A/B is repeatably faster with exact checksums
  • run the full unit plus benchmark-harness suite once only after a measured win
  • commit references this issue and is pushed as Chris without coauthors
10 days ago

Implemented and pushed to main in cfed7bc.

What landed:

  • PreparedInlineLiteralShape descriptor tied to immutable Context-owned Shape metadata
  • one-time validation of root identity, exact slot/count chain, inline capacity, distinct names, and non-index names
  • per-object publication still guards the value count, empty inline storage, accessor/attribute/key-order state, and extensibility
  • insertion barriers remain on every object-valued slot
  • the quickened allocation loop prepares the descriptor after resolving warmed transitions, outside the allocation loop
  • synchronized/no-GIL execution and ordinary bytecode fallback are unchanged

Coverage explicitly rejects wrong count, wrong root, duplicate names, indexed names, occupied receivers, accessors, attributes, key-order state, and sealed receivers. Optimized/ordinary VM result bits and exact steps remain covered.

Post-change profile:

  • the 237-sample repeated equality/name-validation hot entry disappeared
  • prepareInlineLiteralShape appears only as a 23-sample invocation-level cost
  • the next avoidable local cost is per-iteration restriction checking before the already-exclusive dense replacement

Pinned 1821c8a vs cfed7bc evidence:

  • two independent batches, each seven alternating process pairs and three timed samples per process
  • combined median of process medians: 272.808875 ms -> 262.587146 ms
  • candidate won 11 of 14 pairs
  • elapsed reduction: 3.75%; throughput gain: 1.039x
  • checksum 1030552128 in all 84 timed samples

Validation:

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

Sign in to comment on this issue.