ReviewOS

zig-utils/zig-js

VM: lower bare identifier deletion across tiers

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

Parents: #465, #713 Related: #716, #491

Problem

#713 lowered property/value deletion and #716 lowered SuperReference deletion, but delete identifier remains the final DeleteExpression admission barrier. Generator, async, and async-generator bodies cannot fall back after suspension, while plain functions currently reject even statically non-deletable frame locals.

Identifier deletion resolves an Environment Record reference rather than an object expression. Exact behavior distinguishes frame/upvalue bindings, declarative and deletable eval bindings, global object bindings, unresolvable references, and active with object environments including Symbol.unscopables and proxy traps.

Scope

  • Add an owned name-deletion bytecode operation for program and function chunks.
  • Fold statically resolved frame/upvalue deletion to false when no activation-local environment can shadow it.
  • When block/catch/with environments are active, search exactly the compiler-recorded activation environment depth before falling back to a non-deletable frame/upvalue binding; never consult an outer captured with past that boundary.
  • Fully resolve name-backed generator/async/global bindings, deletable eval bindings, global own properties, and unresolvable references.
  • Preserve proxy/Symbol.unscopables ordering, configurable attributes, abrupt traps, suspension, moving GC, and cached native-tier rejection.
  • Share one exact runtime name-deletion helper with the tree-walker rather than duplicating environment semantics.

No-workaround rules

  • No source rewriting, eval callback, tree-walker dispatch disguised as bytecode, guessed scope cutoff, global-only special case, swallowed proxy trap, or broad function fallback.
  • No activation scratch, stacks, queues, jobs, Promise/microtask, Worker lifecycle, or Map/Set iterator implementation changes.

Acceptance

  • Program, plain, generator, async, and async-generator admission/runtime coverage spans local/upvalue, declarative, deletable eval, global, unresolvable, and nested with references.
  • Ordering witnesses cover proxy has/delete traps, Symbol.unscopables, abrupt completion, configurable attributes, suspension, and moving GC.
  • Focused compiler/VM/frontend, full units, exact relevant Test262, and applicable TSan gates pass with exact accounting.
  • Landing commit and parent issues are cross-linked with quantified evidence.
9 days ago

Implementation is in progress. delete_name now distinguishes full Environment/global resolution from a compiler-bounded activation-environment search before statically known frame/upvalue bindings. Nested functions accumulate only the exact runtime Environment Records between frames, so an active with may shadow an upvalue without consulting captured environments behind that slot. The tree-walker and VM share one Environment Record deletion helper.

Evidence so far:

  • focused #717: 4/4 pass, 0 fail/leak (plain differential, resumable generator/async/async-generator through moving GC, compiler operand boundaries, cached native rejection)
  • broad deletion: 37/37 pass, 0 fail/leak, including all prior property/SuperReference/global/eval/proxy/shape/parallel deletion coverage

TSan, frontend, full units, and exact Test262 accounting remain in progress.

9 days ago

Landed in c8e1b0c0 (feat(compiler): lower identifier deletion (#717)).

Evidence:

  • focused #717: 4/4 pass normally and 4/4 under TSan; 0 failures, leaks, or race diagnostics
  • broad deletion: 37/37 pass
  • production frontend: 12/12 pass
  • full units: 1,837 pass, 1 skip, 0 fail, 0 leak across six shards
  • exact detached parent e051fc45 runner SHA-256 5401308b8efa… vs landing candidate SHA-256 ad1b3fa9c7f…: test/language/expressions/delete 69/69 -> 69/69, byte-identical transcripts, 0 flips, no regressions; both runs retained only after continuous one-second overlap monitors stayed clear

The implementation uses compiler-owned frame/environment depth boundaries, adds no activation scratch, and leaves the independent plain-frame arguments policy barrier unchanged.

Sign in to comment on this issue.