Skip to content

fix(runtime): Date.now/parse/UTC usable as first-class function values#4622

Merged
proggeramlug merged 1 commit into
mainfrom
fix-date-statics-as-values
Jun 5, 2026
Merged

fix(runtime): Date.now/parse/UTC usable as first-class function values#4622
proggeramlug merged 1 commit into
mainfrom
fix-date-statics-as-values

Conversation

@proggeramlug
Copy link
Copy Markdown
Contributor

Problem

typeof Date.now      // "number"     → "function"
Date.now.name        // undefined     → "now"
Date.UTC.length      // undefined     → 7
const u = Date.UTC; u(2020, 0)  // NaN → 1577836800000

Root causes (two)

  1. The feat(runtime): .constructor on Date/Array/Object instances #973/runtime: builtin own-property descriptor attributes wrong + getOwnPropertyDescriptor returns undefined #4139 reroute-undo collapsed value reads of Date.now/.parse/.UTC to GlobalGet(0).<name>, for which codegen has no intrinsic handler (unlike Object.keys / Math.max), so they mis-folded to a number. Added a Date now/parse/UTC exception to the reroute-undo so the read hits the reified Date constructor object (the aliased const D=Date; D.now and computed Date['now'] forms already worked). Direct calls Date.now() stay on the Expr::DateNow fast path — unaffected.
  2. date_utc_static collects all args into its rest param, but Date.UTC was registered with call-arity 7 (7 fixed params before the rest), so Date.UTC(2020,0) (fewer than 7 args) put nothing in the rest array → js_date_utc([]) → NaN. Registered call-arity 0 (all args → rest) while keeping spec .length = 7.

Verification

Byte-identical to node --experimental-strip-types: typeof/name/length, value-calls (const u=Date.UTC; u(2020,0)), and direct calls. Fixes test262 Date/{now,parse,UTC}/{name,length}, Date/now/15.9.4.4-0-1, 15.9.4.4-0-3 (8 tests). Date general usage (construction, getters, instanceof) unchanged.

Two bugs made the dotted static reads broken:
1. The #973/#4139 reroute-undo collapsed value reads of Date.now/parse/UTC to
   GlobalGet(0).<name>, for which codegen has no intrinsic handler (unlike
   Object.keys / Math.max), so they mis-folded to a number (typeof 'number').
   Add a Date now/parse/UTC exception to the reroute-undo so the read hits the
   reified Date constructor object (the aliased/computed forms already did).
   Direct calls (Date.now()) stay on the Expr::DateNow fast path (unaffected).
2. date_utc_static collects all args into its rest param, but Date.UTC was
   registered with call-arity 7 (7 fixed params before rest), so Date.UTC(2020,0)
   put nothing in the rest array → js_date_utc([]) → NaN. Register call-arity 0
   (all args → rest) while keeping spec .length = 7.

Now byte-identical to node: typeof Date.now/parse/UTC === 'function', correct
.name/.length, value-calls (const u=Date.UTC; u(2020,0)) work, direct calls
unchanged. Fixes test262 Date/{now,parse,UTC}/{name,length}, Date/now/15.9.4.4-0-1/3.
@proggeramlug proggeramlug merged commit 1ba28a4 into main Jun 5, 2026
13 checks passed
@proggeramlug proggeramlug deleted the fix-date-statics-as-values branch June 5, 2026 16:23
proggeramlug added a commit that referenced this pull request Jun 5, 2026
…lues (#4626)

Same reroute-undo issue as Date.now (#4622): value reads of Array.isArray /
Array.from / Array.of collapsed to GlobalGet(0).<name>, whose intrinsic path
drops the function metadata — typeof was 'function' but .name was undefined and
.length undefined. They are installed with metadata via
install_constructor_static, so add Array to the reified-static reroute-undo
exception. Array.fromAsync is unreified and unchanged; direct calls keep the
intrinsic fast path via the !member_is_call_callee gate.

Byte-identical to node: Array.isArray.name==='isArray'/.length===1,
Array.from.name==='from'/.length===1, Array.of.name==='of'/.length===0, value-calls
and direct calls work. Fixes test262 Array/{isArray,from,of}/{name,length}.

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
proggeramlug added a commit that referenced this pull request Jun 5, 2026
…nction values (#4631)

Same reroute-undo issue as Date.now (#4622) / Array.isArray (#4626). All six
Number statics (isFinite/isInteger/isNaN/isSafeInteger/parseFloat/parseInt) are
reified with metadata via install_constructor_static, but the #973/#4139
reroute-undo collapsed value reads to GlobalGet(0).<name>, whose intrinsic path
dropped the metadata for isInteger/isSafeInteger (.name/.length undefined).

Add Number to the reified-static reroute-undo exception. The already-named
siblings (isFinite/isNaN/parseFloat/parseInt) are also reified, so routing them
to the reified receiver preserves their names; direct calls keep the intrinsic
fast path via the !member_is_call_callee gate.

Byte-identical to node: Number.isInteger.name==='isInteger'/.length===1,
isSafeInteger likewise; value-calls and direct calls work. Fixes test262
Number/{isInteger,isSafeInteger}/{name,length}. (String.fromCharCode/etc. are not
reified yet — tracked in #4627.)

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
proggeramlug added a commit that referenced this pull request Jun 5, 2026
… function values (#4634)

Completes the static-function-values series (#4622 Date, #4626 Array, #4631
Number). Unlike those, String.fromCharCode/fromCodePoint were not reified at all,
so this both reifies them and wires the reroute-undo exception:

- New js_string_from_code_point_array runtime helper (variadic fromCodePoint with
  per-element RangeError validation; lone surrogates → U+FFFD).
- Reify fromCharCode/fromCodePoint via install_constructor_static_with_call_arity
  (call-arity 0 = all args into rest; spec .length 1) — fromCharCode reuses the
  existing js_string_from_char_code_array.
- Explicit String fromCharCode/fromCodePoint exception in the #973/#4139
  reroute-undo (NOT the whole namespace — String.raw is not reified and stays on
  its intrinsic path, unaffected).

Byte-identical to node: typeof/name/length, value-calls (incl. astral code
points), direct calls, RangeError on invalid code points; String.raw unchanged.
Fixes test262 String/{fromCharCode,fromCodePoint}/{name,length}. (String.raw .name
/.length tracked in #4627.)

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
proggeramlug added a commit that referenced this pull request Jun 5, 2026
Completes the static-function-values series (Date #4622, Array #4626, Number
#4631, String.fromCharCode/fromCodePoint #4634). Reify String.raw as a real
function value: a thunk taking the template/cooked object as a fixed param plus
a rest of substitutions (call-arity 1, spec .length 1), forwarding to
js_string_raw. Add 'raw' to the String reroute-undo exception so value reads hit
the reified receiver.

Byte-identical to node: String.raw.name==='raw'/.length===1, value-calls
(const r=String.raw; r({raw:[...]}, ...)) and tagged-template calls
(String.raw`x${10}y`) work. Fixes test262 String/raw/{name,length}; closes the
String portion of #4627.

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
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.

1 participant