ReviewOS

zig-utils/zig-js

JSON: transfer escaped decode buffers into string values

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

Parent: #473 Related: #480

Defect

The JSON string parser correctly borrows unescaped source slices, but an escaped string value still decodes into an owned arena buffer and then calls Value.strAlloc, allocating and copying the complete decoded bytes a second time into its string cell. Wide escaped-string inputs therefore retain both the temporary decode storage and the runtime copy for the life of the arena.

Property names have a different ownership boundary because shapes establish key storage; this issue targets value strings only and must not make shape keys alias parser scratch.

Implementation

  • Return explicit borrowed-versus-owned string parse results.
  • Copy borrowed source text once into the runtime string cell.
  • Transfer owned escaped decode buffers through Value.strOwned with no second byte copy.
  • Preserve JSON source-text slices, WTF-8/lone-surrogate decoding, malformed escape rejection, and OOM propagation.

Acceptance

  • Allocator witnesses distinguish the borrowed and owned paths and prove the escaped value avoids the redundant byte allocation.
  • Escaped keys and values, surrogate pairs/lone surrogates, controls, reviver context.source, OOM, and malformed syntax remain covered.
  • Focused normal + TSan, full unit, and JSON.parse test262 pass with zero regressions.
  • Exact-parent escaped-string evidence records CPU and memory impact without unsupported claims.
9 days ago

Decision: rejected and reverted after production exact-parent measurement.

Why it was rejected: the active precise-GC engine decodes parser scratch through a cheap arena, while managed StringCell bytes use the realm backing allocator. Moving incremental escape decoding to that backing allocator removed a conceptual copy but introduced allocator growth/shrink cost. Seven order-balanced exact-parent pairs measured 1.021x wall time, 1.0017x instructions, 1.0087x cycles, and 30.8 MB vs 29.5 MB median peak RSS. A bounded one-reservation pre-scan was also tested locally; it remained instruction-negative and was not landed.

All checksums matched, no samples were discarded, and JSON.parse test262 remained 77/77. The benchmark stays to evaluate a future owned string-builder design, but the regressive engine abstraction does not. Closing as not planned because the stated transfer is not a production win under the engine current allocator contract.

9 days ago

Follow-up stringify work #557 is complete. a7da43f4 bulk-appends ordinary output runs without changing escaped decode or WTF-8 ownership; 6dbe188f includes exact Unicode, mixed-escape, and lone-surrogate controls.

Sign in to comment on this issue.