ReviewOS

zig-utils/zig-js

Frontend: borrow unescaped private names

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

Parent: #496 Related: #493, #460, #461, #537, #538

Problem

The lexer already borrows ordinary IdentifierName source slices, but every private name takes a separate unconditional allocPrint("#{s}") path. Plain #field declarations, reads, writes, brand checks, methods, and accessors therefore allocate and copy bytes even though their exact token spelling is already a stable slice of Context-owned source. Private-heavy generated classes amplify this into proportional parse-arena traffic.

Scope

  • Add parser-only 1K/2K/4K plain private-field growth rows with frozen source construction, exact member-name/index validation, warmup, and timed parse boundary; retain an escaped-private control.
  • Return the exact #name source slice when the underlying IdentifierName contains no escape.
  • Preserve owned # + decoded-name construction for escaped private names.
  • Preserve private declaration/use matching, duplicate/accessor rules, brand checks, source positions, Unicode, diagnostics, and source lifetime.

Security and correctness

  • Borrowed private-name slices may not outlive Context-owned source.
  • Escaped names must remain exact decoded bytes with failure-atomic OOM propagation.
  • Do not special-case benchmark names, weaken private-name early errors, globally intern attacker-controlled names, or change class element ordering.

Acceptance

  • Benchmark source and exact member-name structural checks land before lexer changes.
  • Pointer/allocation witnesses prove plain private tokens are source-backed and escaped private tokens remain owned/decoded.
  • 1K/2K/4K rows show bounded near-linear work and materially lower allocation/instruction cost versus the exact parent; escaped control remains semantically exact.
  • Lexer/parser/frontend suites, private field/method/accessor/brand/eval cases, malformed/OOM diagnostics, forced execution paths, full units, and affected test262 private-name subtrees pass with no regressions.
9 days ago

Benchmark design exposed a dominant prerequisite tracked as #540: private-name duplicate validation is currently O(N²) for one real private-heavy class. #539 now depends on #540 so its zero-copy evidence is not hidden behind that adversarial parser cost. I will land the collision-independent duplicate-validation bound first, then measure the exact private-token allocation change against that corrected parent.

9 days ago

Dependency #540 is complete on main in f888b717.

The private-name benchmark rows now measure lexer/token/AST work without the prior quadratic duplicate-validation confounder. The exact decoded-name collision matrix, source ordering, and scratch OOM behavior are frozen, and the candidate validation path has a deterministic O(N log N) bound.

I am resuming this issue against f888b717 as its exact parent: plain private names should borrow the complete #name source slice, while escaped names must retain owned decoded construction and failure-atomic OOM behavior.

9 days ago

Completed on main in 8cd6034f, after dependency #540 established the bounded private-name validation baseline.

Plain private IdentifierName tokens now borrow their complete #name source slice. Escaped private names retain the owned decoded path, exact raw offsets, and failure-atomic OOM behavior.

Ownership witnesses:

  • #plain_π succeeds with a zero-byte allocator and its token pointer equals the source pointer.
  • escaped #priv\u0061te returns owned #private bytes with a distinct pointer and exact raw pos/end.
  • the same escaped token reports OutOfMemory with a zero-byte allocator.

Seven order-balanced exact-parent pairs against f888b71 (ReleaseFast, one timed parse after ten warmups, frozen checksums):

  • 1,024 plain fields: retired instructions 0.907x; peak footprint 0.868x; maximum RSS 0.898x.
  • 2,048: instructions 0.883x; footprint 0.811x; RSS 0.847x.
  • 4,096: instructions 0.870x; footprint 0.794x; RSS 0.821x.
  • diagnostic timed-parse medians: 0.105 -> 0.089 ms, 0.221 -> 0.185 ms, and 0.436 -> 0.395 ms. Wall samples contained outliers, so the CPU-work claim relies on the stable retired-instruction counter.
  • escaped 4,096 control: 1.0003x instructions, 0.994x cycles, identical median memory.

Correctness gates:

  • affected test262 class-element surface: 2,962 pass -> 2,962 pass; flips 0, regressions 0.
  • private unit surface: 92/92.
  • lexer TSan: 11/11.
  • focused frontend: 12/12.
  • full sharded units: 1,599 passed, 1 skipped, 0 failed, 0 leaked.

Sign in to comment on this issue.