ReviewOS

zig-utils/zig-js

Globals: keep lexical bindings out of property lookup

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

Parent: #465 Related: #498, #1060, #1061

Ordinary Get on the global object falls back to the root environment when the property chain misses. This exposes declarative global lexical bindings as properties and revives deleted builtin properties.

Executed seven-assertion probe: Node returns all true. The saved before binary returns false,false,false,true,true,true,false in both tree and required-bytecode modes. Global let, const, and class values are visible through globalThis despite having no property; deleting globalThis.Math still returns the environment's Math value. Real var/function global properties already work.

Acceptance:

  • Remove environment lookup from global-object Ordinary Get; keep identifier resolution and declarative bindings separate.
  • Preserve actual startup globals and global var/function properties, including eval-created variables and later evaluate calls.
  • Pin lexical/TDZ separation, own/inherited descriptors, undefined-vs-absence, deletion, and local shadows against Node.
  • Normal/unsuppressed TSan, required-bytecode isolated/shared contexts, and exact before/after global/declaration corpus checks pass.
9 days ago

Fixed in fd5baca.

Ordinary Get on the global object no longer consults the root environment after a property miss. Lexical let/const/class values and TDZ state remain separate from object properties; deleted builtins are not revived. Actual startup, var/function, eval-created, and accessor/descriptor properties retain their behavior.

All seven reproduction assertions now match Node in tree and required-bytecode modes. The persistent-context matrix runs tree, required, and shared configurations across multiple evaluate calls, including GC in a real global accessor and absent-vs-present-undefined property slots. Normal and unsuppressed TSan tests each pass 4/4.

Before/after Test262 transcripts are byte-identical: global-code 42, let 145, const 136, variable 178, builtins/global 29. All 530 pass on both sides, with zero failures and zero flips. The nonexistent builtins/globalThis directory is not counted; the pinned builtins/global group above was executed completely. Inventory passes.

Sign in to comment on this issue.