Skip to content

perf(engine): speed up FormatDouble shortest-representation scan#899

Merged
frostney merged 7 commits into
mainfrom
claude/ecstatic-cohen-c61125
Jun 28, 2026
Merged

perf(engine): speed up FormatDouble shortest-representation scan#899
frostney merged 7 commits into
mainfrom
claude/ecstatic-cohen-c61125

Conversation

@frostney

@frostney frostney commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • Speeds up FormatDouble's general (non-integer) case — the shortest round-tripping decimal used by Number.prototype.toString, String(x), template interpolation, property-key stringification, and JSON.stringify of floats — without changing its output.
  • The issue's proposed fix is unsafe, and this PR proves why. perf(number): FormatDouble linear-probes precision for shortest round-trip #812 proposed binary-searching the Str(V:W) precision width ("same candidates, fewer probes"). A sweep of ~70M doubles (prod -O4) shows FPC Str is not correctly rounded at every width, so the "parses back exactly" predicate is not monotonic in W: 14,241 general-case doubles have round-trip "holes". The upward first-hit scan is robust to them; a binary search converges above the true minimum and emits a non-shortest, spec-violating string for ~1 in 520k general-case doubles (e.g. 9.18742501042000e+222 instead of 9.18742501042e+222), violating "k as small as possible" in ES2026 §6.1.6.1.20 Number::toString.
  • Instead, keep the first-hit linear scan and cut per-probe overhead. Each probe now reads Str(V:W) into a fixed ShortString, strips leading spaces in place (no heap allocation), and parses with the locale-free Val instead of Trim + TryStrToFloat. Val selects the identical width — verified byte-for-byte against TryStrToFloat over 74.9M doubles with zero divergence — while avoiding the per-iteration heap allocation and the TFormatSettings scan.

Performance (measured end-to-end, not just in isolation)

  • Bytecode, --prod, a toString-dominated workload of 2M Number.prototype.toString calls over 15–17-significant-digit doubles: 13.4s → vs 18.8s on origin/main = ~1.4× faster (−28% execution time), stable across 3 runs each.
  • The isolated probe loop is ~2× faster, but the engine's per-call string allocation and dispatch are a roughly constant overhead around FormatDouble, so the end-to-end figure is ~1.4×. It is a real speedup on float stringification — not neutral, not a regression.
  • New benchmark benchmarks/numbers.js → "toString non-integer (shortest round-trip)" covers this path going forward (the existing toString bench only exercised the integer fast path).

Constraints / non-goals

  • The first-hit-from-the-bottom scan is load-bearing and must not become a binary search or any probe-skipping scheme — documented in the code and in ADR 0080.
  • A correct single-pass alternative (Ryū/Grisu) would remove the dependence on Str's per-width rounding entirely; it's a larger spec-exact rewrite, explicitly deferred (this is a watch-tier item).
  • toFixed/toExponential/toPrecision use a separate FormatDoubleToPrecision path and are untouched.
  • Divergence from the literal issue text (binary search → safe per-probe micro-opt) was chosen deliberately after the investigation overturned the issue's "low risk" premise.

Verification

  • Full JS suite 10,993/10,993 in interpreter and bytecode mode; ./format.pas --check clean.
  • New regression tests assert exact shortest output for computed fractionals (0.1+0.2, 1/3, π, √2) and for several non-monotonic "hole" doubles — the exact values a binary search would break.
  • Full Number + JSON test262 sweep under --prod (bytecode, pinned SHA de8e621c): wrapper_infra_failures: 0, and failure sets are identical to the origin/main baseline (Number 282/58, JSON 136/29) → provably zero conformance movement.
  • ValTryStrToFloat equivalence proven over 74.9M doubles (0 selected-width mismatches).

Docs

  • New ADR 0080 — FormatDouble first-hit precision scan (records the non-monotonicity evidence, why binary search is rejected, and the measured speedup) + README index entry.
  • Corrects the stale §6.1.6.1.13§6.1.6.1.20 Number::toString clause annotation (source + code-style.md) surfaced by the new ADR.

Closes #812

Testing

  • Verified no regressions and confirmed the new feature or bugfix in end-to-end JavaScript/TypeScript tests
  • Updated documentation
  • Optional: Verified no regressions and confirmed the new feature or bugfix in native Pascal tests (if AST, scope, evaluator, or value types changed) — behavior is byte-identical and fully covered through the JS surface (Number.prototype.toString, JSON.stringify); no value-type semantics changed.
  • Optional: Verified no benchmark regressions or confirmed benchmark coverage for the change — added a non-integer float toString benchmark to benchmarks/numbers.js; measured ~1.4× faster end-to-end (2M calls, bytecode, --prod) vs origin/main.

frostney and others added 2 commits June 28, 2026 11:34
FormatDouble's general (non-integer) case finds the shortest round-tripping
decimal by scanning the Str(V:W) precision width upward and taking the first
width that parses back exactly. Issue #812 proposed binary-searching the width
to cut probes. A sweep of ~70M doubles showed that is incorrect: FPC Str is not
correctly rounded at every width, so the round-trip predicate is not monotonic
in W, and a binary search emits non-shortest strings (e.g. 9.18742501042000e+222
instead of 9.18742501042e+222) for ~1 in 520k general-case doubles, violating
"k as small as possible" in ES2026 Number::toString.

Keep the first-hit linear scan (now documented as load-bearing in ADR 0079) and
instead cut per-probe overhead: read Str into a fixed ShortString, strip leading
spaces in place, and parse with the locale-free Val instead of Trim +
TryStrToFloat. Val selects the identical width — verified byte-for-byte against
TryStrToFloat over 74.9M doubles with zero divergence — while avoiding the
per-iteration heap allocation and the TFormatSettings scan (~2x faster on this
path). Output is unchanged: the full Number+JSON test262 sweep under --prod has
identical failure sets to the origin/main baseline.

toFixed/toExponential/toPrecision use a separate FormatDoubleToPrecision path and
are untouched. Also corrects the stale ES2026 §6.1.6.1.13 -> §6.1.6.1.20
Number::toString clause annotation surfaced by the new ADR.

Closes #812

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
gocciascript-homepage Ignored Ignored Preview Jun 28, 2026 3:15pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 15dd2cd8-830e-43ea-aaf1-0d1b8335b859

📥 Commits

Reviewing files that changed from the base of the PR and between 2f5bdcb and 80aeabe.

📒 Files selected for processing (1)
  • tests/built-ins/Number/prototype/toString.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/built-ins/Number/prototype/toString.js

📝 Walkthrough

Walkthrough

FormatDouble now probes shortest round-tripping non-integer output with Str(AValue:W, Buf) and Val, replacing the prior Trim plus TryStrToFloat approach. ADR 0080, spec citation updates, tests, and a benchmark were added.

Changes

FormatDouble first-hit precision scan

Layer / File(s) Summary
FormatDouble scan: ShortString/Val replacement
source/units/Goccia.Values.Primitives.pas
Introduces Buf and Code locals, replaces the probe loop with Str(AValue:W, Buf) and Val-based matching, and updates inline ES2026 Number::toString references.
ADR 0080 and doc citation updates
docs/adr/0080-formatdouble-first-hit-precision-scan.md, docs/adr/README.md, docs/contributing/code-style.md
Adds ADR 0080, links it from the ADR index, and updates the code-style ECMAScript citation.
Regression tests and benchmark
tests/built-ins/Number/prototype/toString.js, tests/built-ins/JSON/stringify.js, benchmarks/numbers.js
Adds shortest round-trip and scientific-notation stringification tests, expands coercion consistency coverage, adds fractional JSON.stringify checks, and adds the non-integer toString benchmark sample set and case.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • frostney/GocciaScript#163: Also updates tests/built-ins/JSON/stringify.js with assertions around shortest round-tripping formatting for fractional double values.
  • frostney/GocciaScript#415: Touches the same Number::toString/JSON.stringify stringification path in source/units/Goccia.Values.Primitives.pas.

Suggested labels

documentation, internal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: speeding up FormatDouble's shortest-representation scan.
Description check ✅ Passed The description matches the repository template and includes summary, constraints, issue link, and testing details.
Linked Issues check ✅ Passed The PR fulfills #812 by improving shortest-roundtrip formatting performance while preserving output and adding the required coverage.
Out of Scope Changes check ✅ Passed The docs, benchmark, and test updates are all aligned with the FormatDouble optimization and its verification needs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Comment @coderabbitai help to get the list of available commands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Suite Timing

Test Runner (interpreted: 11,006 passed; bytecode: 11,006 passed)
Metric Interpreted Bytecode
Total 11006 11006
Passed 11006 ✅ 11006 ✅
Workers 4 4
Test Duration 18.33s 20.53s
Lex (cumulative) 559.6ms 535.3ms
Parse (cumulative) 383.4ms 385.6ms
Compile (cumulative) 795.4ms
Execute (cumulative) 59.7ms 48.34s
Engine Total (cumulative) 1.00s 50.06s
Lex (avg/worker) 139.9ms 133.8ms
Parse (avg/worker) 95.9ms 96.4ms
Compile (avg/worker) 198.8ms
Execute (avg/worker) 14.9ms 12.09s
Engine Total (avg/worker) 250.7ms 12.51s

Memory

GC rows aggregate the main thread plus all worker thread-local GCs. Test runner worker shutdown frees thread-local heaps in bulk; that shutdown reclamation is not counted as GC collections or collected objects.

Metric Interpreted Bytecode
GC Live 282.89 MiB 280.31 MiB
GC Peak Live 324.59 MiB 324.72 MiB
GC Allocated During Run 529.61 MiB 473.75 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 195 195
GC Collected Objects 2,600,924 2,170,953
Heap Start Allocated 182.0 KiB 182.0 KiB
Heap End Allocated 3.66 MiB 3.66 MiB
Heap Delta Allocated 3.48 MiB 3.48 MiB
Heap Delta Free 1.68 MiB 1.68 MiB
Benchmarks (interpreted: 437; bytecode: 437)
Metric Interpreted Bytecode
Total 437 437
Workers 4 4
Duration 2.84min 2.78min

Memory

GC rows aggregate the main thread plus all worker thread-local GCs. Benchmark runner performs explicit between-file collections, so collection and collected-object counts can be much higher than the test runner.

Metric Interpreted Bytecode
GC Live 6.28 MiB 6.28 MiB
GC Peak Live 97.82 MiB 67.04 MiB
GC Allocated During Run 15.23 GiB 9.94 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 3,642 3,444
GC Collected Objects 236,898,172 227,405,710
Heap Start Allocated 3.36 MiB 3.36 MiB
Heap End Allocated 3.36 MiB 3.36 MiB
Heap Delta Allocated 128 B 128 B

Measured on ubuntu-latest x64.

@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

437 benchmarks · PR vs same-runner main build

Interpreted: 🟢 44 improved · 🔴 19 regressed · 374 unchanged · avg +0.9%
Bytecode: 🟢 42 improved · 🔴 44 regressed · 351 unchanged · avg +0.4%

Typical per-run noise (median variance): interpreted ±2.9%, bytecode ±2.2%. Deltas within noise overlap and read as unchanged.

arraybuffer.js — Interp: 🟢 2, 12 unch. · avg +0.2% · Bytecode: 🟢 2, 🔴 2, 10 unch. · avg +4.0%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
create ArrayBuffer(0) 118,641 ops/sec [104,840..120,310] → 117,446 ops/sec [103,592..122,155] ~ overlap (-1.0%) 147,833 ops/sec [102,399..183,805] → 184,707 ops/sec [165,710..198,087] ~ overlap (+24.9%)
create ArrayBuffer(64) 117,049 ops/sec [114,000..123,532] → 119,046 ops/sec [114,968..140,556] ~ overlap (+1.7%) 142,467 ops/sec [138,157..143,715] → 148,096 ops/sec [141,882..197,994] ~ overlap (+4.0%)
create ArrayBuffer(1024) 107,572 ops/sec [102,223..108,318] → 103,142 ops/sec [102,615..105,759] ~ overlap (-4.1%) 129,636 ops/sec [129,412..129,721] → 126,279 ops/sec [124,286..129,594] ~ overlap (-2.6%)
create ArrayBuffer(8192) 69,423 ops/sec [64,221..84,590] → 65,615 ops/sec [64,220..67,262] ~ overlap (-5.5%) 75,178 ops/sec [74,874..76,107] → 73,002 ops/sec [72,662..73,562] 🔴 -2.9%
slice full buffer (64 bytes) 97,856 ops/sec [95,063..99,494] → 98,703 ops/sec [95,521..102,822] ~ overlap (+0.9%) 119,284 ops/sec [117,716..120,402] → 118,804 ops/sec [115,582..123,100] ~ overlap (-0.4%)
slice half buffer (512 of 1024 bytes) 90,459 ops/sec [88,156..96,459] → 92,948 ops/sec [91,795..93,940] ~ overlap (+2.8%) 112,807 ops/sec [108,738..123,000] → 110,890 ops/sec [110,241..111,499] ~ overlap (-1.7%)
slice with negative indices 82,775 ops/sec [81,520..89,108] → 86,349 ops/sec [85,956..96,197] ~ overlap (+4.3%) 111,138 ops/sec [109,288..113,656] → 113,399 ops/sec [111,798..114,186] ~ overlap (+2.0%)
slice empty range 94,400 ops/sec [93,782..94,861] → 98,095 ops/sec [97,106..98,705] 🟢 +3.9% 113,704 ops/sec [112,899..115,010] → 116,305 ops/sec [115,875..136,346] 🟢 +2.3%
byteLength access 278,784 ops/sec [276,335..280,939] → 279,758 ops/sec [276,148..291,081] ~ overlap (+0.3%) 330,431 ops/sec [321,805..341,387] → 355,812 ops/sec [338,822..400,670] ~ overlap (+7.7%)
Symbol.toStringTag access 225,073 ops/sec [223,429..227,470] → 221,671 ops/sec [216,514..229,241] ~ overlap (-1.5%) 238,359 ops/sec [234,651..240,277] → 267,773 ops/sec [244,126..281,768] 🟢 +12.3%
ArrayBuffer.isView 169,341 ops/sec [168,075..169,662] → 173,751 ops/sec [170,916..175,091] 🟢 +2.6% 222,578 ops/sec [221,181..241,066] → 249,264 ops/sec [228,177..260,447] ~ overlap (+12.0%)
clone ArrayBuffer(64) 131,910 ops/sec [127,782..143,589] → 128,092 ops/sec [127,272..130,467] ~ overlap (-2.9%) 167,563 ops/sec [165,318..190,117] → 169,088 ops/sec [162,759..181,448] ~ overlap (+0.9%)
clone ArrayBuffer(1024) 115,604 ops/sec [113,005..116,075] → 115,784 ops/sec [114,710..116,291] ~ overlap (+0.2%) 148,508 ops/sec [147,752..149,165] → 141,994 ops/sec [139,884..145,381] 🔴 -4.4%
clone ArrayBuffer inside object 85,509 ops/sec [82,195..91,821] → 86,377 ops/sec [86,035..88,447] ~ overlap (+1.0%) 102,127 ops/sec [101,623..102,775] → 103,435 ops/sec [100,649..107,394] ~ overlap (+1.3%)
arrays.js — Interp: 🟢 3, 16 unch. · avg +1.1% · Bytecode: 🟢 3, 🔴 1, 15 unch. · avg -0.2%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
Array.from length 100 3,840 ops/sec [3,249..3,924] → 3,308 ops/sec [3,138..3,624] ~ overlap (-13.9%) 3,002 ops/sec [2,942..3,031] → 3,063 ops/sec [2,992..3,310] ~ overlap (+2.0%)
Array.from 10 elements 73,644 ops/sec [64,441..82,461] → 69,657 ops/sec [64,893..79,029] ~ overlap (-5.4%) 84,913 ops/sec [72,836..86,784] → 72,654 ops/sec [71,710..73,160] ~ overlap (-14.4%)
Array.of 10 elements 85,018 ops/sec [82,048..86,388] → 85,967 ops/sec [83,471..86,738] ~ overlap (+1.1%) 103,570 ops/sec [69,867..120,632] → 106,745 ops/sec [105,361..107,142] ~ overlap (+3.1%)
spread into new array 94,325 ops/sec [91,836..95,662] → 104,045 ops/sec [97,114..115,219] 🟢 +10.3% 55,241 ops/sec [53,658..57,270] → 52,503 ops/sec [51,943..88,425] ~ overlap (-5.0%)
map over 50 elements 5,343 ops/sec [5,327..6,090] → 5,555 ops/sec [5,355..6,294] ~ overlap (+4.0%) 5,810 ops/sec [5,787..6,217] → 6,106 ops/sec [5,884..6,564] ~ overlap (+5.1%)
filter over 50 elements 4,944 ops/sec [4,506..4,967] → 4,894 ops/sec [4,833..5,024] ~ overlap (-1.0%) 5,781 ops/sec [5,615..6,362] → 5,656 ops/sec [5,556..6,619] ~ overlap (-2.2%)
reduce sum 50 elements 5,426 ops/sec [5,326..5,457] → 5,470 ops/sec [5,355..6,618] ~ overlap (+0.8%) 5,470 ops/sec [5,416..5,508] → 5,774 ops/sec [5,591..5,798] 🟢 +5.6%
forEach over 50 elements 3,752 ops/sec [3,695..3,779] → 3,726 ops/sec [3,676..3,740] ~ overlap (-0.7%) 6,389 ops/sec [5,965..6,712] → 5,982 ops/sec [5,966..6,061] ~ overlap (-6.4%)
find in 50 elements 7,192 ops/sec [6,856..7,291] → 7,377 ops/sec [7,287..7,509] ~ overlap (+2.6%) 7,563 ops/sec [7,543..7,579] → 7,698 ops/sec [7,682..7,727] 🟢 +1.8%
sort 20 elements 4,505 ops/sec [4,391..4,537] → 4,512 ops/sec [4,484..4,748] ~ overlap (+0.2%) 4,883 ops/sec [4,699..4,967] → 4,993 ops/sec [4,968..5,004] 🟢 +2.3%
flat nested array 40,381 ops/sec [39,785..50,450] → 41,130 ops/sec [40,837..41,899] ~ overlap (+1.9%) 44,840 ops/sec [44,646..44,924] → 44,395 ops/sec [43,970..56,331] ~ overlap (-1.0%)
flatMap 21,512 ops/sec [21,393..21,708] → 22,923 ops/sec [21,802..25,807] 🟢 +6.6% 23,654 ops/sec [23,547..23,762] → 23,437 ops/sec [22,910..23,653] ~ overlap (-0.9%)
map inside map (5x5) 5,750 ops/sec [5,653..5,816] → 5,828 ops/sec [5,801..5,836] ~ overlap (+1.4%) 6,349 ops/sec [6,287..6,388] → 6,667 ops/sec [6,078..6,876] ~ overlap (+5.0%)
filter inside map (5x10) 3,932 ops/sec [3,867..4,189] → 3,983 ops/sec [3,932..4,095] ~ overlap (+1.3%) 4,470 ops/sec [4,357..4,927] → 4,691 ops/sec [4,148..5,040] ~ overlap (+5.0%)
reduce inside map (5x10) 4,659 ops/sec [4,336..5,371] → 4,474 ops/sec [4,317..4,651] ~ overlap (-4.0%) 4,526 ops/sec [4,510..4,556] → 4,725 ops/sec [4,452..5,698] ~ overlap (+4.4%)
forEach inside forEach (5x10) 3,132 ops/sec [3,096..3,644] → 3,166 ops/sec [3,131..3,188] ~ overlap (+1.1%) 5,232 ops/sec [4,912..5,777] → 4,957 ops/sec [4,902..5,031] ~ overlap (-5.3%)
find inside some (10x10) 3,289 ops/sec [3,113..3,473] → 3,474 ops/sec [3,311..3,664] ~ overlap (+5.6%) 3,472 ops/sec [3,456..3,531] → 3,503 ops/sec [3,496..3,508] ~ overlap (+0.9%)
map+filter chain nested (5x20) 1,193 ops/sec [1,160..1,216] → 1,233 ops/sec [1,220..1,319] 🟢 +3.4% 1,347 ops/sec [1,338..1,484] → 1,323 ops/sec [1,307..1,328] 🔴 -1.8%
reduce flatten (10x5) 9,841 ops/sec [9,802..10,207] → 10,419 ops/sec [9,901..11,155] ~ overlap (+5.9%) 4,269 ops/sec [4,232..4,281] → 4,198 ops/sec [4,186..4,293] ~ overlap (-1.7%)
async-await.js — Interp: 🟢 1, 5 unch. · avg -1.9% · Bytecode: 🟢 1, 🔴 1, 4 unch. · avg +0.6%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
single await 22,852 ops/sec [20,234..23,301] → 23,249 ops/sec [18,887..27,839] ~ overlap (+1.7%) 23,449 ops/sec [17,368..25,660] → 23,302 ops/sec [22,158..24,944] ~ overlap (-0.6%)
multiple awaits 10,581 ops/sec [9,336..13,129] → 9,485 ops/sec [9,293..14,804] ~ overlap (-10.4%) 8,132 ops/sec [8,083..8,259] → 8,766 ops/sec [8,423..9,898] 🟢 +7.8%
await non-Promise value 32,108 ops/sec [29,467..39,717] → 30,878 ops/sec [29,997..31,795] ~ overlap (-3.8%) 28,596 ops/sec [28,312..29,780] → 30,228 ops/sec [29,012..30,702] ~ overlap (+5.7%)
await with try/catch 20,032 ops/sec [19,826..22,322] → 20,066 ops/sec [19,016..21,488] ~ overlap (+0.2%) 20,991 ops/sec [15,775..26,056] → 22,098 ops/sec [19,896..23,043] ~ overlap (+5.3%)
await Promise.all 5,492 ops/sec [5,418..5,569] → 5,717 ops/sec [5,678..5,749] 🟢 +4.1% 5,688 ops/sec [5,405..5,876] → 5,682 ops/sec [5,371..5,725] ~ overlap (-0.1%)
nested async function call 13,170 ops/sec [12,461..13,730] → 12,749 ops/sec [11,369..13,448] ~ overlap (-3.2%) 13,542 ops/sec [13,451..13,977] → 11,614 ops/sec [11,371..13,348] 🔴 -14.2%
async-generators.js — Interp: 2 unch. · avg -0.3% · Bytecode: 2 unch. · avg +0.8%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
for-await-of over async generator 1,646 ops/sec [1,549..1,736] → 1,621 ops/sec [1,486..1,963] ~ overlap (-1.5%) 583 ops/sec [450..647] → 584 ops/sec [509..590] ~ overlap (+0.2%)
async generator with await in body 11,171 ops/sec [10,836..11,956] → 11,279 ops/sec [10,744..13,163] ~ overlap (+1.0%) 4,299 ops/sec [4,231..4,476] → 4,363 ops/sec [4,303..4,721] ~ overlap (+1.5%)
atomics.js — Interp: 🔴 1, 5 unch. · avg -2.1% · Bytecode: 🔴 2, 4 unch. · avg -4.2%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
load and store Int32Array 83,495 ops/sec [80,052..90,800] → 82,221 ops/sec [80,798..88,573] ~ overlap (-1.5%) 134,360 ops/sec [118,600..143,505] → 123,735 ops/sec [121,423..152,282] ~ overlap (-7.9%)
read-modify-write Int32Array 56,961 ops/sec [56,838..62,435] → 55,093 ops/sec [54,739..55,857] 🔴 -3.3% 81,301 ops/sec [78,750..83,468] → 83,259 ops/sec [79,398..83,657] ~ overlap (+2.4%)
compareExchange hit and miss 50,893 ops/sec [33,565..59,065] → 50,487 ops/sec [50,159..51,035] ~ overlap (-0.8%) 72,781 ops/sec [70,895..80,430] → 71,445 ops/sec [70,885..71,981] ~ overlap (-1.8%)
wait with zero timeout 136,220 ops/sec [134,341..145,156] → 135,235 ops/sec [130,862..145,481] ~ overlap (-0.7%) 194,333 ops/sec [188,927..208,976] → 184,144 ops/sec [182,967..192,696] ~ overlap (-5.2%)
waitAsync synchronous not-equal 99,628 ops/sec [97,860..108,086] → 100,120 ops/sec [96,017..107,156] ~ overlap (+0.5%) 124,057 ops/sec [123,007..124,203] → 118,036 ops/sec [116,470..119,890] 🔴 -4.9%
notify with no waiters 148,489 ops/sec [139,913..149,618] → 138,822 ops/sec [136,861..141,539] ~ overlap (-6.5%) 201,126 ops/sec [197,262..203,881] → 185,963 ops/sec [185,428..190,114] 🔴 -7.5%
base64.js — Interp: 🟢 2, 8 unch. · avg +0.7% · Bytecode: 🟢 1, 🔴 1, 8 unch. · avg -0.0%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
short ASCII (13 chars) 2,431 ops/sec [2,412..2,449] → 2,449 ops/sec [2,426..3,079] ~ overlap (+0.7%) 2,374 ops/sec [2,345..2,392] → 2,354 ops/sec [2,345..2,357] ~ overlap (-0.8%)
medium ASCII (450 chars) 89 ops/sec [89..90] → 94 ops/sec [90..100] 🟢 +5.8% 87 ops/sec [86..87] → 87 ops/sec [85..87] ~ overlap (-0.4%)
Latin-1 characters 3,679 ops/sec [3,505..3,978] → 3,482 ops/sec [3,422..3,695] ~ overlap (-5.3%) 3,457 ops/sec [3,429..3,476] → 3,401 ops/sec [3,309..3,409] 🔴 -1.6%
short base64 (20 chars) 1,739 ops/sec [1,699..2,073] → 1,768 ops/sec [1,749..2,373] ~ overlap (+1.7%) 1,739 ops/sec [1,702..1,747] → 1,692 ops/sec [1,658..1,718] ~ overlap (-2.7%)
medium base64 (600 chars) 69 ops/sec [69..70] → 70 ops/sec [69..71] ~ overlap (+1.1%) 66 ops/sec [66..67] → 65 ops/sec [65..66] ~ overlap (-1.6%)
Latin-1 output 2,476 ops/sec [2,459..2,666] → 2,523 ops/sec [2,514..2,639] ~ overlap (+1.9%) 2,430 ops/sec [2,371..2,439] → 2,407 ops/sec [2,365..2,442] ~ overlap (-0.9%)
forgiving (no padding) 3,695 ops/sec [3,632..3,797] → 3,999 ops/sec [3,819..4,111] 🟢 +8.2% 3,604 ops/sec [3,572..3,646] → 3,609 ops/sec [3,482..3,995] ~ overlap (+0.1%)
with whitespace 1,646 ops/sec [1,626..1,864] → 1,635 ops/sec [1,627..1,857] ~ overlap (-0.7%) 1,564 ops/sec [1,540..1,573] → 1,664 ops/sec [1,575..1,843] 🟢 +6.4%
atob(btoa(short)) 1,017 ops/sec [1,005..1,054] → 1,001 ops/sec [990..1,106] ~ overlap (-1.6%) 981 ops/sec [971..987] → 991 ops/sec [920..1,005] ~ overlap (+1.0%)
atob(btoa(medium)) 41 ops/sec [38..44] → 39 ops/sec [39..39] ~ overlap (-4.6%) 38 ops/sec [37..40] → 38 ops/sec [36..39] ~ overlap (+0.1%)
classes.js — Interp: 🟢 3, 28 unch. · avg +2.0% · Bytecode: 🟢 1, 🔴 3, 27 unch. · avg +0.0%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
simple class new 44,086 ops/sec [39,999..46,715] → 40,339 ops/sec [40,108..53,933] ~ overlap (-8.5%) 52,568 ops/sec [52,326..52,977] → 52,422 ops/sec [51,671..53,394] ~ overlap (-0.3%)
class with defaults 31,393 ops/sec [31,016..33,910] → 31,611 ops/sec [31,019..36,444] ~ overlap (+0.7%) 36,093 ops/sec [35,930..36,372] → 37,916 ops/sec [34,840..40,281] ~ overlap (+5.1%)
50 instances via Array.from 1,550 ops/sec [1,382..1,662] → 1,558 ops/sec [1,436..1,662] ~ overlap (+0.5%) 1,676 ops/sec [1,671..1,677] → 1,642 ops/sec [1,622..1,656] 🔴 -2.0%
instance method call 18,660 ops/sec [17,101..19,111] → 18,679 ops/sec [18,026..21,575] ~ overlap (+0.1%) 28,084 ops/sec [27,954..28,118] → 26,560 ops/sec [26,380..27,463] 🔴 -5.4%
static method call 32,071 ops/sec [30,993..33,846] → 32,235 ops/sec [31,184..40,505] ~ overlap (+0.5%) 54,495 ops/sec [54,132..56,592] → 55,133 ops/sec [53,594..61,646] ~ overlap (+1.2%)
single-level inheritance 16,312 ops/sec [16,027..16,459] → 16,494 ops/sec [16,099..17,974] ~ overlap (+1.1%) 18,488 ops/sec [18,222..18,687] → 19,044 ops/sec [18,595..19,322] ~ overlap (+3.0%)
two-level inheritance 14,261 ops/sec [14,130..14,459] → 15,267 ops/sec [14,530..16,007] 🟢 +7.1% 14,508 ops/sec [14,367..14,696] → 14,842 ops/sec [14,316..15,841] ~ overlap (+2.3%)
private field access 20,398 ops/sec [20,117..23,762] → 21,328 ops/sec [20,029..23,492] ~ overlap (+4.6%) 14,250 ops/sec [14,155..15,845] → 14,179 ops/sec [14,013..14,573] ~ overlap (-0.5%)
private methods 22,628 ops/sec [22,101..23,712] → 22,803 ops/sec [22,441..23,298] ~ overlap (+0.8%) 16,420 ops/sec [16,338..16,546] → 17,156 ops/sec [16,264..18,625] ~ overlap (+4.5%)
getter/setter access 21,941 ops/sec [21,621..25,816] → 22,205 ops/sec [22,093..22,371] ~ overlap (+1.2%) 29,643 ops/sec [29,392..29,871] → 28,539 ops/sec [28,344..29,195] 🔴 -3.7%
class decorator (identity) 33,106 ops/sec [32,521..33,370] → 32,994 ops/sec [32,523..37,824] ~ overlap (-0.3%) 33,825 ops/sec [32,969..34,924] → 35,940 ops/sec [35,095..36,936] 🟢 +6.3%
class decorator (wrapping) 18,040 ops/sec [17,198..21,046] → 20,044 ops/sec [18,588..22,525] ~ overlap (+11.1%) 17,305 ops/sec [16,928..17,351] → 18,494 ops/sec [17,103..19,246] ~ overlap (+6.9%)
identity method decorator 25,310 ops/sec [22,937..26,945] → 23,479 ops/sec [23,243..29,667] ~ overlap (-7.2%) 28,901 ops/sec [26,989..30,280] → 27,391 ops/sec [27,162..30,066] ~ overlap (-5.2%)
wrapping method decorator 19,666 ops/sec [19,076..20,406] → 18,894 ops/sec [18,241..21,878] ~ overlap (-3.9%) 20,238 ops/sec [20,058..30,083] → 20,223 ops/sec [20,049..20,487] ~ overlap (-0.1%)
stacked method decorators (x3) 13,787 ops/sec [13,361..16,127] → 13,988 ops/sec [13,354..14,577] ~ overlap (+1.5%) 14,935 ops/sec [14,517..15,294] → 14,930 ops/sec [14,684..14,971] ~ overlap (-0.0%)
identity field decorator 25,979 ops/sec [25,678..26,753] → 27,551 ops/sec [25,922..30,599] ~ overlap (+6.1%) 26,577 ops/sec [26,408..32,081] → 30,158 ops/sec [27,545..31,051] ~ overlap (+13.5%)
field initializer decorator 21,751 ops/sec [21,514..22,044] → 21,788 ops/sec [21,668..22,081] ~ overlap (+0.2%) 24,814 ops/sec [23,066..26,336] → 26,369 ops/sec [23,175..28,347] ~ overlap (+6.3%)
getter decorator (identity) 20,750 ops/sec [20,500..22,303] → 22,295 ops/sec [20,648..26,894] ~ overlap (+7.4%) 18,382 ops/sec [18,156..22,204] → 18,417 ops/sec [18,300..19,062] ~ overlap (+0.2%)
setter decorator (identity) 16,886 ops/sec [16,825..17,020] → 19,818 ops/sec [15,602..24,081] ~ overlap (+17.4%) 14,920 ops/sec [14,688..16,695] → 14,833 ops/sec [14,797..14,895] ~ overlap (-0.6%)
static method decorator 23,690 ops/sec [23,563..23,806] → 24,446 ops/sec [24,107..32,629] 🟢 +3.2% 30,649 ops/sec [30,169..30,818] → 30,639 ops/sec [30,076..30,941] ~ overlap (-0.0%)
static field decorator 32,817 ops/sec [29,583..40,439] → 29,354 ops/sec [28,377..29,592] ~ overlap (-10.6%) 36,120 ops/sec [29,531..39,013] → 33,045 ops/sec [32,328..33,637] ~ overlap (-8.5%)
private method decorator 18,571 ops/sec [16,947..19,769] → 17,610 ops/sec [17,461..17,834] ~ overlap (-5.2%) 20,050 ops/sec [19,799..20,185] → 19,901 ops/sec [19,559..25,554] ~ overlap (-0.7%)
private field decorator 20,643 ops/sec [19,905..22,755] → 22,780 ops/sec [21,098..23,366] ~ overlap (+10.4%) 18,101 ops/sec [17,430..18,526] → 17,857 ops/sec [17,844..18,258] ~ overlap (-1.3%)
plain auto-accessor (no decorator) 34,225 ops/sec [34,169..35,084] → 38,864 ops/sec [36,757..44,170] 🟢 +13.6% 33,867 ops/sec [33,250..38,371] → 33,739 ops/sec [33,675..33,777] ~ overlap (-0.4%)
auto-accessor with decorator 21,477 ops/sec [19,576..23,685] → 23,401 ops/sec [19,555..26,073] ~ overlap (+9.0%) 20,163 ops/sec [19,892..20,347] → 20,020 ops/sec [19,287..20,105] ~ overlap (-0.7%)
decorator writing metadata 16,105 ops/sec [15,857..16,584] → 16,420 ops/sec [15,890..16,725] ~ overlap (+2.0%) 18,823 ops/sec [18,448..19,497] → 18,407 ops/sec [18,216..21,384] ~ overlap (-2.2%)
static getter read 39,814 ops/sec [37,900..43,419] → 38,760 ops/sec [38,176..39,818] ~ overlap (-2.6%) 61,748 ops/sec [52,363..71,450] → 52,620 ops/sec [52,413..52,710] ~ overlap (-14.8%)
static getter/setter pair 27,550 ops/sec [26,654..28,702] → 27,311 ops/sec [26,841..29,845] ~ overlap (-0.9%) 38,377 ops/sec [37,541..40,491] → 39,691 ops/sec [38,205..45,153] ~ overlap (+3.4%)
inherited static getter 24,905 ops/sec [24,809..24,946] → 25,026 ops/sec [24,659..27,696] ~ overlap (+0.5%) 33,640 ops/sec [33,371..42,213] → 34,112 ops/sec [33,398..44,011] ~ overlap (+1.4%)
inherited static setter 25,550 ops/sec [25,172..29,335] → 25,423 ops/sec [24,932..26,287] ~ overlap (-0.5%) 33,634 ops/sec [31,418..37,425] → 33,250 ops/sec [30,301..35,431] ~ overlap (-1.1%)
inherited static getter with this binding 19,525 ops/sec [19,290..23,119] → 19,853 ops/sec [19,763..20,024] ~ overlap (+1.7%) 28,236 ops/sec [25,661..30,017] → 26,554 ops/sec [26,315..30,071] ~ overlap (-6.0%)
closures.js — Interp: 🟢 1, 10 unch. · avg +0.7% · Bytecode: 🔴 1, 10 unch. · avg +0.1%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
closure over single variable 27,939 ops/sec [27,458..28,777] → 28,859 ops/sec [27,879..31,674] ~ overlap (+3.3%) 92,407 ops/sec [91,201..98,837] → 90,689 ops/sec [89,748..91,481] ~ overlap (-1.9%)
closure over multiple variables 37,533 ops/sec [35,520..39,110] → 35,520 ops/sec [34,948..35,847] ~ overlap (-5.4%) 85,722 ops/sec [84,066..91,355] → 85,981 ops/sec [83,366..114,522] ~ overlap (+0.3%)
nested closures 37,724 ops/sec [36,978..39,798] → 41,089 ops/sec [40,715..42,784] 🟢 +8.9% 85,595 ops/sec [82,883..88,341] → 90,148 ops/sec [85,145..104,147] ~ overlap (+5.3%)
function as argument 27,992 ops/sec [27,248..30,500] → 29,227 ops/sec [29,003..29,341] ~ overlap (+4.4%) 82,249 ops/sec [81,155..85,836] → 79,533 ops/sec [79,257..85,653] ~ overlap (-3.3%)
function returning function 36,133 ops/sec [35,839..37,468] → 36,286 ops/sec [36,170..37,001] ~ overlap (+0.4%) 94,347 ops/sec [93,081..96,467] → 91,370 ops/sec [89,060..92,684] 🔴 -3.2%
compose two functions 23,057 ops/sec [22,811..23,342] → 23,014 ops/sec [22,833..23,102] ~ overlap (-0.2%) 56,930 ops/sec [56,437..57,173] → 55,643 ops/sec [55,150..56,889] ~ overlap (-2.3%)
fn.call 49,457 ops/sec [41,293..59,585] → 49,857 ops/sec [49,596..50,479] ~ overlap (+0.8%) 70,579 ops/sec [70,004..71,929] → 70,989 ops/sec [69,743..76,661] ~ overlap (+0.6%)
fn.apply 39,912 ops/sec [38,869..48,317] → 39,200 ops/sec [38,475..51,003] ~ overlap (-1.8%) 70,269 ops/sec [64,966..90,312] → 67,800 ops/sec [67,561..68,016] ~ overlap (-3.5%)
fn.bind 43,593 ops/sec [41,252..54,216] → 41,905 ops/sec [41,748..42,090] ~ overlap (-3.9%) 92,137 ops/sec [88,205..99,923] → 91,917 ops/sec [91,149..91,989] ~ overlap (-0.2%)
recursive sum to 50 3,261 ops/sec [3,227..4,017] → 3,341 ops/sec [3,310..3,929] ~ overlap (+2.5%) 12,890 ops/sec [11,783..13,720] → 12,029 ops/sec [11,937..12,047] ~ overlap (-6.7%)
recursive tree traversal 5,061 ops/sec [4,875..7,926] → 4,970 ops/sec [4,960..5,021] ~ overlap (-1.8%) 11,622 ops/sec [11,137..12,762] → 13,446 ops/sec [10,797..19,352] ~ overlap (+15.7%)
collections.js — Interp: 🟢 1, 🔴 1, 10 unch. · avg +0.7% · Bytecode: 🟢 1, 11 unch. · avg +3.7%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
add 50 elements 3,108 ops/sec [2,985..3,461] → 2,913 ops/sec [2,906..2,926] 🔴 -6.3% 3,853 ops/sec [3,840..3,885] → 4,111 ops/sec [3,973..4,256] 🟢 +6.7%
has lookup (50 elements) 62,433 ops/sec [61,586..66,149] → 64,513 ops/sec [63,341..64,962] ~ overlap (+3.3%) 96,766 ops/sec [96,168..108,845] → 104,167 ops/sec [96,721..110,052] ~ overlap (+7.6%)
delete elements 34,983 ops/sec [33,953..36,783] → 34,747 ops/sec [34,498..37,459] ~ overlap (-0.7%) 46,423 ops/sec [45,680..48,192] → 47,217 ops/sec [46,498..48,931] ~ overlap (+1.7%)
forEach iteration 3,826 ops/sec [3,717..4,920] → 3,869 ops/sec [3,789..3,897] ~ overlap (+1.1%) 6,178 ops/sec [5,982..6,528] → 6,458 ops/sec [6,169..6,474] ~ overlap (+4.5%)
spread to array 13,496 ops/sec [11,950..15,464] → 11,900 ops/sec [11,154..18,937] ~ overlap (-11.8%) 71,750 ops/sec [67,916..78,619] → 71,543 ops/sec [71,176..77,342] ~ overlap (-0.3%)
deduplicate array 20,485 ops/sec [19,482..24,654] → 19,320 ops/sec [19,029..24,564] ~ overlap (-5.7%) 39,986 ops/sec [34,267..48,673] → 43,360 ops/sec [39,674..48,546] ~ overlap (+8.4%)
set 50 entries 2,162 ops/sec [2,134..2,195] → 2,247 ops/sec [2,130..2,402] ~ overlap (+3.9%) 2,883 ops/sec [2,850..3,683] → 2,849 ops/sec [2,823..2,851] ~ overlap (-1.2%)
get lookup (50 entries) 63,936 ops/sec [63,584..65,193] → 66,797 ops/sec [66,125..82,565] 🟢 +4.5% 84,923 ops/sec [84,467..85,493] → 84,439 ops/sec [84,130..86,277] ~ overlap (-0.6%)
has check 83,599 ops/sec [82,533..86,887] → 90,245 ops/sec [81,787..93,086] ~ overlap (+7.9%) 110,031 ops/sec [107,503..132,624] → 107,205 ops/sec [104,460..110,901] ~ overlap (-2.6%)
delete entries 35,074 ops/sec [33,157..35,218] → 40,643 ops/sec [33,959..41,498] ~ overlap (+15.9%) 44,040 ops/sec [40,624..47,673] → 42,301 ops/sec [41,444..42,867] ~ overlap (-3.9%)
forEach iteration 3,792 ops/sec [3,728..3,974] → 3,838 ops/sec [3,791..3,881] ~ overlap (+1.2%) 6,250 ops/sec [6,208..6,348] → 6,509 ops/sec [6,162..7,413] ~ overlap (+4.1%)
keys/values/entries 3,521 ops/sec [3,391..3,833] → 3,340 ops/sec [3,014..4,296] ~ overlap (-5.2%) 11,495 ops/sec [10,863..14,036] → 13,793 ops/sec [11,222..16,512] ~ overlap (+20.0%)
csv.js — Interp: 🟢 1, 12 unch. · avg +4.3% · Bytecode: 🟢 3, 🔴 1, 9 unch. · avg +2.2%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
parse simple 3-column CSV 40,236 ops/sec [37,558..44,013] → 39,905 ops/sec [37,087..44,525] ~ overlap (-0.8%) 43,076 ops/sec [42,394..54,337] → 43,773 ops/sec [43,414..45,030] ~ overlap (+1.6%)
parse 10-row CSV 11,420 ops/sec [11,150..14,012] → 12,415 ops/sec [11,308..13,450] ~ overlap (+8.7%) 11,828 ops/sec [11,699..11,885] → 12,067 ops/sec [11,631..12,394] ~ overlap (+2.0%)
parse 100-row CSV 1,823 ops/sec [1,779..1,849] → 1,898 ops/sec [1,775..2,189] ~ overlap (+4.1%) 1,844 ops/sec [1,837..1,853] → 2,135 ops/sec [2,062..2,189] 🟢 +15.8%
parse CSV with quoted fields 58,012 ops/sec [56,544..61,942] → 57,888 ops/sec [56,399..58,934] ~ overlap (-0.2%) 64,159 ops/sec [63,508..71,570] → 63,692 ops/sec [63,042..74,483] ~ overlap (-0.7%)
parse without headers (array of arrays) 5,609 ops/sec [5,358..5,987] → 6,220 ops/sec [5,564..7,180] ~ overlap (+10.9%) 5,529 ops/sec [5,480..5,797] → 5,472 ops/sec [5,450..7,545] ~ overlap (-1.0%)
parse with semicolon delimiter 8,395 ops/sec [8,332..8,418] → 8,379 ops/sec [8,247..8,673] ~ overlap (-0.2%) 8,875 ops/sec [8,275..11,658] → 8,417 ops/sec [8,255..11,830] ~ overlap (-5.2%)
stringify array of objects 54,702 ops/sec [54,107..58,497] → 55,803 ops/sec [54,465..55,946] ~ overlap (+2.0%) 63,040 ops/sec [62,106..63,292] → 65,513 ops/sec [63,585..65,899] 🟢 +3.9%
stringify array of arrays 25,354 ops/sec [22,490..26,821] → 22,487 ops/sec [22,279..26,074] ~ overlap (-11.3%) 23,235 ops/sec [23,000..23,263] → 23,480 ops/sec [22,583..24,224] ~ overlap (+1.1%)
stringify with values needing escaping 43,369 ops/sec [42,604..54,053] → 52,188 ops/sec [45,397..52,562] ~ overlap (+20.3%) 48,718 ops/sec [47,985..49,324] → 50,806 ops/sec [49,073..53,501] ~ overlap (+4.3%)
reviver converts numbers 891 ops/sec [874..919] → 910 ops/sec [877..935] ~ overlap (+2.2%) 1,061 ops/sec [1,054..1,065] → 1,117 ops/sec [1,033..1,357] ~ overlap (+5.3%)
reviver filters empty to null 7,453 ops/sec [6,683..7,470] → 7,554 ops/sec [7,503..7,581] 🟢 +1.4% 10,032 ops/sec [9,992..10,066] → 9,861 ops/sec [9,540..9,974] 🔴 -1.7%
parse then stringify 7,292 ops/sec [7,203..9,507] → 8,395 ops/sec [7,620..8,490] ~ overlap (+15.1%) 7,582 ops/sec [7,513..7,633] → 7,711 ops/sec [7,654..8,853] 🟢 +1.7%
stringify then parse 7,086 ops/sec [6,730..7,459] → 7,332 ops/sec [7,277..7,428] ~ overlap (+3.5%) 7,427 ops/sec [7,309..7,489] → 7,564 ops/sec [7,430..7,667] ~ overlap (+1.8%)
destructuring.js — Interp: 🟢 2, 20 unch. · avg +1.2% · Bytecode: 🟢 1, 🔴 2, 19 unch. · avg -2.1%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
simple array destructuring 69,430 ops/sec [64,626..82,885] → 65,411 ops/sec [63,458..67,774] ~ overlap (-5.8%) 83,326 ops/sec [82,906..83,866] → 81,344 ops/sec [81,158..107,077] ~ overlap (-2.4%)
with rest element 54,726 ops/sec [54,123..67,400] → 55,189 ops/sec [54,639..55,792] ~ overlap (+0.8%) 64,570 ops/sec [59,525..69,066] → 64,810 ops/sec [64,027..72,087] ~ overlap (+0.4%)
with defaults 66,161 ops/sec [56,955..70,645] → 66,249 ops/sec [65,422..67,936] ~ overlap (+0.1%) 89,198 ops/sec [88,427..89,845] → 89,277 ops/sec [87,233..99,230] ~ overlap (+0.1%)
skip elements 73,585 ops/sec [69,672..76,137] → 74,979 ops/sec [74,738..78,383] ~ overlap (+1.9%) 92,384 ops/sec [88,186..96,891] → 88,002 ops/sec [87,889..88,470] ~ overlap (-4.7%)
nested array destructuring 32,135 ops/sec [30,870..32,663] → 35,006 ops/sec [31,285..36,860] ~ overlap (+8.9%) 36,022 ops/sec [31,063..39,934] → 31,774 ops/sec [30,681..33,203] ~ overlap (-11.8%)
swap variables 106,591 ops/sec [100,375..110,379] → 99,904 ops/sec [91,376..114,047] ~ overlap (-6.3%) 120,851 ops/sec [119,321..124,857] → 118,844 ops/sec [118,108..119,151] 🔴 -1.7%
simple object destructuring 80,600 ops/sec [78,527..91,717] → 79,965 ops/sec [79,307..80,889] ~ overlap (-0.8%) 93,469 ops/sec [91,608..94,391] → 95,022 ops/sec [92,237..103,035] ~ overlap (+1.7%)
with defaults 87,429 ops/sec [86,410..88,128] → 87,925 ops/sec [86,028..94,158] ~ overlap (+0.6%) 135,835 ops/sec [135,109..158,845] → 134,495 ops/sec [129,385..135,362] ~ overlap (-1.0%)
with renaming 87,162 ops/sec [86,738..87,555] → 90,110 ops/sec [86,881..92,024] ~ overlap (+3.4%) 101,594 ops/sec [99,248..109,169] → 99,440 ops/sec [99,224..99,777] ~ overlap (-2.1%)
nested object destructuring 47,241 ops/sec [46,852..47,417] → 49,732 ops/sec [49,575..50,524] 🟢 +5.3% 51,341 ops/sec [50,426..52,805] → 49,005 ops/sec [48,718..50,541] ~ overlap (-4.5%)
rest properties 36,291 ops/sec [35,533..36,907] → 38,106 ops/sec [38,026..38,236] 🟢 +5.0% 53,182 ops/sec [43,636..59,082] → 43,430 ops/sec [42,658..43,844] ~ overlap (-18.3%)
object parameter 26,219 ops/sec [25,989..26,422] → 26,465 ops/sec [25,695..33,764] ~ overlap (+0.9%) 43,478 ops/sec [37,738..55,336] → 41,882 ops/sec [41,584..46,747] ~ overlap (-3.7%)
array parameter 31,276 ops/sec [31,140..31,712] → 35,504 ops/sec [30,645..39,945] ~ overlap (+13.5%) 43,036 ops/sec [41,905..43,477] → 44,403 ops/sec [41,147..51,475] ~ overlap (+3.2%)
mixed destructuring in map 8,379 ops/sec [8,309..8,394] → 8,335 ops/sec [8,317..8,783] ~ overlap (-0.5%) 11,152 ops/sec [11,118..11,345] → 11,295 ops/sec [11,241..11,359] ~ overlap (+1.3%)
forEach with array destructuring 13,926 ops/sec [13,500..16,431] → 13,583 ops/sec [13,271..13,952] ~ overlap (-2.5%) 16,037 ops/sec [15,815..17,203] → 15,544 ops/sec [15,293..15,919] ~ overlap (-3.1%)
map with array destructuring 15,649 ops/sec [15,490..15,719] → 15,570 ops/sec [15,428..16,655] ~ overlap (-0.5%) 15,237 ops/sec [15,169..15,297] → 14,970 ops/sec [14,762..15,058] 🔴 -1.8%
filter with array destructuring 15,842 ops/sec [15,552..15,997] → 15,887 ops/sec [15,642..16,381] ~ overlap (+0.3%) 16,081 ops/sec [15,534..18,237] → 15,756 ops/sec [15,675..15,840] ~ overlap (-2.0%)
reduce with array destructuring 16,915 ops/sec [15,956..17,044] → 16,995 ops/sec [16,312..17,303] ~ overlap (+0.5%) 16,710 ops/sec [16,427..17,286] → 16,166 ops/sec [15,955..16,625] ~ overlap (-3.3%)
map with object destructuring 19,095 ops/sec [18,721..19,324] → 19,364 ops/sec [19,016..19,642] ~ overlap (+1.4%) 22,589 ops/sec [22,289..22,784] → 23,205 ops/sec [22,603..25,058] ~ overlap (+2.7%)
map with nested destructuring 15,756 ops/sec [15,707..15,870] → 15,939 ops/sec [15,810..16,116] ~ overlap (+1.2%) 22,109 ops/sec [21,891..22,163] → 22,157 ops/sec [21,782..22,539] ~ overlap (+0.2%)
map with rest in destructuring 8,678 ops/sec [8,615..8,790] → 8,880 ops/sec [8,557..9,293] ~ overlap (+2.3%) 7,903 ops/sec [7,801..8,111] → 7,984 ops/sec [7,919..9,088] ~ overlap (+1.0%)
map with defaults in destructuring 10,768 ops/sec [10,183..11,024] → 10,424 ops/sec [10,386..10,458] ~ overlap (-3.2%) 17,762 ops/sec [17,484..18,255] → 18,441 ops/sec [18,262..18,645] 🟢 +3.8%
fibonacci.js — Interp: 🟢 1, 7 unch. · avg -0.7% · Bytecode: 🔴 1, 7 unch. · avg -3.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
recursive fib(15) 99 ops/sec [92..105] → 93 ops/sec [90..104] ~ overlap (-6.2%) 355 ops/sec [326..404] → 335 ops/sec [319..445] ~ overlap (-5.5%)
recursive fib(20) 9 ops/sec [8..10] → 9 ops/sec [9..9] ~ overlap (-3.2%) 30 ops/sec [29..31] → 31 ops/sec [30..32] ~ overlap (+2.9%)
recursive fib(15) typed 93 ops/sec [91..94] → 93 ops/sec [91..94] ~ overlap (+0.2%) 328 ops/sec [321..341] → 349 ops/sec [326..352] ~ overlap (+6.4%)
recursive fib(20) typed 9 ops/sec [9..9] → 9 ops/sec [9..10] ~ overlap (+0.1%) 31 ops/sec [29..33] → 30 ops/sec [29..33] ~ overlap (-3.4%)
iterative fib(20) via reduce 4,341 ops/sec [4,013..4,683] → 4,080 ops/sec [4,069..4,084] ~ overlap (-6.0%) 6,769 ops/sec [6,068..7,446] → 5,976 ops/sec [5,936..7,312] ~ overlap (-11.7%)
iterator fib(20) 2,294 ops/sec [2,271..2,444] → 2,399 ops/sec [2,320..2,412] ~ overlap (+4.6%) 4,995 ops/sec [4,811..5,414] → 4,800 ops/sec [4,685..6,240] ~ overlap (-3.9%)
iterator fib(20) via Iterator.from + take 2,176 ops/sec [2,155..2,190] → 2,257 ops/sec [2,251..2,269] 🟢 +3.7% 2,911 ops/sec [2,675..3,173] → 2,707 ops/sec [2,598..2,887] ~ overlap (-7.0%)
iterator fib(20) last value via reduce 1,882 ops/sec [1,852..1,905] → 1,904 ops/sec [1,869..1,963] ~ overlap (+1.2%) 2,324 ops/sec [2,266..2,534] → 2,218 ops/sec [2,201..2,262] 🔴 -4.5%
float16array.js — Interp: 🟢 1, 🔴 3, 28 unch. · avg -0.6% · Bytecode: 🟢 6, 🔴 1, 25 unch. · avg +2.7%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
new Float16Array(0) 89,144 ops/sec [88,903..94,458] → 91,499 ops/sec [90,620..92,098] ~ overlap (+2.6%) 106,489 ops/sec [102,908..107,227] → 107,666 ops/sec [105,303..108,705] ~ overlap (+1.1%)
new Float16Array(100) 87,219 ops/sec [86,490..91,278] → 89,297 ops/sec [88,538..89,751] ~ overlap (+2.4%) 100,983 ops/sec [99,094..102,675] → 103,507 ops/sec [99,437..104,254] ~ overlap (+2.5%)
new Float16Array(1000) 77,769 ops/sec [77,576..85,052] → 79,925 ops/sec [79,639..80,783] ~ overlap (+2.8%) 87,710 ops/sec [85,294..109,733] → 90,789 ops/sec [88,363..103,172] ~ overlap (+3.5%)
Float16Array.from([...100]) 1,588 ops/sec [1,539..1,889] → 1,549 ops/sec [1,534..1,551] ~ overlap (-2.4%) 1,584 ops/sec [1,497..1,717] → 1,576 ops/sec [1,511..1,934] ~ overlap (-0.5%)
Float16Array.of(1.5, 2.5, 3.5, 4.5, 5.5) 78,149 ops/sec [77,241..78,460] → 78,761 ops/sec [71,992..102,064] ~ overlap (+0.8%) 72,718 ops/sec [71,463..78,353] → 72,373 ops/sec [70,705..88,316] ~ overlap (-0.5%)
new Float16Array(float64Array) 25,879 ops/sec [25,679..26,161] → 25,102 ops/sec [24,714..25,577] 🔴 -3.0% 26,927 ops/sec [25,642..31,973] → 26,163 ops/sec [24,819..33,213] ~ overlap (-2.8%)
sequential write 100 elements 1,022 ops/sec [978..1,075] → 1,010 ops/sec [987..1,022] ~ overlap (-1.2%) 3,286 ops/sec [3,105..3,304] → 3,500 ops/sec [3,264..3,850] ~ overlap (+6.5%)
sequential read 100 elements 1,152 ops/sec [1,114..1,331] → 1,147 ops/sec [1,139..1,155] ~ overlap (-0.5%) 3,987 ops/sec [3,966..3,993] → 3,892 ops/sec [3,832..4,226] ~ overlap (-2.4%)
write special values (NaN, Inf, -0) 42,912 ops/sec [42,329..47,909] → 43,069 ops/sec [42,802..43,238] ~ overlap (+0.4%) 78,823 ops/sec [75,806..80,353] → 78,982 ops/sec [78,613..90,800] ~ overlap (+0.2%)
Float16Array write 1,011 ops/sec [1,003..1,029] → 1,016 ops/sec [1,010..1,026] ~ overlap (+0.5%) 3,204 ops/sec [3,108..3,224] → 3,161 ops/sec [3,099..3,216] ~ overlap (-1.3%)
Float32Array write 1,005 ops/sec [1,002..1,016] → 1,003 ops/sec [998..1,004] ~ overlap (-0.2%) 3,130 ops/sec [3,111..3,148] → 3,161 ops/sec [3,116..3,394] ~ overlap (+1.0%)
Float64Array write 1,012 ops/sec [1,004..1,018] → 1,004 ops/sec [999..1,021] ~ overlap (-0.8%) 3,301 ops/sec [3,211..3,313] → 3,393 ops/sec [3,165..3,846] ~ overlap (+2.8%)
Float16Array read 1,113 ops/sec [1,087..1,129] → 1,086 ops/sec [1,082..1,095] ~ overlap (-2.4%) 3,192 ops/sec [3,171..3,240] → 3,726 ops/sec [3,462..4,136] 🟢 +16.7%
Float32Array read 1,186 ops/sec [1,104..1,317] → 1,133 ops/sec [1,129..1,139] ~ overlap (-4.5%) 3,632 ops/sec [3,605..4,588] → 3,964 ops/sec [3,599..4,037] ~ overlap (+9.1%)
Float64Array read 1,123 ops/sec [1,114..1,304] → 1,199 ops/sec [1,171..1,203] ~ overlap (+6.7%) 3,387 ops/sec [3,323..3,402] → 3,626 ops/sec [3,607..3,708] 🟢 +7.1%
fill(1.5) 6,791 ops/sec [6,479..7,654] → 6,734 ops/sec [6,620..7,026] ~ overlap (-0.8%) 6,560 ops/sec [6,440..6,607] → 6,831 ops/sec [6,780..6,880] 🟢 +4.1%
slice() 11,073 ops/sec [10,970..11,344] → 12,208 ops/sec [11,533..14,424] 🟢 +10.3% 11,460 ops/sec [11,320..11,953] → 12,386 ops/sec [12,355..14,648] 🟢 +8.1%
map(x => x * 2) 1,963 ops/sec [1,892..2,215] → 1,946 ops/sec [1,924..2,132] ~ overlap (-0.9%) 2,124 ops/sec [2,041..2,285] → 2,206 ops/sec [2,146..2,271] ~ overlap (+3.8%)
filter(x => x > 25) 1,971 ops/sec [1,949..2,102] → 1,972 ops/sec [1,926..2,275] ~ overlap (+0.0%) 2,217 ops/sec [2,184..2,278] → 2,283 ops/sec [2,193..2,305] ~ overlap (+3.0%)
reduce (sum) 2,079 ops/sec [2,043..2,172] → 1,975 ops/sec [1,955..1,999] 🔴 -5.0% 2,226 ops/sec [2,090..2,358] → 2,006 ops/sec [1,954..2,038] 🔴 -9.9%
sort() 19,408 ops/sec [19,282..19,489] → 18,456 ops/sec [18,233..18,485] 🔴 -4.9% 20,250 ops/sec [19,999..20,792] → 21,779 ops/sec [19,997..22,378] ~ overlap (+7.6%)
indexOf() 25,544 ops/sec [25,395..26,503] → 24,771 ops/sec [24,425..30,045] ~ overlap (-3.0%) 26,402 ops/sec [26,315..26,481] → 27,429 ops/sec [27,099..28,188] 🟢 +3.9%
reverse() 27,335 ops/sec [26,849..28,207] → 27,330 ops/sec [27,309..27,357] ~ overlap (-0.0%) 29,436 ops/sec [28,800..30,100] → 30,396 ops/sec [29,089..33,070] ~ overlap (+3.3%)
toReversed() 21,930 ops/sec [21,626..23,095] → 22,381 ops/sec [22,136..24,652] ~ overlap (+2.1%) 23,184 ops/sec [22,527..23,384] → 22,874 ops/sec [22,338..26,117] ~ overlap (-1.3%)
toSorted() 11,005 ops/sec [10,975..11,072] → 11,150 ops/sec [10,829..11,298] ~ overlap (+1.3%) 11,513 ops/sec [11,279..11,649] → 11,432 ops/sec [11,282..13,647] ~ overlap (-0.7%)
create view over existing buffer 102,812 ops/sec [102,049..105,143] → 104,003 ops/sec [102,157..139,401] ~ overlap (+1.2%) 121,287 ops/sec [115,829..122,522] → 116,435 ops/sec [115,998..118,368] ~ overlap (-4.0%)
subarray() 71,163 ops/sec [68,151..72,735] → 68,277 ops/sec [65,327..78,159] ~ overlap (-4.1%) 76,458 ops/sec [73,401..100,360] → 75,365 ops/sec [74,825..75,959] ~ overlap (-1.4%)
set() from array 101,420 ops/sec [97,655..136,865] → 100,206 ops/sec [94,579..108,234] ~ overlap (-1.2%) 128,425 ops/sec [127,809..136,008] → 129,482 ops/sec [125,528..183,976] ~ overlap (+0.8%)
for-of loop 1,517 ops/sec [1,424..1,535] → 1,494 ops/sec [1,436..1,538] ~ overlap (-1.6%) 5,707 ops/sec [5,469..6,205] → 6,569 ops/sec [6,404..7,593] 🟢 +15.1%
spread into array 6,335 ops/sec [6,129..6,402] → 6,161 ops/sec [5,938..6,218] ~ overlap (-2.7%) 23,563 ops/sec [22,853..23,714] → 23,302 ops/sec [22,507..23,965] ~ overlap (-1.1%)
f16round(1.337) 187,663 ops/sec [177,740..216,918] → 176,455 ops/sec [172,764..179,286] ~ overlap (-6.0%) 230,094 ops/sec [223,372..242,456] → 237,562 ops/sec [228,932..242,802] ~ overlap (+3.2%)
f16round over 100 values 1,173 ops/sec [1,094..1,499] → 1,117 ops/sec [1,079..1,221] ~ overlap (-4.8%) 2,920 ops/sec [2,857..3,208] → 3,152 ops/sec [3,095..3,591] ~ overlap (+7.9%)
for-in/for-in.js — Interp: 🟢 1, 2 unch. · avg +1.8% · Bytecode: 🔴 1, 2 unch. · avg -0.5%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
for...in over 50 own keys 2,851 ops/sec [2,767..2,861] → 2,893 ops/sec [2,798..3,141] ~ overlap (+1.5%) 3,817 ops/sec [3,706..4,875] → 3,975 ops/sec [3,634..4,301] ~ overlap (+4.1%)
for...in over an 8-level chain of 50 shared keys 2,141 ops/sec [2,114..2,154] → 2,161 ops/sec [2,080..2,575] ~ overlap (+0.9%) 2,855 ops/sec [2,683..3,794] → 2,809 ops/sec [2,777..2,813] ~ overlap (-1.6%)
for...in over a 16-level chain of 100 shared keys 851 ops/sec [819..866] → 878 ops/sec [875..883] 🟢 +3.2% 1,123 ops/sec [1,105..1,429] → 1,078 ops/sec [1,061..1,082] 🔴 -4.1%
for-of.js — Interp: 🟢 1, 6 unch. · avg +1.8% · Bytecode: 7 unch. · avg -3.0%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
for...of with 10-element array 13,266 ops/sec [13,083..15,610] → 13,208 ops/sec [12,973..13,339] ~ overlap (-0.4%) 77,610 ops/sec [72,981..86,633] → 73,094 ops/sec [72,275..81,057] ~ overlap (-5.8%)
for...of with 100-element array 1,548 ops/sec [1,517..2,021] → 1,730 ops/sec [1,410..1,870] ~ overlap (+11.8%) 10,091 ops/sec [9,563..10,181] → 10,006 ops/sec [9,865..10,218] ~ overlap (-0.8%)
for...of with string (10 chars) 10,522 ops/sec [10,233..10,604] → 10,613 ops/sec [9,595..10,908] ~ overlap (+0.9%) 28,053 ops/sec [25,167..29,322] → 26,629 ops/sec [26,440..27,864] ~ overlap (-5.1%)
for...of with Set (10 elements) 13,701 ops/sec [13,626..13,724] → 13,739 ops/sec [13,533..14,386] ~ overlap (+0.3%) 88,877 ops/sec [83,695..95,658] → 82,718 ops/sec [81,606..83,778] ~ overlap (-6.9%)
for...of with Map entries (10 entries) 7,505 ops/sec [7,180..7,531] → 7,329 ops/sec [6,540..8,209] ~ overlap (-2.4%) 12,179 ops/sec [12,110..12,762] → 12,073 ops/sec [11,758..16,263] ~ overlap (-0.9%)
for...of with destructuring 8,042 ops/sec [8,024..8,196] → 8,260 ops/sec [8,222..8,946] 🟢 +2.7% 14,427 ops/sec [14,306..14,452] → 14,756 ops/sec [14,413..16,194] ~ overlap (+2.3%)
for-await-of with sync array 8,717 ops/sec [8,458..8,765] → 8,682 ops/sec [8,654..8,912] ~ overlap (-0.4%) 1,847 ops/sec [1,746..1,901] → 1,774 ops/sec [1,525..1,852] ~ overlap (-3.9%)
generators.js — Interp: 🟢 1, 3 unch. · avg +1.0% · Bytecode: 🔴 2, 2 unch. · avg -5.1%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
manual next over object generator 689 ops/sec [665..695] → 711 ops/sec [703..720] 🟢 +3.2% 1,044 ops/sec [1,036..1,084] → 1,003 ops/sec [995..1,007] 🔴 -3.9%
for...of over object generator 991 ops/sec [965..1,206] → 1,021 ops/sec [981..1,046] ~ overlap (+3.0%) 1,464 ops/sec [1,455..1,487] → 1,436 ops/sec [1,417..1,653] ~ overlap (-2.0%)
yield delegation 1,045 ops/sec [993..1,233] → 1,057 ops/sec [1,019..1,136] ~ overlap (+1.2%) 1,507 ops/sec [1,501..1,588] → 1,445 ops/sec [1,430..1,586] ~ overlap (-4.1%)
class generator method 1,061 ops/sec [1,021..1,199] → 1,025 ops/sec [1,011..1,028] ~ overlap (-3.4%) 1,591 ops/sec [1,478..1,744] → 1,423 ops/sec [1,403..1,430] 🔴 -10.5%
intl.js — Interp: 🟢 1, 5 unch. · avg +0.9% · Bytecode: 🔴 4, 2 unch. · avg -6.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
format decimal 25,716 ops/sec [25,506..27,630] → 25,082 ops/sec [23,355..34,153] ~ overlap (-2.5%) 29,781 ops/sec [27,671..31,534] → 24,311 ops/sec [23,609..24,544] 🔴 -18.4%
format currency 19,936 ops/sec [19,410..20,094] → 20,504 ops/sec [19,631..21,690] ~ overlap (+2.8%) 22,031 ops/sec [21,838..22,126] → 19,305 ops/sec [19,040..20,538] 🔴 -12.4%
format UTC date 2,462 ops/sec [2,417..2,489] → 2,635 ops/sec [2,502..2,822] 🟢 +7.0% 2,487 ops/sec [2,471..2,498] → 2,376 ops/sec [2,372..2,421] 🔴 -4.5%
formatRange UTC dates 3,096 ops/sec [3,041..3,110] → 3,237 ops/sec [3,090..3,383] ~ overlap (+4.5%) 3,026 ops/sec [2,999..3,095] → 3,013 ops/sec [2,978..3,027] ~ overlap (-0.4%)
compare numeric strings 100,633 ops/sec [94,607..107,997] → 94,953 ops/sec [89,459..108,273] ~ overlap (-5.6%) 102,406 ops/sec [101,214..104,820] → 100,635 ops/sec [100,223..100,935] 🔴 -1.7%
sort short string list 19,042 ops/sec [18,739..19,375] → 18,853 ops/sec [18,274..18,981] ~ overlap (-1.0%) 19,660 ops/sec [18,895..19,886] → 19,619 ops/sec [19,106..20,383] ~ overlap (-0.2%)
iterators.js — Interp: 🟢 1, 🔴 5, 36 unch. · avg -2.2% · Bytecode: 🟢 2, 🔴 1, 39 unch. · avg -0.2%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
Iterator.from({next}).toArray() — 20 elements 2,833 ops/sec [2,768..2,878] → 2,756 ops/sec [2,728..2,814] ~ overlap (-2.7%) 3,905 ops/sec [3,851..3,927] → 3,884 ops/sec [3,868..3,920] ~ overlap (-0.5%)
Iterator.from({next}).toArray() — 50 elements 1,190 ops/sec [1,075..1,287] → 1,238 ops/sec [1,167..1,306] ~ overlap (+4.0%) 1,664 ops/sec [1,637..1,881] → 1,644 ops/sec [1,637..1,686] ~ overlap (-1.2%)
spread pre-wrapped iterator — 20 elements 2,966 ops/sec [2,733..3,104] → 3,071 ops/sec [2,820..3,464] ~ overlap (+3.6%) 5,349 ops/sec [5,319..5,379] → 5,494 ops/sec [5,330..5,571] ~ overlap (+2.7%)
Iterator.from({next}).forEach — 50 elements 841 ops/sec [826..898] → 884 ops/sec [842..1,009] ~ overlap (+5.0%) 1,253 ops/sec [1,237..1,267] → 1,263 ops/sec [1,214..1,303] ~ overlap (+0.8%)
Iterator.from({next}).reduce — 50 elements 925 ops/sec [905..929] → 905 ops/sec [842..982] ~ overlap (-2.2%) 1,372 ops/sec [1,235..1,430] → 1,259 ops/sec [1,238..1,268] ~ overlap (-8.3%)
wrap array iterator 17,958 ops/sec [17,092..18,245] → 18,703 ops/sec [16,691..20,904] ~ overlap (+4.1%) 18,326 ops/sec [17,244..19,416] → 17,501 ops/sec [16,963..18,664] ~ overlap (-4.5%)
wrap plain {next()} object 1,885 ops/sec [1,846..1,887] → 1,897 ops/sec [1,863..2,004] ~ overlap (+0.6%) 2,634 ops/sec [2,618..2,699] → 2,713 ops/sec [2,705..3,015] 🟢 +3.0%
map + toArray (50 elements) 725 ops/sec [722..727] → 724 ops/sec [687..1,024] ~ overlap (-0.1%) 954 ops/sec [924..956] → 916 ops/sec [880..934] ~ overlap (-4.0%)
filter + toArray (50 elements) 771 ops/sec [754..819] → 758 ops/sec [754..760] ~ overlap (-1.7%) 971 ops/sec [955..1,003] → 981 ops/sec [978..1,126] ~ overlap (+1.0%)
take(10) + toArray (50 element source) 4,000 ops/sec [3,924..4,081] → 3,813 ops/sec [3,663..3,866] 🔴 -4.7% 4,767 ops/sec [4,716..4,909] → 4,992 ops/sec [4,809..5,689] ~ overlap (+4.7%)
drop(40) + toArray (50 element source) 1,007 ops/sec [985..1,103] → 1,031 ops/sec [954..1,179] ~ overlap (+2.4%) 1,335 ops/sec [1,262..1,476] → 1,343 ops/sec [1,324..1,349] ~ overlap (+0.6%)
chained map + filter + take (100 element source) 1,335 ops/sec [1,183..1,355] → 1,202 ops/sec [1,148..1,330] ~ overlap (-10.0%) 1,406 ops/sec [1,397..1,649] → 1,443 ops/sec [1,442..1,452] ~ overlap (+2.6%)
some + every (50 elements) 532 ops/sec [512..682] → 526 ops/sec [486..567] ~ overlap (-1.0%) 728 ops/sec [699..753] → 712 ops/sec [705..726] ~ overlap (-2.2%)
find (50 elements) 1,131 ops/sec [1,125..1,186] → 1,205 ops/sec [1,138..1,259] ~ overlap (+6.5%) 1,568 ops/sec [1,477..1,906] → 1,557 ops/sec [1,542..1,710] ~ overlap (-0.7%)
concat 2 arrays (10 + 10 elements) 6,858 ops/sec [6,468..9,799] → 6,484 ops/sec [6,422..6,515] ~ overlap (-5.5%) 6,756 ops/sec [6,306..8,414] → 6,820 ops/sec [6,257..7,727] ~ overlap (+1.0%)
concat 5 arrays (10 elements each) 3,553 ops/sec [2,841..4,209] → 2,731 ops/sec [2,713..2,783] 🔴 -23.1% 2,751 ops/sec [2,697..2,852] → 2,871 ops/sec [2,828..4,337] ~ overlap (+4.4%)
concat 2 arrays (20 + 20 elements) 3,907 ops/sec [3,554..4,902] → 3,570 ops/sec [3,470..4,329] ~ overlap (-8.6%) 3,547 ops/sec [3,437..4,078] → 3,586 ops/sec [3,563..5,601] ~ overlap (+1.1%)
concat + filter + toArray (20 + 20 elements) 1,558 ops/sec [1,460..1,565] → 1,553 ops/sec [1,473..1,762] ~ overlap (-0.3%) 1,640 ops/sec [1,560..1,678] → 1,599 ops/sec [1,091..2,406] ~ overlap (-2.5%)
concat + map + take (20 + 20 elements, take 10) 3,867 ops/sec [3,846..4,836] → 3,794 ops/sec [3,655..4,895] ~ overlap (-1.9%) 3,855 ops/sec [3,823..3,883] → 3,874 ops/sec [3,785..3,898] ~ overlap (+0.5%)
concat Sets (15 + 15 elements) 4,853 ops/sec [4,827..4,866] → 4,630 ops/sec [4,545..4,669] 🔴 -4.6% 4,754 ops/sec [4,738..4,762] → 4,686 ops/sec [4,619..4,787] ~ overlap (-1.4%)
concat strings (13 + 13 characters) 6,220 ops/sec [5,311..8,444] → 5,084 ops/sec [4,916..6,468] ~ overlap (-18.3%) 5,093 ops/sec [5,071..5,111] → 5,795 ops/sec [5,330..6,445] 🟢 +13.8%
zip 2 arrays (10 + 10 elements) 12,352 ops/sec [12,081..14,729] → 11,682 ops/sec [11,316..12,283] ~ overlap (-5.4%) 11,739 ops/sec [11,673..12,229] → 12,103 ops/sec [11,875..12,414] ~ overlap (+3.1%)
zip 3 arrays (10 elements each) 11,403 ops/sec [11,152..11,442] → 11,200 ops/sec [11,006..12,819] ~ overlap (-1.8%) 11,368 ops/sec [10,762..11,444] → 11,243 ops/sec [11,153..11,487] ~ overlap (-1.1%)
zip 2 arrays (20 + 20 elements) 7,131 ops/sec [6,575..7,815] → 7,100 ops/sec [7,060..7,117] ~ overlap (-0.4%) 7,774 ops/sec [7,468..8,074] → 7,066 ops/sec [6,985..7,112] 🔴 -9.1%
zip 2 arrays (50 + 50 elements) 3,332 ops/sec [3,253..3,384] → 3,176 ops/sec [3,019..3,739] ~ overlap (-4.7%) 3,209 ops/sec [3,191..3,220] → 3,045 ops/sec [2,686..3,258] ~ overlap (-5.1%)
zip shortest mode (20 + 10 elements) 12,210 ops/sec [11,602..13,584] → 13,768 ops/sec [12,119..14,588] ~ overlap (+12.8%) 11,967 ops/sec [10,881..11,986] → 11,945 ops/sec [11,055..12,328] ~ overlap (-0.2%)
zip longest mode (10 + 20 elements) 7,056 ops/sec [6,797..7,594] → 7,749 ops/sec [7,704..7,789] 🟢 +9.8% 6,624 ops/sec [6,479..6,839] → 6,437 ops/sec [6,250..7,675] ~ overlap (-2.8%)
zip strict mode (20 + 20 elements) 7,475 ops/sec [7,173..8,518] → 6,934 ops/sec [6,906..6,977] 🔴 -7.2% 7,687 ops/sec [6,659..8,050] → 6,989 ops/sec [6,637..7,612] ~ overlap (-9.1%)
zip + map + toArray (20 + 20 elements) 2,349 ops/sec [2,311..2,380] → 2,284 ops/sec [2,233..2,610] ~ overlap (-2.8%) 2,128 ops/sec [2,103..2,306] → 2,098 ops/sec [2,027..2,241] ~ overlap (-1.4%)
zip + filter + toArray (20 + 20 elements) 2,689 ops/sec [2,457..2,753] → 2,397 ops/sec [2,366..2,801] ~ overlap (-10.9%) 2,339 ops/sec [2,269..2,344] → 2,347 ops/sec [2,183..2,384] ~ overlap (+0.3%)
zip Sets (15 + 15 elements) 9,484 ops/sec [9,278..10,455] → 10,015 ops/sec [9,140..12,260] ~ overlap (+5.6%) 9,304 ops/sec [9,079..11,824] → 9,968 ops/sec [8,705..10,913] ~ overlap (+7.1%)
zipKeyed 2 keys (10 elements each) 11,999 ops/sec [11,950..12,017] → 11,716 ops/sec [11,146..13,797] ~ overlap (-2.4%) 11,422 ops/sec [11,139..12,231] → 11,723 ops/sec [11,339..12,219] ~ overlap (+2.6%)
zipKeyed 3 keys (20 elements each) 7,337 ops/sec [6,163..9,074] → 6,206 ops/sec [5,796..7,202] ~ overlap (-15.4%) 5,722 ops/sec [5,631..6,037] → 5,828 ops/sec [5,731..5,878] ~ overlap (+1.9%)
zipKeyed longest mode (10 + 20 elements) 7,412 ops/sec [6,975..7,647] → 7,457 ops/sec [6,789..7,983] ~ overlap (+0.6%) 6,209 ops/sec [6,145..7,769] → 6,339 ops/sec [6,204..6,568] ~ overlap (+2.1%)
zipKeyed strict mode (20 + 20 elements) 7,345 ops/sec [6,907..8,367] → 6,729 ops/sec [6,666..10,252] ~ overlap (-8.4%) 6,454 ops/sec [6,236..7,605] → 6,562 ops/sec [6,543..6,581] ~ overlap (+1.7%)
zipKeyed + filter + map (20 elements) 2,242 ops/sec [1,988..2,424] → 2,042 ops/sec [1,994..2,108] ~ overlap (-8.9%) 2,257 ops/sec [2,220..2,561] → 2,225 ops/sec [2,216..2,235] ~ overlap (-1.4%)
array.values().map().filter().toArray() 923 ops/sec [861..1,087] → 914 ops/sec [839..1,053] ~ overlap (-1.0%) 884 ops/sec [853..895] → 868 ops/sec [857..878] ~ overlap (-1.8%)
array.values().take(5).toArray() 15,799 ops/sec [15,339..16,123] → 16,082 ops/sec [14,691..18,692] ~ overlap (+1.8%) 14,172 ops/sec [14,013..15,224] → 15,165 ops/sec [14,714..17,975] ~ overlap (+7.0%)
array.values().drop(45).toArray() 3,264 ops/sec [2,951..3,431] → 4,007 ops/sec [3,192..4,262] ~ overlap (+22.8%) 3,362 ops/sec [2,920..4,321] → 3,101 ops/sec [3,069..3,369] ~ overlap (-7.8%)
map.entries() chained helpers 1,227 ops/sec [1,191..1,408] → 1,177 ops/sec [1,168..1,745] ~ overlap (-4.1%) 1,135 ops/sec [1,084..1,215] → 1,117 ops/sec [1,116..1,122] ~ overlap (-1.5%)
set.values() chained helpers 2,083 ops/sec [2,061..2,407] → 2,035 ops/sec [2,018..2,061] ~ overlap (-2.3%) 2,136 ops/sec [2,073..2,282] → 2,145 ops/sec [2,074..2,409] ~ overlap (+0.4%)
string iterator map + toArray 2,366 ops/sec [2,168..2,409] → 2,073 ops/sec [2,043..2,077] 🔴 -12.4% 2,225 ops/sec [1,981..2,364] → 2,140 ops/sec [2,092..2,477] ~ overlap (-3.8%)
json.js — Interp: 🟢 1, 22 unch. · avg -0.9% · Bytecode: 🟢 5, 🔴 3, 15 unch. · avg +2.2%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
parse simple object 58,857 ops/sec [58,378..59,295] → 59,052 ops/sec [56,179..62,119] ~ overlap (+0.3%) 66,670 ops/sec [66,546..66,689] → 60,757 ops/sec [59,888..62,514] 🔴 -8.9%
parse nested object 40,849 ops/sec [40,011..46,669] → 39,594 ops/sec [39,200..41,320] ~ overlap (-3.1%) 44,323 ops/sec [44,216..44,563] → 41,789 ops/sec [41,542..42,263] 🔴 -5.7%
parse array of objects 26,129 ops/sec [25,991..26,353] → 27,985 ops/sec [26,176..34,150] ~ overlap (+7.1%) 26,662 ops/sec [26,424..29,129] → 25,453 ops/sec [25,330..28,960] ~ overlap (-4.5%)
parse large flat object 28,421 ops/sec [24,185..31,181] → 28,470 ops/sec [28,364..28,569] ~ overlap (+0.2%) 28,463 ops/sec [27,994..28,866] → 31,633 ops/sec [28,198..33,605] ~ overlap (+11.1%)
parse mixed types 32,336 ops/sec [29,584..34,825] → 31,233 ops/sec [29,738..33,657] ~ overlap (-3.4%) 33,483 ops/sec [33,061..33,566] → 34,739 ops/sec [33,014..40,407] ~ overlap (+3.8%)
stringify simple object 55,789 ops/sec [54,887..58,301] → 58,008 ops/sec [56,573..62,462] ~ overlap (+4.0%) 54,997 ops/sec [54,796..55,192] → 61,378 ops/sec [55,513..63,027] 🟢 +11.6%
stringify nested object 33,923 ops/sec [33,399..39,118] → 34,570 ops/sec [33,929..42,626] ~ overlap (+1.9%) 33,213 ops/sec [30,749..34,440] → 32,039 ops/sec [31,697..37,206] ~ overlap (-3.5%)
stringify array of objects 16,078 ops/sec [16,005..16,276] → 16,508 ops/sec [15,792..17,161] ~ overlap (+2.7%) 16,709 ops/sec [15,607..19,123] → 16,367 ops/sec [16,293..16,710] ~ overlap (-2.0%)
stringify mixed types 23,499 ops/sec [23,370..23,612] → 23,968 ops/sec [23,498..25,471] ~ overlap (+2.0%) 21,604 ops/sec [21,251..23,272] → 25,140 ops/sec [22,509..27,678] ~ overlap (+16.4%)
reviver doubles numbers 10,031 ops/sec [9,837..11,199] → 9,813 ops/sec [9,079..9,968] ~ overlap (-2.2%) 16,852 ops/sec [13,775..21,351] → 14,448 ops/sec [14,243..16,889] ~ overlap (-14.3%)
reviver filters properties 10,499 ops/sec [9,804..12,850] → 10,200 ops/sec [9,802..11,163] ~ overlap (-2.8%) 12,701 ops/sec [12,406..13,566] → 12,695 ops/sec [12,690..12,700] ~ overlap (-0.1%)
reviver on nested object 12,373 ops/sec [11,608..12,854] → 11,890 ops/sec [11,867..11,931] ~ overlap (-3.9%) 15,243 ops/sec [15,103..16,464] → 16,794 ops/sec [14,943..20,582] ~ overlap (+10.2%)
reviver on array 6,170 ops/sec [5,881..6,904] → 5,989 ops/sec [5,825..6,104] ~ overlap (-2.9%) 8,875 ops/sec [8,840..8,903] → 8,875 ops/sec [6,780..12,064] ~ overlap (-0.0%)
replacer function doubles numbers 10,708 ops/sec [10,410..10,963] → 10,813 ops/sec [10,407..11,714] ~ overlap (+1.0%) 15,127 ops/sec [14,312..17,830] → 16,035 ops/sec [14,622..17,038] ~ overlap (+6.0%)
replacer function excludes properties 14,321 ops/sec [13,798..15,519] → 14,522 ops/sec [14,287..17,014] ~ overlap (+1.4%) 18,832 ops/sec [18,686..20,714] → 18,319 ops/sec [18,108..18,335] 🔴 -2.7%
array replacer (allowlist) 40,301 ops/sec [37,578..41,152] → 38,182 ops/sec [37,452..40,844] ~ overlap (-5.3%) 35,425 ops/sec [31,502..38,201] → 35,248 ops/sec [33,740..51,486] ~ overlap (-0.5%)
stringify with 2-space indent 30,942 ops/sec [30,809..31,571] → 31,419 ops/sec [30,929..32,716] ~ overlap (+1.5%) 28,053 ops/sec [27,969..28,255] → 30,664 ops/sec [29,196..34,232] 🟢 +9.3%
stringify with tab indent 32,344 ops/sec [30,973..32,649] → 32,379 ops/sec [31,590..34,826] ~ overlap (+0.1%) 27,839 ops/sec [27,702..27,886] → 30,224 ops/sec [29,221..30,702] 🟢 +8.6%
stringify deeply nested object with 2-space indent 7,909 ops/sec [6,766..9,389] → 6,606 ops/sec [6,509..7,857] ~ overlap (-16.5%) 6,323 ops/sec [6,272..6,426] → 6,600 ops/sec [6,514..7,220] 🟢 +4.4%
stringify deeply nested array with 2-space indent 9,564 ops/sec [9,264..10,303] → 9,381 ops/sec [9,263..10,513] ~ overlap (-1.9%) 9,559 ops/sec [9,521..9,610] → 9,534 ops/sec [9,177..12,054] ~ overlap (-0.3%)
stringify very deeply nested object with 2-space indent 1,188 ops/sec [1,172..1,313] → 1,188 ops/sec [1,168..1,210] ~ overlap (+0.1%) 1,142 ops/sec [1,103..1,173] → 1,108 ops/sec [1,092..1,116] ~ overlap (-3.0%)
parse then stringify 19,762 ops/sec [19,556..19,938] → 20,187 ops/sec [20,015..23,164] 🟢 +2.2% 20,098 ops/sec [19,966..20,235] → 21,539 ops/sec [19,878..21,760] ~ overlap (+7.2%)
stringify then parse 12,669 ops/sec [11,929..13,600] → 12,189 ops/sec [12,017..14,872] ~ overlap (-3.8%) 11,859 ops/sec [11,803..11,964] → 12,870 ops/sec [12,477..13,607] 🟢 +8.5%
jsx.jsx — Interp: 21 unch. · avg +1.1% · Bytecode: 🟢 1, 🔴 1, 19 unch. · avg -3.6%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
simple element 87,702 ops/sec [73,753..88,839] → 79,593 ops/sec [77,257..81,200] ~ overlap (-9.2%) 86,940 ops/sec [85,091..106,904] → 84,435 ops/sec [82,459..89,725] ~ overlap (-2.9%)
self-closing element 81,258 ops/sec [80,337..81,576] → 79,711 ops/sec [71,360..88,741] ~ overlap (-1.9%) 91,976 ops/sec [91,726..92,642] → 91,061 ops/sec [88,070..98,159] ~ overlap (-1.0%)
element with string attribute 69,483 ops/sec [66,754..72,559] → 64,308 ops/sec [61,075..76,916] ~ overlap (-7.4%) 78,460 ops/sec [71,185..90,578] → 71,177 ops/sec [68,598..89,027] ~ overlap (-9.3%)
element with multiple attributes 64,172 ops/sec [56,707..67,790] → 60,784 ops/sec [55,658..61,677] ~ overlap (-5.3%) 51,889 ops/sec [49,177..54,231] → 55,286 ops/sec [50,224..66,844] ~ overlap (+6.5%)
element with expression attribute 59,402 ops/sec [58,005..60,148] → 58,288 ops/sec [56,907..69,766] ~ overlap (-1.9%) 72,386 ops/sec [68,800..87,389] → 66,968 ops/sec [66,448..87,341] ~ overlap (-7.5%)
text child 77,467 ops/sec [76,165..77,832] → 77,146 ops/sec [73,248..94,810] ~ overlap (-0.4%) 86,837 ops/sec [82,519..96,993] → 84,041 ops/sec [80,833..105,444] ~ overlap (-3.2%)
expression child 71,979 ops/sec [69,148..79,148] → 68,687 ops/sec [68,582..70,664] ~ overlap (-4.6%) 90,900 ops/sec [80,734..100,029] → 81,122 ops/sec [79,244..81,792] ~ overlap (-10.8%)
mixed text and expression 71,470 ops/sec [67,089..77,544] → 68,874 ops/sec [65,986..74,821] ~ overlap (-3.6%) 81,306 ops/sec [72,566..98,461] → 74,046 ops/sec [73,457..74,184] ~ overlap (-8.9%)
nested elements (3 levels) 31,872 ops/sec [30,144..36,587] → 30,827 ops/sec [29,930..31,812] ~ overlap (-3.3%) 36,313 ops/sec [33,132..39,225] → 32,795 ops/sec [31,549..48,119] ~ overlap (-9.7%)
sibling children 22,793 ops/sec [22,659..26,060] → 25,397 ops/sec [22,518..30,052] ~ overlap (+11.4%) 24,478 ops/sec [23,890..26,722] → 24,340 ops/sec [24,097..37,512] ~ overlap (-0.6%)
component element 55,906 ops/sec [54,355..68,606] → 62,219 ops/sec [55,507..64,161] ~ overlap (+11.3%) 65,654 ops/sec [65,488..66,283] → 62,284 ops/sec [61,882..63,106] 🔴 -5.1%
component with children 35,579 ops/sec [35,232..43,627] → 40,162 ops/sec [35,213..45,195] ~ overlap (+12.9%) 39,916 ops/sec [39,272..40,225] → 38,959 ops/sec [36,444..40,054] ~ overlap (-2.4%)
dotted component 48,640 ops/sec [39,970..57,194] → 48,705 ops/sec [40,056..63,246] ~ overlap (+0.1%) 51,993 ops/sec [51,123..52,172] → 51,155 ops/sec [49,894..51,652] ~ overlap (-1.6%)
empty fragment 78,077 ops/sec [77,400..93,031] → 78,035 ops/sec [75,406..87,392] ~ overlap (-0.1%) 90,751 ops/sec [89,926..93,028] → 95,642 ops/sec [94,659..96,415] 🟢 +5.4%
fragment with children 22,810 ops/sec [22,508..24,451] → 23,005 ops/sec [22,594..23,888] ~ overlap (+0.9%) 24,348 ops/sec [23,878..24,777] → 24,627 ops/sec [24,078..34,533] ~ overlap (+1.1%)
spread attributes 38,736 ops/sec [37,850..47,058] → 40,929 ops/sec [39,586..46,005] ~ overlap (+5.7%) 38,694 ops/sec [37,638..38,847] → 38,051 ops/sec [37,653..52,265] ~ overlap (-1.7%)
spread with overrides 33,895 ops/sec [33,165..35,140] → 34,600 ops/sec [34,510..34,961] ~ overlap (+2.1%) 32,630 ops/sec [32,146..34,148] → 32,714 ops/sec [32,569..37,108] ~ overlap (+0.3%)
shorthand props 56,454 ops/sec [54,756..56,874] → 61,658 ops/sec [56,639..69,097] ~ overlap (+9.2%) 54,748 ops/sec [54,336..55,280] → 54,862 ops/sec [53,003..58,015] ~ overlap (+0.2%)
nav bar structure 11,907 ops/sec [11,212..12,818] → 11,256 ops/sec [11,142..18,197] ~ overlap (-5.5%) 11,735 ops/sec [10,926..12,272] → 10,896 ops/sec [10,221..11,079] ~ overlap (-7.2%)
card component tree 13,267 ops/sec [12,784..16,542] → 14,571 ops/sec [13,068..20,845] ~ overlap (+9.8%) 14,438 ops/sec [12,438..17,034] → 12,379 ops/sec [12,094..12,939] ~ overlap (-14.3%)
10 list items via Array.from 5,829 ops/sec [5,561..5,872] → 6,010 ops/sec [5,596..8,413] ~ overlap (+3.1%) 5,307 ops/sec [5,186..5,472] → 5,111 ops/sec [4,991..6,392] ~ overlap (-3.7%)
modules.js — Interp: 9 unch. · avg +3.3% · Bytecode: 🔴 2, 7 unch. · avg -4.6%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
call imported function 127,063 ops/sec [122,683..130,257] → 132,045 ops/sec [127,629..150,070] ~ overlap (+3.9%) 48,053 ops/sec [43,991..52,993] → 45,946 ops/sec [44,959..55,237] ~ overlap (-4.4%)
call two imported functions 72,318 ops/sec [69,733..72,498] → 72,711 ops/sec [70,128..74,273] ~ overlap (+0.5%) 24,903 ops/sec [24,175..25,975] → 23,495 ops/sec [21,975..25,129] ~ overlap (-5.7%)
read imported constant 353,678 ops/sec [343,746..374,059] → 386,192 ops/sec [352,031..403,557] ~ overlap (+9.2%) 47,815 ops/sec [47,710..48,596] → 45,839 ops/sec [45,455..45,921] 🔴 -4.1%
read imported string 350,906 ops/sec [347,930..355,353] → 339,079 ops/sec [330,731..351,652] ~ overlap (-3.4%) 48,974 ops/sec [47,643..52,156] → 45,357 ops/sec [43,431..57,182] ~ overlap (-7.4%)
read JSON string property 351,992 ops/sec [348,534..355,516] → 411,284 ops/sec [339,086..423,595] ~ overlap (+16.8%) 48,342 ops/sec [48,067..48,889] → 44,787 ops/sec [43,819..46,090] 🔴 -7.4%
read JSON number property 355,759 ops/sec [294,757..430,954] → 357,384 ops/sec [343,143..367,052] ~ overlap (+0.5%) 51,220 ops/sec [46,445..60,609] → 47,296 ops/sec [46,620..51,645] ~ overlap (-7.7%)
read JSON boolean property 343,570 ops/sec [331,564..408,982] → 358,086 ops/sec [342,235..369,220] ~ overlap (+4.2%) 54,810 ops/sec [49,016..55,346] → 48,280 ops/sec [45,177..49,322] ~ overlap (-11.9%)
read JSON array property 354,564 ops/sec [335,469..372,023] → 351,933 ops/sec [339,836..361,548] ~ overlap (-0.7%) 48,963 ops/sec [45,570..51,137] → 50,043 ops/sec [49,420..51,168] ~ overlap (+2.2%)
read multiple JSON properties 200,271 ops/sec [194,933..240,442] → 198,354 ops/sec [189,896..202,037] ~ overlap (-1.0%) 17,193 ops/sec [16,801..17,467] → 17,961 ops/sec [17,151..23,910] ~ overlap (+4.5%)
numbers.js — Interp: 🟢 1, 🔴 1, 10 unch. · avg +1.7% · Bytecode: 🔴 1, 11 unch. · avg +2.4%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
integer arithmetic 106,633 ops/sec [95,842..143,527] → 94,757 ops/sec [92,556..96,304] ~ overlap (-11.1%) 367,428 ops/sec [288,045..440,024] → 356,178 ops/sec [340,993..422,337] ~ overlap (-3.1%)
floating point arithmetic 114,888 ops/sec [111,957..127,023] → 109,602 ops/sec [108,540..109,724] 🔴 -4.6% 219,700 ops/sec [211,411..260,062] → 204,113 ops/sec [203,669..204,944] 🔴 -7.1%
number coercion 43,662 ops/sec [39,038..48,370] → 41,967 ops/sec [41,176..44,025] ~ overlap (-3.9%) 61,293 ops/sec [58,334..64,885] → 60,449 ops/sec [58,509..61,121] ~ overlap (-1.4%)
toFixed 34,465 ops/sec [33,791..40,655] → 35,282 ops/sec [32,418..39,624] ~ overlap (+2.4%) 37,121 ops/sec [35,419..38,402] → 40,391 ops/sec [34,040..46,661] ~ overlap (+8.8%)
toString 51,764 ops/sec [49,805..60,200] → 54,996 ops/sec [50,834..57,949] ~ overlap (+6.2%) 63,460 ops/sec [60,126..77,780] → 72,466 ops/sec [58,077..79,205] ~ overlap (+14.2%)
toString non-integer (shortest round-trip) 4,605 ops/sec [4,372..4,796] → 5,899 ops/sec [5,584..6,282] 🟢 +28.1% 6,402 ops/sec [5,374..6,897] → 7,043 ops/sec [5,803..9,250] ~ overlap (+10.0%)
valueOf 73,506 ops/sec [69,511..80,403] → 71,656 ops/sec [71,280..72,805] ~ overlap (-2.5%) 91,310 ops/sec [90,214..92,039] → 90,473 ops/sec [86,811..96,276] ~ overlap (-0.9%)
toPrecision 24,408 ops/sec [23,720..27,481] → 24,825 ops/sec [24,788..26,000] ~ overlap (+1.7%) 25,030 ops/sec [24,696..30,839] → 26,122 ops/sec [25,440..27,027] ~ overlap (+4.4%)
Number.isNaN 79,819 ops/sec [77,073..87,289] → 84,591 ops/sec [78,597..92,975] ~ overlap (+6.0%) 103,362 ops/sec [99,387..109,526] → 101,548 ops/sec [100,936..102,990] ~ overlap (-1.8%)
Number.isFinite 77,617 ops/sec [74,510..79,503] → 78,285 ops/sec [77,938..95,602] ~ overlap (+0.9%) 92,369 ops/sec [87,735..93,943] → 90,786 ops/sec [88,899..94,317] ~ overlap (-1.7%)
Number.isInteger 81,325 ops/sec [79,728..94,570] → 79,413 ops/sec [78,884..82,178] ~ overlap (-2.4%) 98,088 ops/sec [91,878..110,846] → 100,880 ops/sec [95,495..133,767] ~ overlap (+2.8%)
Number.parseInt and parseFloat 74,520 ops/sec [65,498..88,148] → 74,378 ops/sec [65,186..81,554] ~ overlap (-0.2%) 72,416 ops/sec [71,871..73,566] → 75,890 ops/sec [72,880..88,247] ~ overlap (+4.8%)
objects.js — Interp: 🟢 1, 6 unch. · avg +3.4% · Bytecode: 🔴 1, 6 unch. · avg -5.8%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
create simple object 148,736 ops/sec [146,849..189,587] → 149,905 ops/sec [147,723..150,534] ~ overlap (+0.8%) 133,573 ops/sec [120,075..159,538] → 119,726 ops/sec [119,421..120,001] 🔴 -10.4%
create nested object 84,640 ops/sec [77,907..103,562] → 89,915 ops/sec [81,957..97,991] ~ overlap (+6.2%) 62,339 ops/sec [58,390..93,211] → 59,447 ops/sec [58,982..60,485] ~ overlap (-4.6%)
create 50 objects via Array.from 3,274 ops/sec [3,264..3,304] → 4,069 ops/sec [3,902..4,126] 🟢 +24.3% 2,524 ops/sec [2,420..2,973] → 2,362 ops/sec [2,222..2,873] ~ overlap (-6.4%)
property read 138,163 ops/sec [131,225..146,732] → 135,787 ops/sec [129,536..161,134] ~ overlap (-1.7%) 267,401 ops/sec [265,227..268,433] → 266,756 ops/sec [256,835..364,251] ~ overlap (-0.2%)
Object.keys 83,453 ops/sec [82,681..89,366] → 84,722 ops/sec [83,021..87,926] ~ overlap (+1.5%) 98,250 ops/sec [97,718..103,830] → 90,390 ops/sec [87,098..147,506] ~ overlap (-8.0%)
Object.entries 44,670 ops/sec [40,286..61,550] → 40,822 ops/sec [40,429..51,117] ~ overlap (-8.6%) 50,797 ops/sec [45,418..54,511] → 43,854 ops/sec [42,125..57,539] ~ overlap (-13.7%)
spread operator 52,855 ops/sec [47,971..72,424] → 53,713 ops/sec [50,825..59,642] ~ overlap (+1.6%) 52,748 ops/sec [51,551..53,865] → 54,075 ops/sec [46,749..73,913] ~ overlap (+2.5%)
promises.js — Interp: 🟢 3, 9 unch. · avg +1.4% · Bytecode: 12 unch. · avg -0.4%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
Promise.resolve(value) 74,819 ops/sec [68,513..86,134] → 70,192 ops/sec [69,309..75,786] ~ overlap (-6.2%) 81,064 ops/sec [71,930..103,893] → 74,479 ops/sec [72,497..81,816] ~ overlap (-8.1%)
new Promise(resolve => resolve(value)) 54,975 ops/sec [53,649..55,996] → 51,413 ops/sec [50,465..58,213] ~ overlap (-6.5%) 56,361 ops/sec [55,703..58,627] → 55,481 ops/sec [53,036..56,642] ~ overlap (-1.6%)
Promise.reject(reason) 82,683 ops/sec [68,397..94,687] → 72,309 ops/sec [71,014..75,482] ~ overlap (-12.5%) 83,158 ops/sec [72,816..106,708] → 75,175 ops/sec [67,615..112,976] ~ overlap (-9.6%)
resolve + then (1 handler) 23,555 ops/sec [22,626..23,708] → 24,349 ops/sec [23,681..26,263] ~ overlap (+3.4%) 24,529 ops/sec [23,473..30,253] → 28,103 ops/sec [22,029..34,086] ~ overlap (+14.6%)
resolve + then chain (3 deep) 9,703 ops/sec [9,610..9,930] → 10,250 ops/sec [9,948..11,463] 🟢 +5.6% 10,290 ops/sec [9,839..15,894] → 10,504 ops/sec [10,427..11,401] ~ overlap (+2.1%)
resolve + then chain (10 deep) 3,279 ops/sec [3,230..4,935] → 3,483 ops/sec [3,267..4,392] ~ overlap (+6.2%) 3,432 ops/sec [3,382..3,461] → 3,472 ops/sec [3,443..3,967] ~ overlap (+1.1%)
reject + catch + then 14,074 ops/sec [13,364..17,481] → 14,195 ops/sec [13,745..14,255] ~ overlap (+0.9%) 14,349 ops/sec [14,111..15,351] → 14,177 ops/sec [13,914..14,430] ~ overlap (-1.2%)
resolve + finally + then 6,644 ops/sec [6,380..7,836] → 6,757 ops/sec [6,662..7,152] ~ overlap (+1.7%) 6,676 ops/sec [6,643..6,679] → 6,597 ops/sec [6,546..6,650] ~ overlap (-1.2%)
Promise.all (5 resolved) 5,018 ops/sec [4,591..5,292] → 4,571 ops/sec [4,533..4,652] ~ overlap (-8.9%) 4,476 ops/sec [4,462..4,565] → 4,633 ops/sec [4,453..4,790] ~ overlap (+3.5%)
Promise.race (5 resolved) 5,321 ops/sec [5,132..6,111] → 5,376 ops/sec [5,364..6,997] ~ overlap (+1.0%) 5,146 ops/sec [5,107..5,317] → 5,386 ops/sec [5,313..5,545] ~ overlap (+4.7%)
Promise.allSettled (5 mixed) 3,887 ops/sec [3,691..3,927] → 4,762 ops/sec [4,302..4,825] 🟢 +22.5% 4,090 ops/sec [3,825..4,673] → 3,934 ops/sec [3,888..4,348] ~ overlap (-3.8%)
Promise.any (5 mixed) 4,507 ops/sec [4,414..4,560] → 4,926 ops/sec [4,757..5,069] 🟢 +9.3% 4,854 ops/sec [4,687..5,948] → 4,616 ops/sec [4,469..6,182] ~ overlap (-4.9%)
property-access.js — Interp: 5 unch. · avg +1.2% · Bytecode: 🔴 2, 3 unch. · avg -8.0%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
class instance fields across 1000 instances 138 ops/sec [129..213] → 136 ops/sec [132..142] ~ overlap (-1.3%) 677 ops/sec [658..758] → 634 ops/sec [628..652] 🔴 -6.3%
object literal fields across 1000 literals 135 ops/sec [131..214] → 140 ops/sec [132..143] ~ overlap (+3.2%) 675 ops/sec [672..678] → 672 ops/sec [652..732] ~ overlap (-0.5%)
mixed-shape literals across 1000 literals 140 ops/sec [136..179] → 144 ops/sec [138..145] ~ overlap (+2.4%) 602 ops/sec [546..658] → 512 ops/sec [502..542] 🔴 -15.0%
own-class method across 1000 instances 85 ops/sec [81..115] → 89 ops/sec [87..98] ~ overlap (+4.4%) 340 ops/sec [327..392] → 328 ops/sec [327..331] ~ overlap (-3.3%)
inherited method across 1000 instances 97 ops/sec [93..114] → 94 ops/sec [92..113] ~ overlap (-2.7%) 443 ops/sec [374..599] → 377 ops/sec [375..383] ~ overlap (-14.8%)
regexp.js — Interp: 🟢 1, 10 unch. · avg +0.1% · Bytecode: 🟢 1, 10 unch. · avg +0.8%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
regex literal creation 7,387 ops/sec [7,320..8,490] → 7,575 ops/sec [7,218..8,198] ~ overlap (+2.5%) 187,981 ops/sec [174,383..193,285] → 179,586 ops/sec [178,039..182,577] ~ overlap (-4.5%)
new RegExp(pattern, flags) 7,208 ops/sec [7,074..7,728] → 7,102 ops/sec [6,890..8,703] ~ overlap (-1.5%) 7,240 ops/sec [7,082..7,921] → 7,582 ops/sec [7,089..7,719] ~ overlap (+4.7%)
RegExp(existingRegex) returns the same regex 190,652 ops/sec [171,695..213,390] → 179,296 ops/sec [176,111..182,527] ~ overlap (-6.0%) 303,521 ops/sec [266,538..350,138] → 286,991 ops/sec [266,421..316,408] ~ overlap (-5.4%)
test() on a global regex 67,867 ops/sec [55,307..77,200] → 56,367 ops/sec [56,196..66,847] ~ overlap (-16.9%) 73,239 ops/sec [69,000..79,527] → 72,429 ops/sec [70,079..86,865] ~ overlap (-1.1%)
exec() with capture groups 14,960 ops/sec [14,857..15,016] → 15,568 ops/sec [15,547..15,643] 🟢 +4.1% 16,448 ops/sec [15,941..17,069] → 16,434 ops/sec [16,207..17,195] ~ overlap (-0.1%)
toString() 154,143 ops/sec [150,673..175,211] → 158,636 ops/sec [154,427..246,108] ~ overlap (+2.9%) 214,904 ops/sec [212,849..222,278] → 216,404 ops/sec [215,259..250,446] ~ overlap (+0.7%)
match() with global regex 20,174 ops/sec [19,875..20,948] → 22,515 ops/sec [20,293..31,814] ~ overlap (+11.6%) 22,351 ops/sec [22,052..23,978] → 23,917 ops/sec [22,144..29,692] ~ overlap (+7.0%)
matchAll() with capture groups 9,685 ops/sec [9,664..9,701] → 9,795 ops/sec [9,684..9,820] ~ overlap (+1.1%) 13,927 ops/sec [13,722..13,990] → 14,323 ops/sec [14,043..14,623] 🟢 +2.8%
replace() with global regex 18,513 ops/sec [18,033..20,411] → 18,328 ops/sec [17,592..18,706] ~ overlap (-1.0%) 19,546 ops/sec [19,200..21,570] → 20,060 ops/sec [17,278..20,136] ~ overlap (+2.6%)
search() with regex 39,691 ops/sec [39,554..39,840] → 40,192 ops/sec [37,915..41,925] ~ overlap (+1.3%) 46,918 ops/sec [44,807..56,452] → 47,295 ops/sec [47,155..47,466] ~ overlap (+0.8%)
split() with regex separator 7,188 ops/sec [7,052..8,208] → 7,404 ops/sec [7,188..7,903] ~ overlap (+3.0%) 7,558 ops/sec [7,481..7,621] → 7,642 ops/sec [7,582..7,713] ~ overlap (+1.1%)
strings.js — Interp: 🟢 1, 🔴 3, 15 unch. · avg -1.5% · Bytecode: 🟢 2, 🔴 2, 15 unch. · avg +0.9%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
string concatenation 117,283 ops/sec [114,323..133,050] → 126,329 ops/sec [120,012..131,658] ~ overlap (+7.7%) 493,949 ops/sec [488,787..496,926] → 485,551 ops/sec [472,040..491,286] ~ overlap (-1.7%)
template literal 204,081 ops/sec [198,533..230,986] → 203,068 ops/sec [201,987..203,705] ~ overlap (-0.5%) 380,074 ops/sec [359,057..442,959] → 376,039 ops/sec [369,075..390,326] ~ overlap (-1.1%)
string repeat 144,587 ops/sec [129,621..145,649] → 133,695 ops/sec [130,273..137,506] ~ overlap (-7.5%) 157,386 ops/sec [155,357..200,311] → 167,608 ops/sec [160,346..175,735] ~ overlap (+6.5%)
split and join 49,546 ops/sec [47,641..59,271] → 47,847 ops/sec [47,431..65,762] ~ overlap (-3.4%) 56,062 ops/sec [53,388..58,648] → 60,505 ops/sec [53,350..65,078] ~ overlap (+7.9%)
indexOf and includes 53,584 ops/sec [50,770..55,894] → 51,715 ops/sec [51,451..51,879] ~ overlap (-3.5%) 56,686 ops/sec [55,732..72,050] → 57,830 ops/sec [55,876..58,533] ~ overlap (+2.0%)
toUpperCase and toLowerCase 71,559 ops/sec [67,649..85,436] → 67,436 ops/sec [66,201..67,884] ~ overlap (-5.8%) 77,937 ops/sec [76,568..78,344] → 79,222 ops/sec [78,955..80,792] 🟢 +1.6%
slice and substring 51,088 ops/sec [49,737..54,076] → 49,614 ops/sec [48,257..59,053] ~ overlap (-2.9%) 61,382 ops/sec [60,380..87,107] → 61,460 ops/sec [61,230..67,716] ~ overlap (+0.1%)
trim operations 59,633 ops/sec [59,098..59,898] → 57,636 ops/sec [56,952..57,881] 🔴 -3.3% 70,324 ops/sec [70,288..70,840] → 69,792 ops/sec [69,183..70,254] 🔴 -0.8%
replace and replaceAll 58,922 ops/sec [58,808..60,437] → 58,198 ops/sec [57,932..58,613] 🔴 -1.2% 63,855 ops/sec [60,029..75,823] → 62,618 ops/sec [61,322..63,272] ~ overlap (-1.9%)
startsWith and endsWith 42,826 ops/sec [41,770..45,116] → 42,501 ops/sec [41,787..42,735] ~ overlap (-0.8%) 50,077 ops/sec [44,912..56,025] → 50,052 ops/sec [45,345..53,039] ~ overlap (-0.0%)
padStart and padEnd 67,612 ops/sec [67,451..67,783] → 66,231 ops/sec [65,298..77,215] ~ overlap (-2.0%) 77,615 ops/sec [70,966..77,730] → 73,604 ops/sec [73,267..81,088] ~ overlap (-5.2%)
identity tag, no substitutions 107,911 ops/sec [106,656..110,516] → 105,584 ops/sec [104,857..108,027] ~ overlap (-2.2%) 158,709 ops/sec [158,254..162,935] → 157,630 ops/sec [157,393..158,019] 🔴 -0.7%
tag with 1 substitution 24,976 ops/sec [23,902..29,266] → 24,937 ops/sec [24,455..25,872] ~ overlap (-0.2%) 31,543 ops/sec [31,411..31,871] → 31,862 ops/sec [31,787..32,128] ~ overlap (+1.0%)
tag with 3 substitutions 13,767 ops/sec [13,666..13,791] → 13,970 ops/sec [13,900..14,156] 🟢 +1.5% 18,962 ops/sec [18,789..18,986] → 20,175 ops/sec [19,324..20,330] 🟢 +6.4%
tag with 6 substitutions 8,296 ops/sec [8,202..8,335] → 8,325 ops/sec [8,150..8,393] ~ overlap (+0.4%) 11,362 ops/sec [11,122..11,466] → 11,711 ops/sec [11,357..12,891] ~ overlap (+3.1%)
String.raw, no substitutions 84,782 ops/sec [84,258..85,254] → 85,419 ops/sec [83,997..85,826] ~ overlap (+0.8%) 88,413 ops/sec [86,830..94,399] → 86,035 ops/sec [84,484..87,012] ~ overlap (-2.7%)
String.raw, 2 substitutions 70,106 ops/sec [68,782..73,514] → 67,451 ops/sec [66,949..67,789] 🔴 -3.8% 69,325 ops/sec [69,256..69,684] → 69,796 ops/sec [69,617..70,197] ~ overlap (+0.7%)
tag accessing .raw array 40,796 ops/sec [39,808..42,037] → 41,053 ops/sec [38,520..43,015] ~ overlap (+0.6%) 44,939 ops/sec [44,520..45,749] → 45,651 ops/sec [44,736..45,794] ~ overlap (+1.6%)
method as tag (this binding) 17,498 ops/sec [16,754..18,758] → 17,178 ops/sec [16,257..17,213] ~ overlap (-1.8%) 22,154 ops/sec [21,963..22,329] → 22,084 ops/sec [21,847..22,513] ~ overlap (-0.3%)
temporal.js — Interp: 6 unch. · avg +0.3% · Bytecode: 6 unch. · avg +3.7%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
PlainDate.add({ months: 1 }) 44,589 ops/sec [44,146..44,891] → 47,188 ops/sec [42,726..47,550] ~ overlap (+5.8%) 46,835 ops/sec [44,073..55,301] → 44,833 ops/sec [42,949..45,154] ~ overlap (-4.3%)
PlainDate.until(..., { largestUnit: 'months' }) 51,928 ops/sec [51,590..62,209] → 50,683 ops/sec [50,229..54,465] ~ overlap (-2.4%) 52,833 ops/sec [52,307..80,776] → 53,666 ops/sec [51,775..61,667] ~ overlap (+1.6%)
Duration.total days relative to PlainDate 46,327 ops/sec [45,304..47,052] → 46,593 ops/sec [45,481..46,687] ~ overlap (+0.6%) 46,664 ops/sec [45,145..48,918] → 45,765 ops/sec [45,023..46,001] ~ overlap (-1.9%)
Duration.round to hours 36,321 ops/sec [32,185..39,786] → 34,184 ops/sec [32,497..38,927] ~ overlap (-5.9%) 32,500 ops/sec [31,779..38,986] → 38,529 ops/sec [32,915..41,450] ~ overlap (+18.5%)
ZonedDateTime.from named time zone 10,201 ops/sec [9,817..11,327] → 10,682 ops/sec [10,151..11,141] ~ overlap (+4.7%) 10,232 ops/sec [10,008..11,885] → 10,316 ops/sec [10,132..10,989] ~ overlap (+0.8%)
ZonedDateTime.since across DST 10,093 ops/sec [9,950..11,476] → 9,967 ops/sec [9,886..11,149] ~ overlap (-1.2%) 10,056 ops/sec [9,895..13,521] → 10,780 ops/sec [9,969..12,637] ~ overlap (+7.2%)
tsv.js — Interp: 🟢 1, 🔴 1, 7 unch. · avg -5.3% · Bytecode: 🟢 1, 8 unch. · avg +1.2%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
parse simple 3-column TSV 39,917 ops/sec [39,522..41,363] → 41,367 ops/sec [40,073..45,401] ~ overlap (+3.6%) 42,930 ops/sec [42,279..49,290] → 43,223 ops/sec [41,617..44,383] ~ overlap (+0.7%)
parse 10-row TSV 12,562 ops/sec [11,149..15,206] → 11,531 ops/sec [11,252..14,182] ~ overlap (-8.2%) 11,276 ops/sec [11,123..12,607] → 12,175 ops/sec [11,385..13,000] ~ overlap (+8.0%)
parse 100-row TSV 1,825 ops/sec [1,782..1,973] → 1,827 ops/sec [1,795..2,616] ~ overlap (+0.1%) 1,957 ops/sec [1,704..2,307] → 1,870 ops/sec [1,790..1,918] ~ overlap (-4.5%)
parse TSV with backslash-escaped fields 10,094 ops/sec [8,657..10,408] → 8,719 ops/sec [8,706..8,738] ~ overlap (-13.6%) 8,557 ops/sec [8,193..8,783] → 8,608 ops/sec [8,475..8,974] ~ overlap (+0.6%)
parse without headers (array of arrays) 6,684 ops/sec [6,593..6,892] → 5,709 ops/sec [5,503..5,727] 🔴 -14.6% 5,443 ops/sec [5,329..6,258] → 5,642 ops/sec [5,452..8,021] ~ overlap (+3.7%)
stringify array of objects 34,956 ops/sec [34,526..36,264] → 34,120 ops/sec [33,983..35,275] ~ overlap (-2.4%) 37,825 ops/sec [37,082..38,189] → 37,946 ops/sec [37,319..37,988] ~ overlap (+0.3%)
stringify array of arrays 11,927 ops/sec [10,889..13,791] → 10,989 ops/sec [10,850..11,063] ~ overlap (-7.9%) 11,138 ops/sec [10,871..11,485] → 10,881 ops/sec [10,749..14,553] ~ overlap (-2.3%)
stringify with values needing escaping 30,777 ops/sec [28,073..34,257] → 28,781 ops/sec [28,436..29,400] ~ overlap (-6.5%) 30,488 ops/sec [28,081..31,357] → 30,132 ops/sec [29,690..31,005] ~ overlap (-1.2%)
parse then stringify 6,656 ops/sec [6,452..6,710] → 6,782 ops/sec [6,749..8,212] 🟢 +1.9% 6,269 ops/sec [6,137..6,337] → 6,601 ops/sec [6,496..6,673] 🟢 +5.3%
typed-arrays.js — Interp: 🟢 2, 🔴 4, 16 unch. · avg -7.8% · Bytecode: 🟢 2, 🔴 2, 18 unch. · avg +0.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
new Int32Array(0) 90,170 ops/sec [89,346..93,564] → 93,895 ops/sec [93,078..94,574] ~ overlap (+4.1%) 111,450 ops/sec [106,617..119,687] → 106,774 ops/sec [106,050..137,003] ~ overlap (-4.2%)
new Int32Array(100) 89,353 ops/sec [84,165..105,555] → 89,598 ops/sec [88,701..89,896] ~ overlap (+0.3%) 101,660 ops/sec [99,736..102,708] → 107,885 ops/sec [101,911..116,711] ~ overlap (+6.1%)
new Int32Array(1000) 72,742 ops/sec [70,220..75,496] → 77,131 ops/sec [73,704..79,959] ~ overlap (+6.0%) 88,988 ops/sec [76,940..110,859] → 80,613 ops/sec [76,143..92,567] ~ overlap (-9.4%)
new Float64Array(100) 85,440 ops/sec [85,187..85,507] → 90,324 ops/sec [89,261..90,888] 🟢 +5.7% 97,925 ops/sec [96,189..98,957] → 97,269 ops/sec [95,976..100,783] ~ overlap (-0.7%)
Int32Array.from([...]) 1,506 ops/sec [1,503..1,563] → 1,542 ops/sec [1,508..1,565] ~ overlap (+2.4%) 1,477 ops/sec [1,463..1,505] → 1,506 ops/sec [1,493..1,602] ~ overlap (+2.0%)
Int32Array.of(1, 2, 3, 4, 5) 68,677 ops/sec [67,202..93,651] → 70,148 ops/sec [68,124..76,958] ~ overlap (+2.1%) 79,057 ops/sec [78,534..79,171] → 78,318 ops/sec [77,377..78,823] ~ overlap (-0.9%)
sequential write 100 elements 1,069 ops/sec [1,035..1,529] → 1,064 ops/sec [1,059..1,072] ~ overlap (-0.5%) 3,670 ops/sec [3,609..3,684] → 3,614 ops/sec [3,598..3,718] ~ overlap (-1.5%)
sequential read 100 elements 1,137 ops/sec [1,083..1,190] → 1,155 ops/sec [1,148..1,160] ~ overlap (+1.6%) 4,109 ops/sec [4,003..4,358] → 4,086 ops/sec [4,075..4,091] ~ overlap (-0.6%)
Float64Array write 100 elements 1,009 ops/sec [1,000..1,029] → 1,164 ops/sec [999..1,510] ~ overlap (+15.4%) 3,223 ops/sec [3,152..3,343] → 3,082 ops/sec [3,055..3,239] ~ overlap (-4.4%)
fill(42) 2,028 ops/sec [1,987..2,353] → 2,043 ops/sec [2,021..2,330] ~ overlap (+0.7%) 2,070 ops/sec [2,047..2,077] → 2,039 ops/sec [2,032..2,082] ~ overlap (-1.5%)
slice() 14,912 ops/sec [14,846..15,052] → 8,443 ops/sec [8,395..9,191] 🔴 -43.4% 8,636 ops/sec [8,613..9,146] → 9,691 ops/sec [8,451..10,674] ~ overlap (+12.2%)
map(x => x * 2) 3,286 ops/sec [3,258..3,290] → 2,236 ops/sec [2,047..3,286] ~ overlap (-31.9%) 2,135 ops/sec [2,107..2,139] → 2,087 ops/sec [2,075..2,116] ~ overlap (-2.2%)
filter(x => x > 50) 3,445 ops/sec [3,413..3,493] → 3,482 ops/sec [3,457..3,489] ~ overlap (+1.1%) 2,353 ops/sec [2,238..2,362] → 2,302 ops/sec [2,296..2,307] ~ overlap (-2.2%)
reduce (sum) 3,519 ops/sec [3,503..3,533] → 3,521 ops/sec [3,510..3,528] ~ overlap (+0.1%) 2,224 ops/sec [2,164..2,244] → 2,182 ops/sec [2,158..2,188] ~ overlap (-1.9%)
sort() 23,177 ops/sec [23,133..23,231] → 23,485 ops/sec [23,404..23,545] 🟢 +1.3% 13,767 ops/sec [13,445..24,222] → 13,461 ops/sec [13,353..13,524] ~ overlap (-2.2%)
indexOf() 48,990 ops/sec [48,851..49,217] → 48,650 ops/sec [48,188..48,772] 🔴 -0.7% 50,669 ops/sec [50,269..50,770] → 30,425 ops/sec [30,096..30,471] 🔴 -40.0%
reverse() 26,047 ops/sec [25,990..26,237] → 26,075 ops/sec [14,832..26,240] ~ overlap (+0.1%) 27,296 ops/sec [27,210..27,359] → 25,484 ops/sec [17,064..27,348] ~ overlap (-6.6%)
create view over existing buffer 164,606 ops/sec [163,507..165,125] → 104,066 ops/sec [102,379..110,389] 🔴 -36.8% 196,267 ops/sec [120,450..198,843] → 198,716 ops/sec [194,154..200,410] ~ overlap (+1.2%)
subarray() 108,364 ops/sec [107,111..108,856] → 69,980 ops/sec [69,382..70,543] 🔴 -35.4% 75,759 ops/sec [74,136..119,580] → 122,250 ops/sec [119,396..122,627] ~ overlap (+61.4%)
set() from array 125,668 ops/sec [125,170..126,745] → 90,241 ops/sec [74,001..127,351] ~ overlap (-28.2%) 148,682 ops/sec [147,656..150,022] → 152,541 ops/sec [152,193..152,780] 🟢 +2.6%
for-of loop 2,501 ops/sec [2,464..2,508] → 1,560 ops/sec [1,515..2,580] ~ overlap (-37.6%) 13,115 ops/sec [13,059..13,152] → 12,694 ops/sec [12,518..12,767] 🔴 -3.2%
spread into array 10,431 ops/sec [10,381..10,502] → 10,525 ops/sec [10,445..10,635] ~ overlap (+0.9%) 38,347 ops/sec [38,067..38,587] → 39,334 ops/sec [38,733..39,625] 🟢 +2.6%
uint8array-encoding.js — Interp: 🟢 9, 9 unch. · avg +21.1% · Bytecode: 🟢 9, 🔴 1, 8 unch. · avg +19.1%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
short (5 bytes) 135,852 ops/sec [134,879..141,629] → 147,780 ops/sec [145,424..152,554] 🟢 +8.8% 176,621 ops/sec [172,656..194,343] → 185,676 ops/sec [182,233..191,935] ~ overlap (+5.1%)
medium (450 bytes) 107,173 ops/sec [98,743..113,411] → 108,716 ops/sec [101,311..117,142] ~ overlap (+1.4%) 124,040 ops/sec [115,006..136,045] → 118,310 ops/sec [116,203..122,008] ~ overlap (-4.6%)
large (4096 bytes) 29,291 ops/sec [28,307..30,885] → 30,332 ops/sec [30,226..31,337] ~ overlap (+3.6%) 30,655 ops/sec [30,095..31,340] → 31,618 ops/sec [30,107..31,842] ~ overlap (+3.1%)
base64url alphabet 77,926 ops/sec [75,752..78,531] → 77,045 ops/sec [75,376..79,170] ~ overlap (-1.1%) 78,420 ops/sec [77,242..90,559] → 79,334 ops/sec [77,693..83,802] ~ overlap (+1.2%)
omitPadding 99,586 ops/sec [96,885..104,614] → 100,970 ops/sec [99,262..104,305] ~ overlap (+1.4%) 106,216 ops/sec [104,592..109,971] → 106,996 ops/sec [106,904..107,214] ~ overlap (+0.7%)
short (8 chars) 116,720 ops/sec [111,613..132,445] → 177,448 ops/sec [176,222..177,694] 🟢 +52.0% 132,532 ops/sec [131,842..132,989] → 131,566 ops/sec [130,809..133,599] ~ overlap (-0.7%)
medium (600 chars) 63,673 ops/sec [62,066..67,865] → 101,872 ops/sec [101,723..102,513] 🟢 +60.0% 68,853 ops/sec [68,497..69,085] → 68,247 ops/sec [67,969..69,107] ~ overlap (-0.9%)
large (5464 chars) 14,398 ops/sec [13,945..16,476] → 22,765 ops/sec [14,120..24,196] ~ overlap (+58.1%) 14,016 ops/sec [13,940..14,138] → 13,780 ops/sec [13,695..14,201] ~ overlap (-1.7%)
short (5 bytes) 150,905 ops/sec [140,955..171,923] → 146,987 ops/sec [145,431..149,107] ~ overlap (-2.6%) 196,770 ops/sec [195,168..197,174] → 192,181 ops/sec [190,614..194,798] 🔴 -2.3%
medium (450 bytes) 88,607 ops/sec [88,176..89,439] → 98,323 ops/sec [92,046..110,110] 🟢 +11.0% 110,976 ops/sec [109,370..111,249] → 182,167 ops/sec [180,721..182,618] 🟢 +64.1%
large (4096 bytes) 22,785 ops/sec [22,308..23,294] → 23,594 ops/sec [21,940..25,517] ~ overlap (+3.6%) 23,707 ops/sec [23,183..23,918] → 40,152 ops/sec [39,914..40,244] 🟢 +69.4%
short (10 chars) 122,095 ops/sec [121,537..124,749] → 154,972 ops/sec [125,069..188,581] 🟢 +26.9% 232,964 ops/sec [231,410..233,789] → 240,434 ops/sec [238,946..241,099] 🟢 +3.2%
medium (900 chars) 86,274 ops/sec [84,787..86,719] → 142,991 ops/sec [141,814..143,365] 🟢 +65.7% 169,081 ops/sec [168,580..169,195] → 170,385 ops/sec [169,406..171,745] 🟢 +0.8%
large (8192 chars) 25,386 ops/sec [24,937..25,974] → 49,072 ops/sec [48,975..49,478] 🟢 +93.3% 30,801 ops/sec [28,204..33,795] → 50,651 ops/sec [49,718..51,253] 🟢 +64.4%
setFromBase64 (450 bytes) 62,142 ops/sec [58,454..86,962] → 87,656 ops/sec [87,350..88,309] 🟢 +41.1% 58,922 ops/sec [58,343..61,492] → 97,581 ops/sec [97,157..98,153] 🟢 +65.6%
setFromHex (450 bytes) 35,213 ops/sec [35,050..35,353] → 28,435 ops/sec [21,823..35,620] ~ overlap (-19.2%) 36,280 ops/sec [36,048..36,303] → 36,971 ops/sec [36,868..37,270] 🟢 +1.9%
toBase64 → fromBase64 (450 bytes) 68,348 ops/sec [68,040..69,175] → 47,646 ops/sec [46,932..71,188] ~ overlap (-30.3%) 75,159 ops/sec [69,531..75,449] → 76,569 ops/sec [76,360..76,799] 🟢 +1.9%
toHex → fromHex (450 bytes) 83,666 ops/sec [82,823..84,148] → 88,425 ops/sec [87,606..89,398] 🟢 +5.7% 56,899 ops/sec [55,350..57,032] → 97,856 ops/sec [96,712..98,366] 🟢 +72.0%
weak-collections.js — Interp: 🟢 1, 14 unch. · avg +7.0% · Bytecode: 🔴 5, 10 unch. · avg -9.9%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
constructor from 50 entries 9,405 ops/sec [9,233..12,867] → 10,099 ops/sec [9,652..10,262] ~ overlap (+7.4%) 9,553 ops/sec [9,322..9,565] → 9,839 ops/sec [9,318..9,885] ~ overlap (+3.0%)
set 50 object keys 2,866 ops/sec [2,773..2,888] → 3,178 ops/sec [2,655..4,068] ~ overlap (+10.9%) 3,762 ops/sec [3,735..3,788] → 3,756 ops/sec [3,728..4,370] ~ overlap (-0.2%)
get lookups (50 entries) 42,883 ops/sec [41,677..44,089] → 44,104 ops/sec [42,822..44,917] ~ overlap (+2.8%) 79,366 ops/sec [78,231..83,668] → 77,672 ops/sec [77,188..79,002] ~ overlap (-2.1%)
has checks (50 entries) 56,929 ops/sec [55,099..66,007] → 58,354 ops/sec [57,931..58,538] ~ overlap (+2.5%) 106,214 ops/sec [97,343..112,397] → 96,893 ops/sec [96,460..98,197] ~ overlap (-8.8%)
delete entries 2,644 ops/sec [2,620..3,137] → 2,771 ops/sec [2,730..2,793] ~ overlap (+4.8%) 3,630 ops/sec [3,582..3,640] → 3,618 ops/sec [3,604..3,637] ~ overlap (-0.3%)
non-registered symbol keys 6,496 ops/sec [6,406..6,908] → 6,740 ops/sec [6,611..6,768] ~ overlap (+3.8%) 8,663 ops/sec [8,579..14,655] → 8,660 ops/sec [8,592..8,739] ~ overlap (-0.0%)
getOrInsert 2,766 ops/sec [2,715..3,012] → 2,831 ops/sec [2,817..2,874] ~ overlap (+2.4%) 5,711 ops/sec [3,916..5,761] → 3,450 ops/sec [3,429..3,463] 🔴 -39.6%
getOrInsertComputed 1,656 ops/sec [1,621..1,677] → 1,690 ops/sec [1,677..1,709] ~ overlap (+2.1%) 1,968 ops/sec [1,812..2,132] → 1,741 ops/sec [1,713..1,766] 🔴 -11.5%
forced gc live-key retention 69 ops/sec [58..88] → 115 ops/sec [84..139] ~ overlap (+65.7%) 100 ops/sec [79..113] → 98 ops/sec [73..129] ~ overlap (-1.3%)
constructor from 50 values 11,534 ops/sec [11,374..11,881] → 12,209 ops/sec [11,872..12,690] ~ overlap (+5.9%) 12,075 ops/sec [11,579..12,360] → 11,926 ops/sec [11,504..12,232] ~ overlap (-1.2%)
add 50 object values 3,040 ops/sec [3,021..3,050] → 3,121 ops/sec [3,095..3,168] 🟢 +2.6% 4,015 ops/sec [3,927..4,382] → 4,032 ops/sec [4,020..4,041] ~ overlap (+0.4%)
has checks (50 values) 57,420 ops/sec [57,138..57,968] → 57,326 ops/sec [56,961..59,112] ~ overlap (-0.2%) 100,969 ops/sec [100,819..100,973] → 97,090 ops/sec [95,944..98,270] 🔴 -3.8%
delete values 9,099 ops/sec [8,952..9,216] → 9,253 ops/sec [9,151..9,353] ~ overlap (+1.7%) 17,366 ops/sec [16,908..17,415] → 10,901 ops/sec [10,606..10,929] 🔴 -37.2%
non-registered symbol values 6,844 ops/sec [6,791..6,897] → 7,015 ops/sec [6,840..7,580] ~ overlap (+2.5%) 15,419 ops/sec [15,349..15,536] → 9,221 ops/sec [9,113..9,282] 🔴 -40.2%
forced gc pruning smoke 79 ops/sec [57..107] → 71 ops/sec [65..116] ~ overlap (-9.8%) 142 ops/sec [140..143] → 134 ops/sec [74..155] ~ overlap (-5.9%)

Deterministic profile diff

Deterministic profile diff: no significant changes.

Measured on ubuntu-latest x64. Each PR run also builds the main base and benchmarks it back-to-back on the same runner after a warm-up discard, so the ranges compare two runs measured under the same conditions; overlapping min/max ranges are treated as unchanged noise. Percentage deltas are secondary context. See docs/adr/0076.

…o measured end-to-end

The "~2x" figure was the isolated probe-loop microbenchmark. End-to-end in the
engine (bytecode, --prod), a toString-dominated float workload of 2M
Number.prototype.toString calls over 15-17-significant-digit doubles runs in
13.4s with the change vs 18.8s on origin/main — ~1.4x faster (-28% execution
time); the engine's per-call string allocation and dispatch are a roughly
constant overhead around FormatDouble. The earlier engine measurements were
invalid because GocciaScript skips unsupported traditional for(;;) loops by
default, so the probe arrays were never populated.

Add a `toString non-integer (shortest round-trip)` benchmark to benchmarks/
numbers.js (using for...of) so CI tracks this path; the existing toString bench
only covered the integer fast path. Correct the speedup claim in ADR 0079 and
the code comment accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

test262 Conformance

Category Run Passed Δ Pass Failed Pass-rate Δ Rate
built-ins 23,643 22,619 +1 1,024 95.7% ±0pp
harness 116 116 ±0 0 100.0% ±0pp
intl402 3,341 3,334 ±0 7 99.8% ±0pp
language 23,711 23,711 ±0 0 100.0% ±0pp
staging 1,482 1,111 ±0 371 75.0% ±0pp
total 52,293 50,891 +1 1,402 97.3% ±0pp

Areas closest to 100%

Area Pass rate Δ vs main Passing
built-ins/TypedArray 99.9% ±0pp 1,445 / 1,446
intl402/Temporal 99.9% ±0pp 2,026 / 2,029
built-ins/Object 99.7% ±0pp 3,401 / 3,411
Per-test deltas (+1 / -0)

Newly passing (1):

  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js

Steady-state failures are non-blocking; regressions vs the cached main baseline (lower total pass count, or any PASS → non-PASS transition) fail the conformance gate. Measured on ubuntu-latest x64, bytecode mode. Areas grouped by the first two test262 path components; minimum 25 attempted tests, areas already at 100% excluded. Δ vs main compares against the most recent cached main baseline.

@frostney frostney marked this pull request as ready for review June 28, 2026 11:33
@coderabbitai coderabbitai Bot added internal Refactoring, CI, tooling, cleanup spec compliance Mismatch against official JavaScript/TypeScript specification labels Jun 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/built-ins/Number/prototype/toString.js (1)

96-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add one non-integer coercion check outside direct toString().

This PR changes the shared non-integer FormatDouble path, but the new regressions only pin direct toString() output here. A single String(0.1 + 0.2) / `${0.1 + 0.2}` assertion would also guard the other call sites called out in the PR summary from drifting later.

Possible addition
+  test("String() and template interpolation share the non-integer shortest-round-trip path", () => {
+    expect(String(0.1 + 0.2)).toBe("0.30000000000000004");
+    expect(`${0.1 + 0.2}`).toBe("0.30000000000000004");
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/built-ins/Number/prototype/toString.js` around lines 96 - 110, The
current Number.prototype.toString tests only cover direct toString output, so
add one non-integer coercion assertion that exercises the shared FormatDouble
path through String() or template literal coercion. Use an existing computed
fractional value in the Number.prototype.toString suite, and keep the new check
alongside the other round-tripping cases so it guards the same behavior via a
different call site.
benchmarks/numbers.js (1)

57-70: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Hoist the sample list out of run.

Rebuilding xs and recomputing values like 0.1 + 0.2 and Math.sqrt(2) on every iteration adds setup overhead unrelated to toString(), so this bench will under-measure regressions in the formatting path itself.

Possible refactor
+const ToStringNonIntegerSamples = [
+  0.1 + 0.2,
+  Math.PI,
+  Math.sqrt(2),
+  Math.E,
+  123.456789012345,
+  9.18742501042e222,
+  5.7016275775556e-8,
+];
+
   bench("toString non-integer (shortest round-trip)", {
     run: () => {
-      const xs = [
-        0.1 + 0.2,
-        Math.PI,
-        Math.sqrt(2),
-        Math.E,
-        123.456789012345,
-        9.18742501042e222,
-        5.7016275775556e-8,
-      ];
       let total = 0;
-      for (const x of xs) total += x.toString().length;
+      for (const x of ToStringNonIntegerSamples) total += x.toString().length;
       return total;
     },
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmarks/numbers.js` around lines 57 - 70, The benchmark in numbers.js is
doing avoidable setup work inside the bench("toString non-integer (shortest
round-trip)") run function by rebuilding xs and recomputing constants like 0.1 +
0.2 and Math.sqrt(2) on every iteration. Hoist the sample list to a shared
constant outside the run callback, then have run only iterate over that
precomputed list and sum each x.toString().length so the benchmark measures
formatting cost more accurately.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@benchmarks/numbers.js`:
- Around line 57-70: The benchmark in numbers.js is doing avoidable setup work
inside the bench("toString non-integer (shortest round-trip)") run function by
rebuilding xs and recomputing constants like 0.1 + 0.2 and Math.sqrt(2) on every
iteration. Hoist the sample list to a shared constant outside the run callback,
then have run only iterate over that precomputed list and sum each
x.toString().length so the benchmark measures formatting cost more accurately.

In `@tests/built-ins/Number/prototype/toString.js`:
- Around line 96-110: The current Number.prototype.toString tests only cover
direct toString output, so add one non-integer coercion assertion that exercises
the shared FormatDouble path through String() or template literal coercion. Use
an existing computed fractional value in the Number.prototype.toString suite,
and keep the new check alongside the other round-tripping cases so it guards the
same behavior via a different call site.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 090841cd-f973-4461-878b-6f12cf1a3128

📥 Commits

Reviewing files that changed from the base of the PR and between 02f4f37 and 61d1636.

📒 Files selected for processing (7)
  • benchmarks/numbers.js
  • docs/adr/0079-formatdouble-first-hit-precision-scan.md
  • docs/adr/README.md
  • docs/contributing/code-style.md
  • source/units/Goccia.Values.Primitives.pas
  • tests/built-ins/JSON/stringify.js
  • tests/built-ins/Number/prototype/toString.js

frostney and others added 2 commits June 28, 2026 12:53
Resolve ADR number collision: origin/main landed ADR 0079 (parser
parenthesized-group relexing, #808), so renumber this PR's ADR to
0080-formatdouble-first-hit-precision-scan and update its code-comment
references accordingly.
…mark samples

Address CodeRabbit review nitpicks on PR #899:
- toString.js: add a coercion test asserting String(), template, and string
  concatenation share the non-integer shortest-round-trip FormatDouble path, not
  just direct toString().
- numbers.js: hoist the sample list out of the bench run callback so the
  benchmark measures formatting cost rather than per-iteration array rebuild.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation and removed spec compliance Mismatch against official JavaScript/TypeScript specification labels Jun 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/built-ins/Number/prototype/toString.js`:
- Around line 132-136: The coercion test in the Number prototype suite is
missing some value/path combinations, so expand the existing test in the
toString-related spec to assert String, template literal, and concatenation
coercion for the same representative non-integer values. Update the test case
around the current `test(...)` block so both `0.1 + 0.2` and `Math.PI` are each
covered by all three coercion forms, keeping the assertion intent aligned with
the test title.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 715c1156-1d40-4d8b-87fc-95a6759bbf80

📥 Commits

Reviewing files that changed from the base of the PR and between 61d1636 and 2f5bdcb.

📒 Files selected for processing (5)
  • benchmarks/numbers.js
  • docs/adr/0080-formatdouble-first-hit-precision-scan.md
  • docs/adr/README.md
  • source/units/Goccia.Values.Primitives.pas
  • tests/built-ins/Number/prototype/toString.js
💤 Files with no reviewable changes (1)
  • docs/adr/0080-formatdouble-first-hit-precision-scan.md
✅ Files skipped from review due to trivial changes (1)
  • docs/adr/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • benchmarks/numbers.js
  • source/units/Goccia.Values.Primitives.pas

Comment thread tests/built-ins/Number/prototype/toString.js
…mples

Address CodeRabbit review on PR #899: the coercion test claimed all three
coercion paths agree but only checked String()/template for 0.1+0.2 and
concatenation for Math.PI, so a regression in the untested combinations would
pass. Assert String(), template interpolation, and string concatenation for
both representative non-integer values.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@frostney frostney merged commit b3d6ddc into main Jun 28, 2026
15 checks passed
@frostney frostney deleted the claude/ecstatic-cohen-c61125 branch June 28, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation internal Refactoring, CI, tooling, cleanup

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(number): FormatDouble linear-probes precision for shortest round-trip

1 participant