ReviewOS

zig-utils/zig-js

Date: format string conversions into one owned buffer

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

Parent: #475 Related: #460, #461, #480, #493

Problem

Date.prototype.toDateString, toTimeString, and toString currently enter one shared branch that formats both date and time halves before selecting the result. The selected half is then copied into a StringCell, while full toString concatenates a third arena buffer. toUTCString also allocates a temporary year string before its final output. In precise-GC contexts, an arena-formatted final buffer is copied again into realm-owned managed-string storage, so repeated conversions retain avoidable high-water backing until Context teardown.

Scope

  • Format toDateString, toTimeString, toString, toUTCString, and Annex B toGMTString directly into exactly one result byte buffer.
  • Render the year through bounded native storage so ordinary and extended years do not require a temporary allocation.
  • In precise-GC realms, allocate the result from the exact realm-owned backing allocator and transfer it into the managed StringCell; preserve arena ownership for standalone/non-GC interpreters.
  • Keep invalid-date behavior, UTC/local method routing, exact punctuation/padding, negative and six-digit years, and GC movement semantics unchanged.
  • Add deterministic 1K/2K/4K conversion rows that exercise every affected method and an unrelated Date getter control. Preserve cross-engine checksum equality by scoring only specification-stable UTC/date/time prefixes while still constructing every complete result.

No-workaround rules

  • No cached output, shared mutable formatting buffer, hard-coded benchmark result, skipped conversion, locale/time-zone omission, or benchmark-only engine path.
  • No borrowed pointer may outlive native storage; OOM must leave ownership exact and leak-free.

Acceptance

  • Each successful affected conversion owns one final byte buffer and one managed string cell, with no retained intermediate arena buffer in precise-GC mode.
  • Existing Date test262 remains regression-free; focused invalid, extended-year, alias, OOM, moving-GC, no-GIL, and TSan witnesses pass.
  • Exact-parent 1K/2K/4K instruction/wall evidence, 4K retained-RSS evidence, and allocation attribution are checked in under docs/.data/ with exact checksums.
  • The unrelated Date getter control remains neutral and all public claims identify exact parent/candidate revisions.
9 days ago

Benchmark parent landed as 9c840f80. The 1K/2K/4K all-conversion rows match JavaScriptCore at checksums 4,165,907 / 8,339,572 / 16,699,331; the 4K getter control matches at 8,360,941. Current zig-js single-context wall grows from about 56 ms to 211 ms across the widths, so the retained intermediate formatting work is directly visible before the engine change.

9 days ago

Completed on main.

Commits:

  • 9c840f80 and cdabd71f: deterministic cross-engine 1K/2K/4K six-result rows and getter control.
  • 0b01b789: bounded native year/ISO rendering and one directly transferred realm-owned result buffer for toDateString, toTimeString, toString, toUTCString/toGMTString, toISOString, and Date-fast toJSON.
  • 3a5fc50d: exact allocation-zero/allocation-one OOM cleanup witness.
  • c7705224: raw and rendered exact-parent evidence.

The scored 4K attribution removes 158,851,286 bytes (97.5%) of new retained Context backing and all 215 backing-growth events while preserving exactly 487,427 GC-cell allocations / 60,818,048 cell bytes. The ordinary 4K row records stable peak RSS at 0.9670x. Its separate retained-RSS observer is intentionally non-directional because parent/candidate RSD is 37.00%/43.95%; the noisy samples remain checked in. The unrelated getter control is 0.9987x instructions and 1.003x wall.

Validation: the implementation full unit run passed 1,568 with 1 skipped, 0 failed, and 0 leaked; Date test262 remains 594/594; moving nursery, 4 MiB reclamation, extended-year/invalid/alias semantics, focused no-GIL TSan, and the independent two-allocation OOM witness pass. Benchmark publication and allocation-arithmetic gates pass. The unrelated BunPress 0.1.21 to 0.2.0 manifest boundary discovered by the docs gate is isolated in #527.

Sign in to comment on this issue.