Skip to content

fix(runtime): expose global builtin function values + rebound builtin constructors - #3487

Merged
proggeramlug merged 2 commits into
mainfrom
fix-global-builtins-2905-2889
May 30, 2026
Merged

proggeramlug merged 2 commits into
mainfrom
fix-global-builtins-2905-2889

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Closes #2905
Closes #2889

#2905 — standard global function values on globalThis

parseInt, parseFloat, isNaN, isFinite, encodeURI, decodeURI, encodeURIComponent, and decodeURIComponent are now function-valued properties on globalThis with real dispatch. Reading them (globalThis.parseInt, bare const p = parseInt) yields a callable closure (typeof === "function"), and calling that closure goes through Perry's existing runtime helpers — matching Node.

Implementation:

  • Runtime: added thunks in object/global_this.rs delegating to js_parse_int / js_parse_float / js_is_nan / js_is_finite / js_encode_uri* / js_decode_uri*, and listed the names in GLOBAL_THIS_BUILTIN_FUNCTIONS with their dispatch arms.
  • Codegen: added the names to is_global_this_builtin_name so globalThis.<name> property reads route through the singleton instead of the 0.0 sentinel.
  • HIR: added the names to is_builtin_global_value_name so a bare value read (const p = parseInt) lowers to PropertyGet { GlobalGet, name }. Bare calls (parseInt(x)) are still picked off earlier by try_global_builtins → Expr::ParseInt/etc., so the call fast paths are unchanged.

#2889 — rebound global builtin constructors through real semantics

  • Call-form thunks for Number/Boolean (Object/String already had them): const N = Number; N("42") → 42, const B = Boolean; B(0) → false.
  • js_new_function_construct now constructs through a rebound global value for Error and its subclasses (TypeError/RangeError/ReferenceError/SyntaxError/EvalError/URIError), RegExp, and all typed arrays (Uint8Array, …). Array/Object/Date were already handled.
  • Installed common static methods on the Object constructor closure (keys/values/entries/freeze/create/getPrototypeOf/getOwnPropertyNames/fromEntries/assign) and the Array closure (isArray/from/of), so const O = Object; O.keys(x) and Array.isArray(new A(1)) dispatch through the real helpers.

Validation

Gap test test-files/test_gap_global_builtins_2905_2889.ts is byte-identical to node --experimental-strip-types under the DEFAULT auto-optimize compile. Covers typeof globalThis.<fn>, const p = parseInt; p("42px"), const A = Array; new A(2).length / Array.isArray(new A(1)), const O = Object; O.keys({a:1,b:2}), and rebound Number/String/Boolean call-form. Additional manual checks (rebound TypeError/Uint8Array/RegExp construct, direct-call non-regression) also match Node.

cargo test -p perry-hir and cargo test -p perry-runtime object:: green; cargo fmt --all -- --check clean; ./scripts/check_file_size.sh exit 0 (no file pushed over the 2000-line cap). No new HIR variant, no new #[no_mangle] fn (thunks are referenced by pointer from live code), no manifest/docs change.

Scope notes (not in this PR)

  • escape / unescape global functions: Perry has no runtime helper for the legacy %XX escape codec yet, so they remain unimplemented (a separate runtime addition).
  • Wrapper-object construct (new Number(x) / new Boolean(x) / new String(x) returning a boxed object): Perry does not model primitive wrapper objects, so the rebound new-form for these falls back to the existing behavior. Call-form coercion (the common case) works.
  • The long tail of Object statics (defineProperty, getOwnPropertyDescriptor, setPrototypeOf, …) is not reified on the rebound constructor value; direct Object.defineProperty(...) is unaffected.

Ralph Küpper added 2 commits May 31, 2026 01:27
… constructors

Closes #2905, closes #2889.

#2905: parseInt/parseFloat/isNaN/isFinite/encodeURI/decodeURI/
encodeURIComponent/decodeURIComponent are now function-valued properties on
globalThis with real dispatch, so globalThis.parseInt and const p = parseInt;
p(...) match Node. Added thunks delegating to the existing runtime helpers,
registered them in GLOBAL_THIS_BUILTIN_FUNCTIONS, mirrored in codegen
is_global_this_builtin_name and HIR is_builtin_global_value_name.

#2889: rebound global builtin constructors go through real semantics. Number/
Boolean call-form thunks (Object/String already had them); js_new_function_
construct now constructs Error subclasses, RegExp, and typed arrays through a
rebound value; Object (keys/values/entries/freeze/create/getPrototypeOf/
getOwnPropertyNames/fromEntries/assign) and Array (isArray/from/of) statics
installed on the constructor closures so const O = Object; O.keys(x) works.
@proggeramlug
proggeramlug merged commit 08ec46b into main May 30, 2026
@proggeramlug
proggeramlug deleted the fix-global-builtins-2905-2889 branch May 30, 2026 23:31
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: expose standard global function values on globalThis runtime: route rebound global built-in constructors through real semantics

1 participant