Skip to content

perf(engine): make for-in key dedup O(k) with a hash set#888

Merged
frostney merged 2 commits into
mainfrom
claude/stoic-hamilton-69cc57
Jun 27, 2026
Merged

perf(engine): make for-in key dedup O(k) with a hash set#888
frostney merged 2 commits into
mainfrom
claude/stoic-hamilton-69cc57

Conversation

@frostney

Copy link
Copy Markdown
Owner

Summary

  • for...in deduplicated keys across the prototype chain with TStringList.IndexOf on an unsorted list — an O(k) linear scan run once per key, making a full enumeration O(k²) in the total (own + inherited) enumerable key count k.
  • Replaces the TStringList with a TOrderedStringMap<Boolean> hash set (ContainsKey + Add), the established string-set idiom in the codebase (cf. Goccia.Modules.Loader.pas). Dedup is now O(k).
  • Both execution engines are fixed: CreateForInEntriesArray (tree-walking interpreter, source/units/Goccia.Evaluator.pas) and the near-identical ForInEntriesArray (bytecode VM, source/units/Goccia.VM.pas). The issue text named only the interpreter site, but the same root cause exists in the VM and for...in runs through it in --mode=bytecode; fixing both was confirmed in scoping.
  • Behavior is identical (membership-only change): membership stays case-sensitive (native string equality, matching the old CaseSensitive := True), and per-level enumeration order is unchanged — OrderForInPropertyKeys / VMOrderOwnPropertyStringKeys still own ordering; the Visited set never influenced output order (that comes from Result.Elements.Add).
  • Non-goals: no for...in semantic changes; no cross-unit refactor of the two duplicated functions (kept tight to the perf fix); the OrderForInPropertyKeys insertion sort is untouched.

Closes #809

Deferred follow-up (out of scope)

While testing I found a pre-existing, unrelated diagnostic bug: a disabled traditional for(;;) loop (requires --compat-traditional-for-loop) whose body contains an interpolated template literal reports a misleading "Unterminated template literal" at EOF instead of the correct "enable --compat-traditional-for-loop" suggestion. Flagged separately; not addressed here.

Testing

  • Verified no regressions and confirmed the new feature or bugfix in end-to-end JavaScript/TypeScript tests
  • Updated documentation — n/a (internal perf optimization, no user-facing behavior or language-surface change)
  • 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 fully covered by the two-mode JS suite below; TOrderedStringMap has its own unit tests
  • Optional: Verified no benchmark regressions or confirmed benchmark coverage for the change

Commands run (all green):

  • ./build.pas testrunner./build/GocciaTestRunner tests10,958/10,958 passed (tree-walking)
  • ./build/GocciaTestRunner tests --mode=bytecode10,958/10,958 passed (bytecode VM)
  • tests/language/for-in-loop35/35 both modes (+2 new regression tests: same-name enumerable shadowing, and dedup + ordering across a 12-level / 40-shared-key prototype chain)
  • ./format.pas --check — 370 files, all formatted correctly
  • ./build/GocciaBenchmarkRunner benchmarks (whole-dir, no CLI flag, as CI runs it) — new for...in benchmark runs cleanly; its --compat-for-in-loop is picked up from the scoped benchmarks/for-in/goccia.json via per-file config discovery, so the benchmark lane stays green. Exit 0.

for...in enumeration deduplicated keys across the prototype chain with
TStringList.IndexOf on an unsorted list, an O(k) linear scan run once per
key, so a full enumeration was O(k^2) in the total (own + inherited) key
count.

Replace the TStringList with a TOrderedStringMap<Boolean> hash set
(ContainsKey + Add), the established string-set idiom in the codebase, in
both execution engines: CreateForInEntriesArray (tree-walking interpreter)
and ForInEntriesArray (bytecode VM). Membership stays case-sensitive
(native string equality) and per-level enumeration order is unchanged
(OrderForInPropertyKeys / VMOrderOwnPropertyStringKeys still own ordering;
the set is membership-only), so behavior is identical.

Add a regression test for same-name enumerable shadowing and dedup across a
deep prototype chain at scale (runs in both modes), plus a scoped for-in
benchmark under benchmarks/for-in/ with its own goccia.json enabling
--compat-for-in-loop.

Closes #809
@vercel

vercel Bot commented Jun 27, 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 27, 2026 6:28pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 27, 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: ec7ccb4e-8e68-4c63-887f-27de090a31ed

📥 Commits

Reviewing files that changed from the base of the PR and between cb71fc2 and 5319324.

📒 Files selected for processing (1)
  • tests/language/for-in-loop/basic-enumeration.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/language/for-in-loop/basic-enumeration.js

📝 Walkthrough

Walkthrough

Replaces TStringList-based prototype-chain key deduplication in CreateForInEntriesArray and ForInEntriesArray with TOrderedStringMap<Boolean>. Adds for...in correctness tests and benchmarks, plus a benchmark config enabling compat-for-in-loop.

for-in key deduplication upgrade

Layer / File(s) Summary
TOrderedStringMap dedup in Evaluator and VM
source/units/Goccia.Evaluator.pas, source/units/Goccia.VM.pas
CreateForInEntriesArray and ForInEntriesArray replace TStringList membership checks with TOrderedStringMap<Boolean>, and Goccia.VM.pas adds OrderedStringMap to its implementation uses clause.
For-in enumeration tests
tests/language/for-in-loop/basic-enumeration.js
Adds tests for shadowed enumerable keys and multi-level prototype-chain enumeration order, uniqueness, and value resolution.
For-in enumeration benchmarks
benchmarks/for-in/for-in.js, benchmarks/for-in/goccia.json
Adds a benchmark suite for flat and prototype-chain for...in enumeration and enables the related benchmark config flag.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

bug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main performance change to for-in deduplication.
Description check ✅ Passed The description matches the template with Summary and Testing sections, key constraints, linked issue, and verification notes.
Linked Issues check ✅ Passed The patch replaces linear key tracking with a hash-set approach and preserves ordering and membership semantics as requested in #809.
Out of Scope Changes check ✅ Passed The added tests and benchmark directly support the for-in dedup fix, and no unrelated code changes are evident.
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.

@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Suite Timing

Test Runner (interpreted: 10,958 passed; bytecode: 10,958 passed)
Metric Interpreted Bytecode
Total 10958 10958
Passed 10958 ✅ 10958 ✅
Workers 4 4
Test Duration 19.53s 19.23s
Lex (cumulative) 536.9ms 561.2ms
Parse (cumulative) 392.1ms 388.1ms
Compile (cumulative) 805.2ms
Execute (cumulative) 94.1ms 43.59s
Engine Total (cumulative) 1.02s 45.35s
Lex (avg/worker) 134.2ms 140.3ms
Parse (avg/worker) 98.0ms 97.0ms
Compile (avg/worker) 201.3ms
Execute (avg/worker) 23.5ms 10.90s
Engine Total (avg/worker) 255.8ms 11.34s

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.87 MiB 280.29 MiB
GC Peak Live 330.28 MiB 352.37 MiB
GC Allocated During Run 529.00 MiB 473.17 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 195 195
GC Collected Objects 2,597,585 2,167,848
Heap Start Allocated 181.0 KiB 181.0 KiB
Heap End Allocated 3.65 MiB 3.65 MiB
Heap Delta Allocated 3.48 MiB 3.48 MiB
Heap Delta Free 1.68 MiB 1.68 MiB
Benchmarks (interpreted: 436; bytecode: 436)
Metric Interpreted Bytecode
Total 436 436
Workers 4 4
Duration 2.87min 2.81min

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 110.16 MiB 81.80 MiB
GC Allocated During Run 15.42 GiB 10.64 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 3,617 3,692
GC Collected Objects 242,639,910 239,963,555
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 27, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

436 benchmarks · PR vs same-runner main build

Interpreted: 🟢 35 improved · 🔴 27 regressed · 374 unchanged · avg +1.5%
Bytecode: 🟢 21 improved · 🔴 49 regressed · 366 unchanged · avg +1.4%

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

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

@frostney frostney marked this pull request as ready for review June 27, 2026 18:16
@coderabbitai coderabbitai Bot added the bug Something isn't working label Jun 27, 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 (1)
tests/language/for-in-loop/basic-enumeration.js (1)

194-199: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the inherited unique* suffix order too.

This test proves the shared-key prefix and total count, but it never checks the order of the inherited unique keys. A regression that scrambles prototype-level unique-key order would still pass.

Suggested assertion
   // All shared keys plus one unique key per level, no duplicates.
   expect(seen.length).toBe(SHARED + LEVELS);
+  expect(seen.slice(SHARED)).toEqual(
+    Array.from({ length: LEVELS }, (_, i) => "unique" + (LEVELS - 1 - i)),
+  );
🤖 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/language/for-in-loop/basic-enumeration.js` around lines 194 - 199, The
for-in enumeration test verifies the shared-key prefix and total length, but it
does not assert the ordering of the inherited unique keys, so a prototype-level
ordering regression could slip through. Extend the assertions in
basic-enumeration.js after the existing seen.slice and length checks to validate
the suffix order of the unique keys from each inherited level, using the
existing seen, sharedKeys, SHARED, and LEVELS symbols to pinpoint the expected
sequence.
🤖 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 `@tests/language/for-in-loop/basic-enumeration.js`:
- Around line 194-199: The for-in enumeration test verifies the shared-key
prefix and total length, but it does not assert the ordering of the inherited
unique keys, so a prototype-level ordering regression could slip through. Extend
the assertions in basic-enumeration.js after the existing seen.slice and length
checks to validate the suffix order of the unique keys from each inherited
level, using the existing seen, sharedKeys, SHARED, and LEVELS symbols to
pinpoint the expected sequence.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 01515fe1-e8cc-4ecc-9998-c8cddfb55fa3

📥 Commits

Reviewing files that changed from the base of the PR and between 47c7a04 and cb71fc2.

📒 Files selected for processing (5)
  • benchmarks/for-in/for-in.js
  • benchmarks/for-in/goccia.json
  • source/units/Goccia.Evaluator.pas
  • source/units/Goccia.VM.pas
  • tests/language/for-in-loop/basic-enumeration.js

@github-actions

Copy link
Copy Markdown
Contributor

test262 Conformance

Category Run Passed Δ Pass Failed Pass-rate Δ Rate
built-ins 23,643 22,609 +1 1,034 95.6% ±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,109 +1 373 74.8% +0.1pp
total 52,293 50,879 +2 1,414 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 (+2 / -0)

Newly passing (2):

  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js
  • staging/sm/extensions/recursion.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.

Strengthen the deep-chain for-in dedup test to also assert the order of the
inherited level-unique keys (leaf to root), not just the shared-key prefix
and total count, so a prototype-level enumeration-order regression cannot
slip through.
@frostney frostney merged commit 3d6f4e2 into main Jun 27, 2026
15 checks passed
@frostney frostney deleted the claude/stoic-hamilton-69cc57 branch June 27, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(interpreter): for-in key dedup uses linear TStringList.IndexOf (O(k^2))

1 participant