Skip to content

Fix for-await-of IteratorClose on abrupt completion#620

Merged
frostney merged 7 commits into
mainfrom
issue-575-for-await-of-iterator-close
May 9, 2026
Merged

Fix for-await-of IteratorClose on abrupt completion#620
frostney merged 7 commits into
mainfrom
issue-575-for-await-of-iterator-close

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented May 9, 2026

Summary

  • Fix for await...of not calling the async iterator's .return() method when the loop exits early via break, return, or throw — in both interpreter and bytecode modes.
  • Interpreter: add CloseAsyncIteratorPreservingError nested procedure (calls .return(), awaits the result per ES2026 AsyncIteratorClose) at all four abrupt-completion sites in the async iterator path; add the existing CloseIteratorPreservingError calls to the sync iterator fallback path.
  • Bytecode compiler: mirror the sync CompileForOfStatement pattern — NeedsIteratorClose detection, CloseErrorReg allocation, OP_PUSH_HANDLER, TPendingFinallyEntry with IsIteratorClose, and OP_ITER_CLOSE + OP_THROW at the handler target.
  • Closes Engine: bytecode for-await-of skips IteratorClose on abrupt completion #575

Testing

  • Verified no regressions and confirmed the new feature or bugfix in end-to-end JavaScript/TypeScript tests
  • Updated documentation
  • Optional: Verified no regressions and confirmed the new feature or bugfix in native Pascal tests (if AST, scope, evaluator, or value types changed)
  • Optional: Verified no benchmark regressions or confirmed benchmark coverage for the change

`for await...of` was not calling the iterator's `.return()` method when
the loop exited early via break, return, or throw — in both interpreter
and bytecode modes.

Interpreter: add CloseAsyncIteratorPreservingError (calls `.return()`,
awaits the result per AsyncIteratorClose spec) at all four abrupt-
completion sites in the async iterator path, and add the existing
CloseIteratorPreservingError calls to the sync iterator fallback path.

Bytecode compiler: mirror the sync CompileForOfStatement pattern —
NeedsIteratorClose detection, CloseErrorReg allocation, OP_PUSH_HANDLER,
TPendingFinallyEntry with IsIteratorClose, and OP_ITER_CLOSE + OP_THROW
at the handler target.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 9, 2026

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 May 9, 2026 10:40pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 9, 2026

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

Run ID: f18cffe3-ec68-4fa3-b423-53b2d31117b7

📥 Commits

Reviewing files that changed from the base of the PR and between b35432c and 5075856.

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

📝 Walkthrough

Walkthrough

Adds async-aware iterator-close across compiler, evaluator, and VM: marks pending-finally entries as async, emits async-mode OP_ITER_CLOSE from compiler, implements awaited iterator.return() paths in VM and evaluator, and adds tests covering break/return/throw and sync fallback cases.

Changes

Async Iterator Close on Abrupt Completion

Layer / File(s) Summary
Data Structure
source/units/Goccia.Compiler.Statements.pas
TPendingFinallyEntry adds IsAsyncIterator Boolean field to distinguish async vs sync iterator-close modes.
Compiler - Async For-await Codegen
source/units/Goccia.Compiler.Statements.pas
CompileForAwaitOfStatement conditionally allocates CloseErrorReg, computes NeedsIteratorClose, emits OP_PUSH_HANDLER, pushes TPendingFinallyEntry with IsAsyncIterator := True, emits async OP_ITER_CLOSE in handler/teardown paths, and conditionally frees CloseErrorReg.
Evaluator - for-await-of Close Semantics
source/units/Goccia.Evaluator.pas
Adds CloseAsyncIterator and CloseAsyncIteratorPreservingError, introduces ShouldCloseIterator per-iteration flag, and invokes preserving/non-preserving async-close on head exceptions, body exceptions, and early exits in saved-loop-state and normal paths.
VM Runtime - Async Iterator Close
source/units/Goccia.VM.pas
Adds CloseRawAsyncIterator (calls/awaits return() and validates result), updates CloseRawIteratorPreservingError to accept an AAsync flag, and changes OP_ITER_CLOSE dispatch to select async/sync and preserving/non-preserving close based on opcode operands.
Tests
tests/language/for-of/for-await-of.js
Adds tests verifying return() is invoked and awaited on break, return, and exception; checks error precedence when return() throws; ensures return() not called on continue or when missing; includes sync-iterator fallback cases.

Sequence Diagram(s)

sequenceDiagram
  participant Compiler
  participant VM
  participant Iterator
  participant Evaluator
  Compiler->>VM: emit OP_ITER_CLOSE async=1 on abrupt exit
  VM->>Iterator: call return() (await in async path)
  alt return() present and resolves to object
    Iterator-->>VM: promise resolved with object
    VM-->>Evaluator: continue/exit
  else missing/primitive/undefined/null
    Iterator-->>VM: resolved to invalid
    VM-->>Evaluator: throw TypeError
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix for-await-of IteratorClose on abrupt completion' directly and clearly describes the main change: fixing the for-await-of construct's iterator closing behavior during abrupt completion.
Description check ✅ Passed The description covers the summary (the fix), identifies both interpreter and bytecode compiler changes, and links to issue #575; only the documentation and optional benchmark/native tests checkboxes are unchecked as noted.
Linked Issues check ✅ Passed The pull request directly addresses issue #575 by implementing all required objectives: detecting NeedsIteratorClose, allocating CloseErrorReg, emitting OP_PUSH_HANDLER and TPendingFinallyEntry with IsAsyncIterator/IsIteratorClose flags, and handling async await of .return() in both compiler and evaluator.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing for-await-of iterator closing: compiler OP_ITER_CLOSE handling, evaluator async iterator close helpers, VM opcode dispatch updates, and corresponding test coverage—no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Suite Timing

Test Runner (interpreted: 9,037 passed; bytecode: 9,037 passed)
Metric Interpreted Bytecode
Total 9037 9037
Passed 9037 ✅ 9037 ✅
Workers 4 4
Test Duration 1.91s 2.10s
Lex (cumulative) 244.4ms 158.9ms
Parse (cumulative) 264.8ms 270.1ms
Compile (cumulative) 522.4ms
Execute (cumulative) 2.09s 2.30s
Engine Total (cumulative) 2.60s 3.25s
Lex (avg/worker) 61.1ms 39.7ms
Parse (avg/worker) 66.2ms 67.5ms
Compile (avg/worker) 130.6ms
Execute (avg/worker) 521.6ms 575.0ms
Engine Total (avg/worker) 648.9ms 812.8ms

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 230.18 MiB 224.68 MiB
GC Peak Live 230.19 MiB 224.68 MiB
GC Allocated During Run 234.02 MiB 228.50 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 1 1
GC Collected Objects 74 74
Heap Start Allocated 146.6 KiB 146.6 KiB
Heap End Allocated 1.38 MiB 1.38 MiB
Heap Delta Allocated 1.24 MiB 1.24 MiB
Heap Delta Free 715.3 KiB 715.3 KiB
Benchmarks (interpreted: 407; bytecode: 407)
Metric Interpreted Bytecode
Total 407 407
Workers 4 4
Duration 2.44min 2.41min

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 3.44 MiB 3.43 MiB
GC Peak Live 100.15 MiB 80.77 MiB
GC Allocated During Run 14.66 GiB 10.31 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 2,813 2,635
GC Collected Objects 269,662,188 244,146,782
Heap Start Allocated 1.14 MiB 1.14 MiB
Heap End Allocated 1.14 MiB 1.14 MiB
Heap Delta Allocated 128 B 128 B

Measured on ubuntu-latest x64.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Benchmark Results

407 benchmarks

Interpreted: 🟢 206 improved · 🔴 83 regressed · 118 unchanged · avg +4.4%
Bytecode: 🟢 338 improved · 🔴 25 regressed · 44 unchanged · avg +10.2%

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

Deterministic profile diff

async-generators

  • 🔴 OP_POP_HANDLER: 0 → 2 (NEW)
  • 🔴 OP_PUSH_HANDLER: 0 → 2 (NEW)

Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

test262 Conformance

Category Run Passed Δ Pass Failed Pass-rate Δ Rate
built-ins 23,449 14,487 +1 8,961 61.8% ±0pp
harness 116 71 ±0 45 61.2% ±0pp
intl402 3,324 167 ±0 3,157 5.0% ±0pp
language 23,635 12,575 +5 11,060 53.2% ±0pp
staging 1,484 484 +1 998 32.6% +0.1pp
total 52,008 27,784 +7 24,221 53.4% ±0pp

Areas closest to 100%

Area Pass rate Δ vs main Passing
built-ins/WeakSet 98.8% ±0pp 84 / 85
built-ins/WeakMap 98.6% ±0pp 139 / 141
language/asi 97.1% ±0pp 99 / 102
Per-test deltas (+7 / -0)

Newly passing (7):

  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js
  • language/statements/for-await-of/iterator-close-non-throw-get-method-abrupt.js
  • language/statements/for-await-of/iterator-close-non-throw-get-method-non-callable.js
  • language/statements/for-of/iterator-close-non-object.js
  • language/statements/for-of/iterator-close-non-throw-get-method-abrupt.js
  • language/statements/for-of/iterator-close-non-throw-get-method-non-callable.js
  • staging/sm/statements/for-of-iterator-close-throw.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.

OP_ITER_CLOSE now uses its B operand as an async flag (B=1 means await
the .return() result per AsyncIteratorClose spec). The compiler sets
B=1 for for-await-of and a new IsAsyncIterator field on
TPendingFinallyEntry carries the flag through EmitPendingEntryCleanup.

Also adds the missing sync-fallback-on-return test and reverts the
unrelated MismatchJump reorder from the previous commit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney marked this pull request as ready for review May 9, 2026 22:10
@coderabbitai coderabbitai Bot added bug Something isn't working spec compliance Mismatch against official JavaScript/TypeScript specification internal Refactoring, CI, tooling, cleanup labels May 9, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/language/for-of/for-await-of.js (1)

361-388: ⚡ Quick win

Consider strengthening the assertion to verify the .return() promise is awaited.

The test currently logs "return" synchronously before the promise settles. While the test verifies that .return() is called, it doesn't verify that the engine awaits the returned promise—per the ES spec requirement for for-await-of on abrupt completion. Moving the logged marker into the promise chain makes this assertion stricter.

Proposed enhancement
          return() {
-            log.push("return");
-            return Promise.resolve({ done: true });
+            log.push("return:start");
+            return Promise.resolve().then(() => {
+              log.push("return:end");
+              return { done: true };
+            });
           }

Then update the final assertion:

-    expect(log.join(",")).toBe("next:1,next:2,return");
+    expect(log.join(",")).toBe("next:1,next:2,return:start,return:end");
🤖 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-of/for-await-of.js` around lines 361 - 388, The test
should ensure the for-await-of loop actually awaits the promise returned by the
async iterator's return method: change asyncIter's return() to return a promise
that logs only after it resolves (e.g. return Promise.resolve().then(() => {
log.push("return"); return { done: true }; })), keeping the rest of the test
(including the expect for "next:1,next:2,return") unchanged; this uses the
asyncIter and its return() method in the "calls async iterator return on break"
test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@source/units/Goccia.Evaluator.pas`:
- Around line 2045-2075: The code is calling
CloseAsyncIteratorPreservingError/CloseIteratorPreservingError for non-exception
completions (cfkBreak/cfkReturn), which suppresses iterator .return() failures;
change the break/return paths to call the non-preserving cleanup functions
(AsyncIteratorClose/IteratorClose) instead of
CloseAsyncIteratorPreservingError/CloseIteratorPreservingError so that
close-time errors replace the loop completion rather than being swallowed;
update the call sites that currently reference CloseAsyncIteratorPreservingError
(and the synchronous CloseIteratorPreservingError) in the cfkBreak/cfkReturn
handling to call the non-preserving versions and keep Close*Preserving* only on
the exception/throw paths.

In `@source/units/Goccia.VM.pas`:
- Around line 4246-4255: CloseRawIteratorPreservingError currently swallows all
exceptions from CloseRawAsyncIterator, which hides rejections for non-throw
abrupt completions; change the helper to accept the original completion kind (or
a boolean like wasThrowCompletion) and only suppress exceptions when the
original completion was a Throw, otherwise propagate the exception back to the
caller so the VM can replace the pending completion with the iterator-return
failure. Update all call sites that route abrupt completions through this helper
(e.g., OP_ITER_CLOSE and the cleanup paths from CompileBreakStatement /
CompileReturnStatement → EmitPendingCleanup → EmitPendingEntryCleanup) to pass
the correct completion-kind flag, and ensure CloseRawIteratorPreservingError
uses CloseRawAsyncIterator / CloseRawIterator unchanged but re-raises or returns
the error when the original completion was not a Throw.

---

Nitpick comments:
In `@tests/language/for-of/for-await-of.js`:
- Around line 361-388: The test should ensure the for-await-of loop actually
awaits the promise returned by the async iterator's return method: change
asyncIter's return() to return a promise that logs only after it resolves (e.g.
return Promise.resolve().then(() => { log.push("return"); return { done: true };
})), keeping the rest of the test (including the expect for
"next:1,next:2,return") unchanged; this uses the asyncIter and its return()
method in the "calls async iterator return on break" test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 612887aa-4091-4970-bcbf-a126e07f4a86

📥 Commits

Reviewing files that changed from the base of the PR and between f2531ee and dccd190.

📒 Files selected for processing (4)
  • source/units/Goccia.Compiler.Statements.pas
  • source/units/Goccia.Evaluator.pas
  • source/units/Goccia.VM.pas
  • tests/language/for-of/for-await-of.js

Comment thread source/units/Goccia.Evaluator.pas Outdated
Comment thread source/units/Goccia.VM.pas
frostney and others added 3 commits May 9, 2026 23:17
Per AsyncIteratorClose step 6–7: only suppress .return() errors when
the original completion is a throw.  Break/return must let close-time
errors surface as the new completion.

Split evaluator CloseAsyncIterator (propagates) from
CloseAsyncIteratorPreservingError (swallows).  Use OP_ITER_CLOSE C
operand as a preserve-error flag (C=1 on exception handler targets,
C=0 on break/return via EmitPendingEntryCleanup).  Strengthen the
break test to verify the .return() promise is actually awaited, and
add a test for .return() rejection surfacing on break.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers the second case CodeRabbit suggested: for-await-of with an
in-loop return where iterator.return() rejects — the rejection must
surface as the new completion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@tests/language/for-of/for-await-of.js`:
- Around line 451-477: The test "preserves original error when return also
throws" currently doesn't verify that the iterator's return() was invoked; add a
boolean flag (e.g., returnCalled = false) and set it to true inside the
asyncIter's return() method, then after the try/catch add an assertion that
returnCalled is true in addition to the existing
expect(caughtMessage).toBe("body-threw"); this ensures the async iterator's
return() actually ran (refer to asyncIter, its return() method, the
caughtMessage variable and the test block).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3abc5070-63ab-4b68-9c89-0b4d6996c7ca

📥 Commits

Reviewing files that changed from the base of the PR and between a01a6c1 and b35432c.

📒 Files selected for processing (1)
  • tests/language/for-of/for-await-of.js

Comment thread tests/language/for-of/for-await-of.js
Add returnCalled counter to the "preserves original error when return
also throws" test so it cannot false-positive when iterator close is
skipped entirely.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney merged commit 2336083 into main May 9, 2026
14 checks passed
@frostney frostney deleted the issue-575-for-await-of-iterator-close branch May 9, 2026 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working internal Refactoring, CI, tooling, cleanup spec compliance Mismatch against official JavaScript/TypeScript specification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Engine: bytecode for-await-of skips IteratorClose on abrupt completion

1 participant