You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #10476 / PR #10591, which fixes a real correctness bug: a method call whose name matched a Date/Number/Array.prototype builtin was lowered straight to that builtin regardless of the receiver, so a
user's own toISOString / toFixed / getTime was silently skipped.
The fix guards that dispatch on the receiver's runtime kind. For a receiver the compiler has statically proven
to be a Date/number/array, nothing changes. For any other receiver, the receiver is evaluated once, rooted, and
branched on at runtime. That guarded path is 3–4x slower than Node.
Measurements (200k iterations, perf stat -e instructions, 3 runs, from PR #10591)
shape
fix instructions
fix wall (3 runs)
Node wall (3 runs)
fix vs Node
dayjs_shape
~4.80B
651 / 675 / 678 ms
187 / 204 / 240 ms
~3.1–3.3x slower
money_shape
~1.30B
363 / 417 / 418 ms
102 / 104 / 107 ms
~3.6–4.0x slower
Control shapes (date_typed, fixed_typed, fixed_any, ends_typed, sorted_typed, date_any) stay within
~2% of baseline, so the cost is confined to the guarded path.
Why there is no "regression vs baseline" number
The pre-fix baseline is not a valid comparator for these two shapes:
dayjs_shape baseline crashed (RangeError: Invalid time value) before completing the iterations.
money_shape baseline computed the wrong answer (600000 where Node and the fix both give 1000000),
because it dispatched to a numeric builtin instead of the user's method.
The old speed was the bug. Only fix-vs-Node is meaningful here.
Why it matters
This is the shape of every decimal/money/date-wrapper library — dayjs's toISOString/toJSON,
decimal.js and bignumber.js's toFixed — i.e. exactly the packages the compile-the-real-package work targets.
The project's bar is to match Node with 20% below acceptable; 3–4x is well outside it.
Where to look
crates/perry-codegen/src/lower_call/property_get/builtin_kind_guard.rs — the guard itself.
A monomorphic inline cache on the receiver kind at the call site would likely collapse most of this: these
loops call the same user method on the same shape every iteration.
Fixtures used for the numbers are the dayjs_shape / money_shape cases in PR #10591's perf section.
Follow-up to #10476 / PR #10591, which fixes a real correctness bug: a method call whose name matched a
Date/Number/Array.prototypebuiltin was lowered straight to that builtin regardless of the receiver, so auser's own
toISOString/toFixed/getTimewas silently skipped.The fix guards that dispatch on the receiver's runtime kind. For a receiver the compiler has statically proven
to be a Date/number/array, nothing changes. For any other receiver, the receiver is evaluated once, rooted, and
branched on at runtime. That guarded path is 3–4x slower than Node.
Measurements (200k iterations,
perf stat -e instructions, 3 runs, from PR #10591)dayjs_shapemoney_shapeControl shapes (
date_typed,fixed_typed,fixed_any,ends_typed,sorted_typed,date_any) stay within~2% of baseline, so the cost is confined to the guarded path.
Why there is no "regression vs baseline" number
The pre-fix baseline is not a valid comparator for these two shapes:
dayjs_shapebaseline crashed (RangeError: Invalid time value) before completing the iterations.money_shapebaseline computed the wrong answer (600000where Node and the fix both give1000000),because it dispatched to a numeric builtin instead of the user's method.
The old speed was the bug. Only fix-vs-Node is meaningful here.
Why it matters
This is the shape of every decimal/money/date-wrapper library — dayjs's
toISOString/toJSON,decimal.js and bignumber.js's
toFixed— i.e. exactly the packages the compile-the-real-package work targets.The project's bar is to match Node with 20% below acceptable; 3–4x is well outside it.
Where to look
crates/perry-codegen/src/lower_call/property_get/builtin_kind_guard.rs— the guard itself.Array.prototype.pushwas re-deriving its receiver 6x per call and fixing it was worth −74.6%.loops call the same user method on the same shape every iteration.
Fixtures used for the numbers are the
dayjs_shape/money_shapecases in PR #10591's perf section.