Skip to content

fix(runtime): #4139 expose Math/JSON/Reflect namespace members to reflection APIs#4148

Merged
proggeramlug merged 2 commits into
mainfrom
worktree-fix-4139-builtin-descriptors
Jun 2, 2026
Merged

fix(runtime): #4139 expose Math/JSON/Reflect namespace members to reflection APIs#4148
proggeramlug merged 2 commits into
mainfrom
worktree-fix-4139-builtin-descriptors

Conversation

@proggeramlug
Copy link
Copy Markdown
Contributor

Summary

Fixes #4139 (sub-bug b): Object.getOwnPropertyDescriptor / getOwnPropertyNames returned undefined / [] for the members of the built-in namespace objects Math, JSON, and Reflect (Math.abs, Math.PI, JSON.stringify, Reflect.get, …).

Two root causes, both fixed here:

  1. Bare namespace identifier resolved to globalThis. A bare Math (used as a value — e.g. passed to getOwnPropertyDescriptor(Math, …), stored in a local) lowered to the GlobalGet(0) sentinel, which is globalThis. So Math === globalThis held and reflection read the wrong object. lower_expr.rs now lowers bare Math/JSON/Reflect to PropertyGet { GlobalGet(0), <name> } (the same value-form the built-in constructors already use), so the value resolves to the real populate_global_this_builtins-installed namespace object. The feat(runtime): .constructor on Date/Array/Object instances #973 reroute-undo in expr_member.rs is extended for these three names so member-object position (Math.max(...), Math.PI) keeps the bare GlobalGet(0) receiver — the intrinsic call / constant-fold paths are byte-identical.

  2. Namespace singletons were empty. Math/JSON/Reflect were created as empty ObjectHeaders (only Math.f16round was installed), so even with a correct receiver there were no fields to reflect. global_this.rs now reifies each namespace's own members as real own properties (methods via install_proto_method, Math constants via set_intrinsic_data_prop) with spec-correct descriptors. Call sites are AST-gated codegen intrinsics and never read these fields — this is reflection parity only.

Sub-bug (a) of #4139 (wrong name/length descriptor attributes) was already correct on main (verified against Node); this PR closes the remaining namespace-member reflection gap.

Result (now byte-identical to Node)

Object.getOwnPropertyDescriptor(Math, 'max')  => {v:<fn> w:true e:false c:true}
Object.getOwnPropertyDescriptor(Math, 'PI')   => {v:3.14159… w:false e:false c:false}
Object.getOwnPropertyDescriptor(JSON, 'parse') => {v:<fn> w:true e:false c:true}
Object.getOwnPropertyDescriptor(Reflect,'get') => {v:<fn> w:true e:false c:true}
Object.getOwnPropertyNames(Math).length        => 44
Object.getOwnPropertyNames(JSON)               => parse,stringify,rawJSON,isRawJSON
Object.getOwnPropertyNames(Reflect).length     => 13
Object.keys(Math)                              => []        (members non-enumerable)
Math === globalThis.Math                       => true
Math === globalThis                            => false

Math.max(...), Math.PI, JSON.stringify, Reflect.get, shadowing (const Math = {...}), and aliasing (const M = Math; M.abs) all continue to work.

Testing

  • New byte-parity test test-parity/node-suite/globals/builtin-namespace-member-descriptors.ts — passes byte-identical to node --experimental-strip-types in both default and PERRY_NO_AUTO_OPTIMIZE=1 modes.
  • Regression sweeps (baseline vs. fix, definitive):
    • test-parity/node-suite/globals/* — identical 38 pass / 7 fail before and after (all 7 pre-existing, unrelated: UTF-8 encodeInto, WASM, strict-mode readonly-write).
    • Canonical gap suite (test-files/test_gap_*.ts) — 170→171 pass, 41→40 fail: net zero new regressions (one unrelated flaky node_fs flip).
  • cargo fmt --all -- --check clean.

@proggeramlug proggeramlug force-pushed the worktree-fix-4139-builtin-descriptors branch from e26e582 to 9637807 Compare June 2, 2026 19:47
@proggeramlug proggeramlug merged commit fcc5fbd into main Jun 2, 2026
11 checks passed
@proggeramlug proggeramlug deleted the worktree-fix-4139-builtin-descriptors branch June 2, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

runtime: builtin own-property descriptor attributes wrong + getOwnPropertyDescriptor returns undefined

1 participant