ReviewOS

zig-utils/zig-js

Intl.ListFormat: publish immutable resolved state

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

Parent: #475 Related benchmark/evidence: #460

Problem

Intl.ListFormat validates type and style at construction but stores the normalized values in a hidden ordinary object. Every format, formatToParts, and resolvedOptions call rereads that bag, while formatting also rereads the hidden locale. The resolved formatter state is immutable and should not pay generic named-property synchronization on its hot path.

The existing representative_intl_list_format_parts boundary performs 6,400 warmed formatToParts calls and consumes every part type/value byte. Current zig-js and system JSC agree on checksum 515925585. Exact-parent zig-js attribution for one 100-job invocation is:

  • property-lock acquisitions: 4,706,794
  • backing allocations: 2,439,308 / 335,620,156 bytes
  • current backing: 72,844,632 bytes; peak: 74,926,278 bytes
  • GC cells: 1,390,458; collections: 51

Single diagnostic samples were 479.7 ms in zig-js and 31.5 ms in system JSC; these are diagnostic only, not publication evidence.

Scope

  • Publish locale, type, and style atomically into an object-owned immutable native record after observable option reads complete.
  • Make format, formatToParts, and resolvedOptions consume that record directly and use the native slot as the receiver brand.
  • Preserve GetOptionsObject behavior, option order/coercion, iterator acquisition/draining/closing, output and part metadata, subclasses, and error ordering.
  • Account/finalize the record through the bounded backing allocator; cover OOM, bounded heap, moving GC, and concurrent read safety.
  • Compare exact-parent timing and attribution at the frozen checksum.

Acceptance

  • No hidden ordinary options bag remains on newly constructed ListFormat objects.
  • Focused ListFormat/test262, Intl402, OOM, GC movement, concurrent read, TSan, and full unit gates pass.
  • Exact-parent comparison reports checksum equality and quantified retained changes; retain only a real improvement.
  • No ICU/system-JSC runtime dependency, global mutable cache, skipped observable hook, or repro-specific shortcut.
9 days ago

Completed on main in 6f8e770c.

ListFormat now publishes object-owned, GC-finalized immutable locale/type/style state after all observable option reads. format, formatToParts, and resolvedOptions consume the native record directly; newly constructed formatters have no hidden ordinary options bag, and forged hidden properties no longer establish the brand. Iterator acquisition/draining/closing behavior remains on the original ordered path.

Exact-parent evidence at checksum 515925585:

  • property locks: 4,706,794 -> 4,629,990 (-1.63%)
  • backing allocations: 2,439,308 -> 2,439,307
  • GC cells: 1,390,458 -> 1,390,455
  • current/peak backing: -1,266 bytes each
  • paired timing was high-variance and established no throughput improvement (no throughput claim)

Validation: ListFormat test262 81 -> 81; full Intl402 3,341 -> 3,341; focused normal and TSan 3/3; bounded-heap, moving-nursery, and shared-realm structural probes pass; full units 1,689 pass / 1 skip / 0 fail / 0 leak.

Sign in to comment on this issue.