ReviewOS

zig-utils/zig-js

Intl.RelativeTimeFormat: publish immutable resolved state

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

Parent: #475 Related benchmark/evidence: #460

Problem

Intl.RelativeTimeFormat validates options at construction but stores normalized values in hidden ordinary properties. Every format, formatToParts, and resolvedOptions call then traverses generic object storage again for locale, numbering system, style, and numeric mode. This adds locking/allocation pressure to a formatter whose resolved state is immutable after construction.

The already-committed representative_intl_relative_time_format_parts boundary performs 6,400 warmed formatToParts calls and consumes every part type/value/unit. On current main, zig-js and system JSC agree on checksum 9262214. Exact-parent zig-js attribution for one 100-job invocation is:

  • property-lock acquisitions: 2,338,798
  • backing allocations: 1,480,915 / 206,315,223 bytes
  • current backing: 50,018,290 bytes; peak: 52,881,058 bytes
  • GC cells: 795,273; collections: 30

A single diagnostic sample was 359.3 ms in zig-js versus 22.2 ms in system JSC; this is diagnostic only, not publication evidence.

Scope

  • Publish locale, resolved numbering system, style, and numeric mode atomically into an object-owned immutable native record after all observable option reads complete.
  • Make steady formatting and resolvedOptions consume that record directly.
  • Preserve ECMA-402 option observation/coercion order, Unicode extension precedence, output, parts metadata, receiver branding, 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 RelativeTimeFormat objects.
  • Focused RelativeTimeFormat/test262, Intl402, OOM, GC movement, concurrent read, TSan, and full unit gates pass.
  • Exact-parent benchmark 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 a3400953.

The formatter now publishes an object-owned, GC-finalized immutable record containing resolved locale, numbering system, style, and numeric mode after all observable option reads. format, formatToParts, and resolvedOptions consume that record directly; the generic hidden options bag is gone, the native slot is the receiver brand, and constructor/reflection share one numbering-system resolver.

Exact-parent evidence at checksum 9262214:

  • property locks: 2,338,798 -> 2,223,594 (-4.93%)
  • GC cells: 795,273 -> 795,270
  • current/peak backing: -144 bytes each; backing allocation count unchanged
  • 7-sample medians: 297,982,792 -> 299,063,542 ns (flat/no throughput claim)

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

Sign in to comment on this issue.