ReviewOS

zig-utils/zig-js

GC: audit Object reflection and copy consumers across metadata callbacks

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

Parent: #465. Follow-up to #810; related #808 and #801. Further internal-record conversion work is tracked separately in #813.

Implemented and pushed in 81978f7b (fix(object): retain reflection state across metadata callbacks (#811)). Local validation and pushed CI run 33144524467 are complete.

Implemented

  • Retain/reload source, target, output, and descriptor operands in Object reflection/copy/integrity callers across metadata and coercion callbacks.
  • Preserve the host own-key target and both ArraySetLength coercion operands.
  • Convert public descriptors once, validate accessors in observable read order, and publish descriptor fields as own data properties in canonical order.
  • Collect all Object.defineProperties descriptors before applying any.
  • Validate nested Proxy defineProperty targets in specification order; capture preventExtensions target/handler before observable trap lookup and correctly forward revoked and length-variable TypedArray targets.
  • Keep Object.assign's required Set semantics; remove the extra descriptor observation from Object.seal.

No pinning, GC suppression, stale-address recovery, synchronization weakening, or native stack/queue/job/Promise/Worker implementation changes were used.

Measured evidence

  • Original isolated moving matrix: 5/14 pass before -> 14/14 pass after, including removal of the Object.assign abort. Expanded matrix: 30 logical cases in both forced tiers, 60 verified movements and exact pointer changes, zero required-bytecode fallback.
  • 13 ordinary semantic controls pass in both tiers and independently match Node.
  • Four no-GIL shared-realm lanes complete 64 reflection/copy/define iterations each.
  • Three deterministic fail-every-allocation sweeps restore roots, environment, and depth for assign, defineProperties, and getOwnPropertyDescriptors.
  • Focused Debug and unsuppressed ReleaseSafe+TSan each pass all 33 reflection tests and 26 existing Proxy metadata tests, with zero failures/leaks/race reports.
  • Full Debug native test-parallel gate: 2101 passed, one platform skip, zero failures/leaks, 658.2 seconds across four shards.
  • 21 upstream test262 subtrees: 4619 pass before -> 4619 pass after, every transcript byte-identical (zero measured flips/regressions in this scope).
  • Debug threadfuzz: 400 default + 300 verify programs from seed 1, zero failures.

Unoptimized local Debug+TSan focused runs were cancelled for instrumentation cost and are not counted as passes; ReleaseSafe+TSan completed with TSAN_OPTIONS=halt_on_error=1 and no suppression file. CI retains the full repository TSan configuration.

Exact binaries, hashes, per-shard plan/logs, before/after transcripts, and reproduction sources are retained at /Users/chris/.cache/zig-js-reflection.iP8bKP. All superseded compiler caches were removed; retained evidence is about 205 MB.

Completed integration (2026-08-28 UTC)

Implementation: 81978f7b. The measured local evidence above and in the linked implementation comments remains unchanged.

  • Complete pushed integration: CI 33144524467 at descendant 81978f7b completed successfully: 53 jobs passed, one scheduled-only job skipped, zero failures. This supersedes earlier pending, cancelled, or failed integration reports; those earlier runs are not counted as successful gates.

Closing this implemented issue as completed. Parent-roadmap work and independently tracked follow-ups remain open; this closure does not claim those broader scopes are finished.

9 days ago

Confirmed against the pushed #810 fix (0ad2b5d): 14 isolated ReleaseSafe moving tests each match exactly one linked test; five logical cases pass and nine fail. Failures cover getOwnPropertyNames/Symbols, Object.keys ownKeys/descriptor callbacks, Object.assign ownKeys/get/set, and Object.defineProperty key/descriptor conversion. assign_get aborts (134); define_field also reports leaked allocations. Each successful test verifies both forced tiers and actual movement; a first-mode failure does not count a second mode. Five of six ordinary semantic controls also fail (own descriptor-map publication, getter validation order, nested defineProperty invariant/order, and arrow-function descriptor lookup invoking an inherited getter); the non-moving revocation control passes. Node matches all 20 expected controls. Only tests are added so far; no caller implementation change or workaround. Evidence: /Users/chris/.cache/zig-js-reflection.iP8bKP .

9 days ago

Implementation and focused ReleaseSafe evidence are now complete locally (not yet committed):

  • 30 isolated actual-moving logical cases pass in both forced tiers: 60 verified movements, exact pointer changes, zero required-bytecode fallback. This includes the original nine failing callers plus descriptor conversion, nested Proxy validation, defineProperties/create, and integrity operations.
  • 13 ordinary semantic controls pass in both tiers and independently match Node. The integrity audit also found absent-trap forwarding to revoked / length-variable TypedArray targets and an extra descriptor observation during Object.seal.
  • Four no-GIL shared-realm lanes × 64 reflection/copy/define iterations pass.
  • Three deterministic fail-every-allocation sweeps (assign, defineProperties, getOwnPropertyDescriptors) restore temporary roots, environment, and depth; existing Proxy ordering/OOM regressions also pass.
  • 18 focused upstream test262 subtrees: 4487 pass before → 4487 pass after, with byte-identical transcripts (0 measured flips, 0 regressions in that scope).

Debug and unsuppressed TSan builds are running next, followed by the full Debug unit integration gate. Native stack/queue/job and Promise/Worker implementations remain untouched. Evidence: /Users/chris/.cache/zig-js-reflection.iP8bKP.

Sign in to comment on this issue.