Skip to content

Add for-in compatibility flag#697

Open
frostney wants to merge 4 commits into
mainfrom
t3code/d69a1c9b
Open

Add for-in compatibility flag#697
frostney wants to merge 4 commits into
mainfrom
t3code/d69a1c9b

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Jun 2, 2026

Summary

  • Add --compat-for-in-loop / "compat-for-in-loop" / cfForIn as a standalone JavaScript compatibility flag for for...in loops.
  • Implement enumerable string key traversal for own and inherited properties in interpreter and bytecode modes, including per-entry descriptor revalidation so deleted or newly non-enumerable properties are skipped when reached.
  • Wire the flag through CLI/config/source pipeline/test262 runner docs, remove the unused test262 compatibility roadmap JSON, and add focused for...in tests.

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

Commands run:

  • ./build.pas loader testrunner
  • ./build.pas loaderbare benchmarkrunner bundler repl
  • ./build/GocciaTestRunner tests/language/for-in-loop
  • ./build/GocciaTestRunner tests/language/for-in-loop --mode=bytecode
  • ./build/GocciaTestRunner tests
  • bun scripts/test-cli.ts
  • bun scripts/run_test262_suite.ts --help
  • direct GocciaScriptLoaderBare --compat-for-in-loop stdin smoke
  • ./format.pas --check
  • git diff --check

Not run: full external test262 suite.

@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 2, 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 Jun 2, 2026 8:54pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 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: 90892912-f7fc-41bf-8be1-a7bdbb14b431

📥 Commits

Reviewing files that changed from the base of the PR and between 999ad2d and aedf2b8.

📒 Files selected for processing (3)
  • source/units/Goccia.Parser.pas
  • tests/language/for-loop/top-level-await/await-array-literal-header.js
  • tests/language/for-loop/top-level-await/goccia.json
✅ Files skipped from review due to trivial changes (1)
  • tests/language/for-loop/top-level-await/goccia.json

📝 Walkthrough

Walkthrough

This PR implements JavaScript for...in loops as an opt-in compatibility mode (--compat-for-in-loop), adding support across the parser, bytecode compiler, interpreter evaluator, bytecode VM, and test infrastructure. The feature enumerates own and inherited enumerable properties with proper prototype-chain traversal, supports destructuring and var bindings, and integrates control-flow (break/continue/return) handling.

Changes

for...in Loop Implementation

Layer / File(s) Summary
Parser and AST Surface
source/units/Goccia.Parser.pas, source/units/Goccia.AST.Statements.pas, source/units/Goccia.AST.BindingPatterns.pas, source/units/Goccia.AST.Expressions.pas
Parser gains configurable ForInLoopsEnabled option. ForStatement detects and parses for...in via binding-pattern heads and expression-based targets converted to patterns. TGocciaForInStatement AST node models loop state; ConvertToPattern supports private-member targets; binding-name collection extended for for-in.
Bytecode Format and Compiler
source/units/Goccia.Bytecode.pas, source/units/Goccia.Compiler.Statements.pas, source/units/Goccia.Compiler.pas
Bytecode format version bumped. New opcodes OP_ENUM_KEYS and OP_ENUM_ENTRY added. CompileForInStatement emits enumeration, per-iteration scope, binding/destructuring emission, continue/break patching, upvalue closing, and register cleanup. Hoisting and static analysis extended for for-in.
Evaluator: Interpreter Execution
source/units/Goccia.Evaluator.pas
EvaluateForIn implements runtime semantics: materializes entries array from RHS via prototype traversal with deduplication and depth cap, validates per-entry enumerability, binds per-iteration targets (including destructuring and var), supports generator suspension/resumption, and propagates abrupt completions. Destructuring was normalized with ToObject and private-member assignment handling added.
VM Bytecode Execution and Object Enumeration
source/units/Goccia.VM.pas, source/units/Goccia.Values.ObjectValue.pas
VM provides ForInEntriesArray to build tagged entry objects and TryForInEntryKey for validation; executor handles OP_ENUM_KEYS and OP_ENUM_ENTRY. VM enforces prototype-chain traversal limits and deduplication semantics.
Destructuring & Private-Member Emission
source/units/Goccia.Compiler.Expressions.pas, source/units/Goccia.AST.Expressions.pas
New TGocciaPrivateMemberExpressionDestructuringPattern added and wired into destructuring emission; EmitBindingAssignmentFromRegister promoted to interface for cross-unit use; EmitDestructuring stores to private slots via PrivateKey(...).
Binding Patterns & Hoisting
source/units/Goccia.AST.BindingPatterns.pas, source/units/Goccia.Compiler.pas
CollectVarBindingNamesFromNode and HoistVarLocals recognize TGocciaForInStatement and hoist var bindings from loop heads and patterns.
Configuration, Testing, and Documentation
source/units/Goccia.SourcePipeline.pas, source/app/Goccia.CLI.Options.pas, scripts/run_test262_suite.ts, scripts/test-cli.ts, README.md, docs/*, tests/language/for-in-loop/*
TGocciaCompatibility gains cfForIn; parser options wired from source-pipeline. CLI and test runners accept/emit --compat-for-in-loop. README and multiple docs updated to list for...in as opt-in; new tests added covering enumeration, control-flow, var hoisting, destructuring, and unsupported-feature fallbacks. One large JSON roadmap file removed.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • frostney/GocciaScript#632: Related changes to Test262 runner compatibility flag handling; this PR adds --compat-for-in-loop to explicit compat flags.
  • frostney/GocciaScript#682: Adds/extends TGocciaSourcePipeline compatibility/option surface used here (cfForIn).
  • frostney/GocciaScript#368: var binding and hoisting infrastructure reused/extended for for...in var-head semantics.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add for-in compatibility flag' directly and clearly summarizes the main change: adding a new compatibility flag for for...in loops.
Description check ✅ Passed The description includes a clear summary of changes, testing completion status with checkmarks, specific commands run, and notes about what was not completed, following the required template structure.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

Suite Timing

Test Runner (interpreted: 9,909 passed; bytecode: 9,909 passed)
Metric Interpreted Bytecode
Total 9909 9909
Passed 9909 ✅ 9909 ✅
Workers 4 4
Test Duration 3.51s 3.41s
Lex (cumulative) 406.4ms 405.3ms
Parse (cumulative) 296.0ms 289.4ms
Compile (cumulative) 583.2ms
Execute (cumulative) 5.39s 4.28s
Engine Total (cumulative) 6.09s 5.55s
Lex (avg/worker) 101.6ms 101.3ms
Parse (avg/worker) 74.0ms 72.3ms
Compile (avg/worker) 145.8ms
Execute (avg/worker) 1.35s 1.07s
Engine Total (avg/worker) 1.52s 1.39s

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 288.56 MiB 280.95 MiB
GC Peak Live 288.56 MiB 280.96 MiB
GC Allocated During Run 293.12 MiB 285.51 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 1 1
GC Collected Objects 87 87
Heap Start Allocated 161.3 KiB 161.3 KiB
Heap End Allocated 1.54 MiB 1.54 MiB
Heap Delta Allocated 1.38 MiB 1.38 MiB
Heap Delta Free 890.0 KiB 890.0 KiB
Benchmarks (interpreted: 407; bytecode: 407)
Metric Interpreted Bytecode
Total 407 407
Workers 4 4
Duration 2.49min 2.28min

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.97 MiB 3.97 MiB
GC Peak Live 122.76 MiB 90.33 MiB
GC Allocated During Run 16.72 GiB 9.54 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 2,823 2,660
GC Collected Objects 264,880,069 215,607,965
Heap Start Allocated 1.27 MiB 1.27 MiB
Heap End Allocated 1.27 MiB 1.27 MiB
Heap Delta Allocated 128 B 128 B

Measured on ubuntu-latest x64.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

Benchmark Results

407 benchmarks

Interpreted: 🟢 8 improved · 🔴 395 regressed · 4 unchanged · avg -21.6%
Bytecode: 🟢 27 improved · 🔴 353 regressed · 27 unchanged · avg -8.1%

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

Deterministic profile diff

Deterministic profile diff: no significant changes.

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 Jun 2, 2026

test262 Conformance

🚫 Regression vs cached main baseline. 6 previously-passing test(s) now fail; pass count Δ +210. This run blocks merge — see "Newly failing" below.

Category Run Passed Δ Pass Failed Pass-rate Δ Rate
built-ins 23,449 16,237 +161 7,206 69.2% +0.7pp
harness 116 72 ±0 44 62.1% ±0pp
intl402 3,324 1,000 ±0 2,324 30.1% ±0pp
language 23,635 14,677 +46 8,958 62.1% +0.2pp
staging 1,484 579 +3 903 39.0% +0.2pp
total 52,008 32,565 +210 19,435 62.6% +0.4pp

Areas closest to 100%

Area Pass rate Δ vs main Passing
language/block-scope 99.3% +0.7pp 144 / 145
built-ins/WeakMap 99.3% ±0pp 140 / 141
language/asi 99.0% ±0pp 101 / 102
Per-test deltas (+216 / -6)

Newly failing (6):

  • built-ins/RegExp/character-class-escape-non-whitespace.js
  • built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/enumerate-detached-buffer.js
  • built-ins/TypedArrayConstructors/internals/GetOwnProperty/enumerate-detached-buffer.js
  • staging/sm/expressions/object-literal-__proto__.js
  • staging/sm/misc/builtin-methods-reject-null-undefined-this.js
  • staging/sm/statements/for-in-with-gc-and-unvisited-deletion.js

Newly passing (216):

  • built-ins/Array/prototype/splice/15.4.4.12-9-c-ii-1.js
  • built-ins/Function/length/S15.3.5.1_A4_T1.js
  • built-ins/Function/length/S15.3.5.1_A4_T2.js
  • built-ins/Function/length/S15.3.5.1_A4_T3.js
  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js
  • built-ins/Object/create/15.2.3.5-4-46.js
  • built-ins/Object/create/15.2.3.5-4-48.js
  • built-ins/Object/create/15.2.3.5-4-49.js
  • built-ins/Object/create/15.2.3.5-4-52.js
  • built-ins/Object/create/15.2.3.5-4-53.js
  • built-ins/Object/create/15.2.3.5-4-59.js
  • built-ins/Object/create/15.2.3.5-4-60.js
  • built-ins/Object/create/15.2.3.5-4-61.js
  • built-ins/Object/create/15.2.3.5-4-62.js
  • built-ins/Object/create/15.2.3.5-4-63.js
  • built-ins/Object/create/15.2.3.5-4-64.js
  • built-ins/Object/create/15.2.3.5-4-65.js
  • built-ins/Object/create/15.2.3.5-4-66.js
  • built-ins/Object/create/15.2.3.5-4-67.js
  • built-ins/Object/create/15.2.3.5-4-68.js
  • built-ins/Object/create/15.2.3.5-4-69.js
  • built-ins/Object/create/15.2.3.5-4-71.js
  • built-ins/Object/create/15.2.3.5-4-74.js
  • built-ins/Object/create/15.2.3.5-4-80.js
  • built-ins/Object/create/15.2.3.5-4-81.js
  • built-ins/Object/create/15.2.3.5-4-83.js
  • built-ins/Object/create/15.2.3.5-4-84.js
  • built-ins/Object/create/15.2.3.5-4-85.js
  • built-ins/Object/create/15.2.3.5-4-86.js
  • built-ins/Object/create/15.2.3.5-4-87.js
  • built-ins/Object/create/15.2.3.5-4-88.js
  • built-ins/Object/create/15.2.3.5-4-89.js
  • built-ins/Object/create/15.2.3.5-4-90.js
  • built-ins/Object/create/15.2.3.5-4-91.js
  • built-ins/Object/create/15.2.3.5-4-92.js
  • built-ins/Object/create/15.2.3.5-4-93.js
  • built-ins/Object/create/15.2.3.5-4-94.js
  • built-ins/Object/create/15.2.3.5-4-96.js
  • built-ins/Object/create/15.2.3.5-4-97.js
  • built-ins/Object/create/15.2.3.5-4-98.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-12.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-13.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-19.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-20.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-21.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-22.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-23.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-24.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-25.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-26.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-27.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-28.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-29.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-31.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-34.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-40.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-41.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-43.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-44.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-45.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-46.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-47.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-48.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-49.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-50.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-51.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-52.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-53.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-54.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-56.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-57.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-58.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-6.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-8.js
  • built-ins/Object/defineProperties/15.2.3.7-5-b-9.js
  • built-ins/Object/defineProperty/15.2.3.6-3-22.js
  • built-ins/Object/defineProperty/15.2.3.6-3-23.js
  • built-ins/Object/defineProperty/15.2.3.6-3-24.js
  • built-ins/Object/defineProperty/15.2.3.6-3-25.js
  • built-ins/Object/defineProperty/15.2.3.6-3-26.js
  • built-ins/Object/defineProperty/15.2.3.6-3-27.js
  • built-ins/Object/defineProperty/15.2.3.6-3-28.js
  • built-ins/Object/defineProperty/15.2.3.6-3-29.js
  • built-ins/Object/defineProperty/15.2.3.6-3-33-1.js
  • built-ins/Object/defineProperty/15.2.3.6-3-33.js
  • built-ins/Object/defineProperty/15.2.3.6-3-34-1.js
  • built-ins/Object/defineProperty/15.2.3.6-3-34.js
  • built-ins/Object/defineProperty/15.2.3.6-3-35-1.js
  • built-ins/Object/defineProperty/15.2.3.6-3-35.js
  • built-ins/Object/defineProperty/15.2.3.6-3-36-1.js
  • built-ins/Object/defineProperty/15.2.3.6-3-36.js
  • built-ins/Object/defineProperty/15.2.3.6-3-37-1.js
  • built-ins/Object/defineProperty/15.2.3.6-3-37.js
  • built-ins/Object/defineProperty/15.2.3.6-3-38-1.js
  • built-ins/Object/defineProperty/15.2.3.6-3-38.js
  • built-ins/Object/defineProperty/15.2.3.6-3-39-1.js
  • built-ins/Object/defineProperty/15.2.3.6-3-39.js
  • built-ins/Object/defineProperty/15.2.3.6-3-40-1.js
  • built-ins/Object/defineProperty/15.2.3.6-3-40.js
  • built-ins/Object/defineProperty/15.2.3.6-3-41-1.js
  • … 116 more

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

@frostney frostney marked this pull request as ready for review June 2, 2026 20:18
@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation new feature New feature or request spec compliance Mismatch against official JavaScript/TypeScript specification internal Refactoring, CI, tooling, cleanup labels Jun 2, 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: 6

🧹 Nitpick comments (2)
tests/language/for-in-loop/control-flow.js (1)

24-30: ⚡ Quick win

Add a return control-flow case.

This suite covers break and continue, but not return, which is another dedicated path in the new for...in execution logic. A small helper test here would guard both interpreter and bytecode propagation.

➕ Suggested test
 test("closures capture per-iteration lexical bindings", () => {
   const fns = [];
   for (const key in { a: 1, b: 2, c: 3 }) {
     fns.push(() => key);
   }
   expect(fns.map(fn => fn())).toEqual(["a", "b", "c"]);
 });
+
+test("return exits the loop and propagates the value", () => {
+  const run = () => {
+    for (const key in { a: 1, b: 2, c: 3 }) {
+      if (key === "b") return key;
+    }
+    return "miss";
+  };
+  expect(run()).toBe("b");
+});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/language/for-in-loop/control-flow.js` around lines 24 - 30, Add a small
test that verifies the `return` control-flow path inside a `for...in` loop also
preserves per-iteration lexical bindings: replicate the existing test pattern
(the `test("closures capture per-iteration lexical bindings", ...)` setup with
`fns` and a `for (const key in {...})`) but include a `return` from within the
loop on a specific key so the loop exits early and ensure the pushed closure
still captures the correct per-iteration `key` values for iterations executed
before the return; update or add a new test name to reflect the `return` case so
the interpreter and bytecode propagation for `return` are exercised.
tests/language/statements/unsupported-features.js (1)

19-31: ⚡ Quick win

Add the skipped destructuring-head case.

The parser has a separate for...in binding-pattern path, but this negative coverage only exercises identifier and assignment targets. A destructuring head here would protect the other compat-gated syntax path too.

➕ Suggested test
   test("code after skipped for-in assignment target loop executes", () => {
     let x = 1;
     let key;
     for (key in { a: 1 }) { x = 99; }
     expect(x).toBe(1);
     expect(key).toBe(undefined);
   });
+
+  test("code after skipped destructuring for-in loop executes", () => {
+    let x = 1;
+    for (const [key] in { ab: 1 }) { x = 99; }
+    expect(x).toBe(1);
+    expect(typeof key).toBe("undefined");
+  });
🤖 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/statements/unsupported-features.js` around lines 19 - 31, Add
a new test that covers the skipped destructuring-head path: mirror the existing
for-in negative tests but use a binding-pattern in the loop head (e.g., test
name "code after skipped for-in destructuring-head executes" and a loop like for
(const [k] in { a: 1 }) { x = 99; }), assert x stays 1 after the loop to ensure
the binding-pattern path in the parser is exercised (reference the existing
tests "code after skipped for-in loop executes" and "code after skipped for-in
assignment target loop executes" to match style and expectations).
🤖 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.Compiler.Statements.pas`:
- Around line 2681-2688: The code only treats a for-in loop's BindingName as a
write when ForIn.IsVar is true, which lets TryCompileCountedFor incorrectly keep
the counted-for fast path; change the check so any for-in loop that binds the
identifier is considered a definite write: in the TGocciaForInStatement branch,
replace the condition "if (ForIn.BindingName = AName) and ForIn.IsVar then
Exit(True)" with a check that treats BindingName match unconditionally (e.g., if
ForIn.BindingName = AName then Exit(True)); keep the existing calls to
ForBodyAssignsIdentifier(ForIn.ObjectExpression, AName) and
ForBodyAssignsIdentifier(ForIn.Body, AName) unchanged.

In `@source/units/Goccia.Evaluator.pas`:
- Around line 2056-2083: The loop state (EntriesArray/EntryIndex/CurrentValue)
is only saved after AssignPattern runs, but AssignPattern can trigger
EGocciaGeneratorYield (computed names/defaults), so a yielded generator will
restart the for...in header; to fix, mirror EvaluateForOf's two-phase head
handling: call Continuation.SaveLoopState with the simple iteration state
(EntriesArray, EntryIndex, CurrentValue) before performing
binding/destructuring, then after the binding finishes replace/update the saved
state with the scopeful state (IterScope/IterContext.Scope/whatever
Continuation.SaveLoopState expects for the per-iteration scope). Ensure you move
the initial SaveLoopState call to just after computing CurrentValue and before
AssignPattern, and keep the existing SaveLoopState call (or update it) to store
the final scopeful state once bindings complete.
- Around line 1910-1935: CreateForInEntriesArray currently allocates Result,
calls ToObject (which may box a primitive) and then allocates EntryObj and key
values without rooting them, allowing a re-entrant GC to reclaim partially built
values; fix by temp-rooting the snapshot objects during the build: ensure Result
and the boxed Obj (result of ToObject) are placed on the GC rootset before
entering the loop and that each newly created EntryObj and its key/value are
rooted (or created within a TempRoot scope) until they are safely stored into
Result.Elements; update CreateForInEntriesArray to push/pop these temporaries
(or use the unit's TempRoot helper) around allocations so the GC cannot collect
them mid-construction.

In `@source/units/Goccia.Parser.pas`:
- Around line 4466-4495: The parser currently fails when a for...in target is a
private member because ConvertToPattern lacks a branch for
TGocciaPrivateMemberExpression; update ConvertToPattern to recognize
TGocciaPrivateMemberExpression and return a valid assignment/pattern node (or
wrap it as a simple assignment target) instead of raising "Invalid destructuring
target", and ensure any pattern validation paths (used by ConvertToPattern and
the for-in handling in the for/in parsing code that calls AssignmentTarget :=
ConvertToPattern(TargetExpr)) allow private-member targets; also verify
TGocciaForInStatement creation (and any downstream destructuring/assignment
logic) accepts the resulting target type so constructs like for (this.#x in obj)
{} parse and compile without error.

In `@source/units/Goccia.Values.ObjectValue.pas`:
- Around line 1116-1134: The traversal over Prototype in the loop starting with
Current := Self needs the same MAX_PROTOTYPE_CHAIN_DEPTH guard used elsewhere to
detect cycles or excessive depth; add a depth counter (e.g., Depth := 0) that
increments each iteration and if Depth >= MAX_PROTOTYPE_CHAIN_DEPTH stop the
loop and fail fast (raise the same exception or error used elsewhere in this
unit) to avoid infinite loops when Prototype is cyclic. Apply this guard inside
the while Assigned(Current) loop before calling
Current.GetAllPropertyNames/GetOwnPropertyDescriptor and reference Current,
Prototype, MAX_PROTOTYPE_CHAIN_DEPTH, Visited, and Names when implementing the
check so it matches the existing pattern in the unit.

---

Nitpick comments:
In `@tests/language/for-in-loop/control-flow.js`:
- Around line 24-30: Add a small test that verifies the `return` control-flow
path inside a `for...in` loop also preserves per-iteration lexical bindings:
replicate the existing test pattern (the `test("closures capture per-iteration
lexical bindings", ...)` setup with `fns` and a `for (const key in {...})`) but
include a `return` from within the loop on a specific key so the loop exits
early and ensure the pushed closure still captures the correct per-iteration
`key` values for iterations executed before the return; update or add a new test
name to reflect the `return` case so the interpreter and bytecode propagation
for `return` are exercised.

In `@tests/language/statements/unsupported-features.js`:
- Around line 19-31: Add a new test that covers the skipped destructuring-head
path: mirror the existing for-in negative tests but use a binding-pattern in the
loop head (e.g., test name "code after skipped for-in destructuring-head
executes" and a loop like for (const [k] in { a: 1 }) { x = 99; }), assert x
stays 1 after the loop to ensure the binding-pattern path in the parser is
exercised (reference the existing tests "code after skipped for-in loop
executes" and "code after skipped for-in assignment target loop executes" to
match style and expectations).
🪄 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: 296a26c2-24fc-432c-b425-9e5ff6af290f

📥 Commits

Reviewing files that changed from the base of the PR and between 68d2d20 and c12815a.

📒 Files selected for processing (31)
  • README.md
  • docs/build-system.md
  • docs/decision-log.md
  • docs/embedding.md
  • docs/errors.md
  • docs/goals.md
  • docs/language-tables.md
  • docs/language.md
  • docs/test262.md
  • docs/tutorial.md
  • scripts/run_test262_suite.ts
  • scripts/test-cli.ts
  • scripts/test262_compatibility_roadmap.json
  • source/app/Goccia.CLI.Options.pas
  • source/units/Goccia.AST.BindingPatterns.pas
  • source/units/Goccia.AST.Statements.pas
  • source/units/Goccia.Bytecode.OpCodeNames.pas
  • source/units/Goccia.Bytecode.pas
  • source/units/Goccia.Compiler.Statements.pas
  • source/units/Goccia.Compiler.pas
  • source/units/Goccia.Evaluator.pas
  • source/units/Goccia.Parser.pas
  • source/units/Goccia.SourcePipeline.pas
  • source/units/Goccia.VM.pas
  • source/units/Goccia.Values.ObjectValue.pas
  • tests/language/for-in-loop/basic-enumeration.js
  • tests/language/for-in-loop/control-flow.js
  • tests/language/for-in-loop/goccia.json
  • tests/language/for-in-loop/var/goccia.json
  • tests/language/for-in-loop/var/var-shared-binding.js
  • tests/language/statements/unsupported-features.js
💤 Files with no reviewable changes (1)
  • scripts/test262_compatibility_roadmap.json

Comment thread source/units/Goccia.Compiler.Statements.pas
Comment thread source/units/Goccia.Compiler.Statements.pas
Comment thread source/units/Goccia.Evaluator.pas Outdated
Comment thread source/units/Goccia.Evaluator.pas
Comment thread source/units/Goccia.Parser.pas
Comment thread source/units/Goccia.Values.ObjectValue.pas Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation internal Refactoring, CI, tooling, cleanup new feature New feature or request spec compliance Mismatch against official JavaScript/TypeScript specification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant