fix(runtime): #4139 expose Math/JSON/Reflect namespace members to reflection APIs#4148
Merged
Merged
Conversation
added 2 commits
June 2, 2026 21:34
…ve bare namespace value to the singleton
e26e582 to
9637807
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #4139 (sub-bug b):
Object.getOwnPropertyDescriptor/getOwnPropertyNamesreturnedundefined/[]for the members of the built-in namespace objectsMath,JSON, andReflect(Math.abs,Math.PI,JSON.stringify,Reflect.get, …).Two root causes, both fixed here:
Bare namespace identifier resolved to
globalThis. A bareMath(used as a value — e.g. passed togetOwnPropertyDescriptor(Math, …), stored in a local) lowered to theGlobalGet(0)sentinel, which isglobalThis. SoMath === globalThisheld and reflection read the wrong object.lower_expr.rsnow lowers bareMath/JSON/ReflecttoPropertyGet { GlobalGet(0), <name> }(the same value-form the built-in constructors already use), so the value resolves to the realpopulate_global_this_builtins-installed namespace object. The feat(runtime): .constructor on Date/Array/Object instances #973 reroute-undo inexpr_member.rsis extended for these three names so member-object position (Math.max(...),Math.PI) keeps the bareGlobalGet(0)receiver — the intrinsic call / constant-fold paths are byte-identical.Namespace singletons were empty.
Math/JSON/Reflectwere created as emptyObjectHeaders (onlyMath.f16roundwas installed), so even with a correct receiver there were no fields to reflect.global_this.rsnow reifies each namespace's own members as real own properties (methods viainstall_proto_method, Math constants viaset_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/lengthdescriptor attributes) was already correct onmain(verified against Node); this PR closes the remaining namespace-member reflection gap.Result (now byte-identical to Node)
Math.max(...),Math.PI,JSON.stringify,Reflect.get, shadowing (const Math = {...}), and aliasing (const M = Math; M.abs) all continue to work.Testing
test-parity/node-suite/globals/builtin-namespace-member-descriptors.ts— passes byte-identical tonode --experimental-strip-typesin both default andPERRY_NO_AUTO_OPTIMIZE=1modes.test-parity/node-suite/globals/*— identical 38 pass / 7 fail before and after (all 7 pre-existing, unrelated: UTF-8encodeInto, WASM, strict-mode readonly-write).test-files/test_gap_*.ts) — 170→171 pass, 41→40 fail: net zero new regressions (one unrelated flakynode_fsflip).cargo fmt --all -- --checkclean.