Skip to content

Add Iterator.concat support#253

Merged
frostney merged 3 commits into
mainfrom
t3code/iterator-concat
Apr 10, 2026
Merged

Add Iterator.concat support#253
frostney merged 3 commits into
mainfrom
t3code/iterator-concat

Conversation

@frostney
Copy link
Copy Markdown
Owner

Summary

  • Adds Iterator.concat(...items) as a new static iterator helper for lazy concatenation of multiple iterables.
  • Implements a dedicated concat iterator value in Pascal, including iterator opening, cleanup, GC marking, and direct next() support.
  • Expands JavaScript coverage with happy-path, laziness, validation, and interop tests for arrays, sets, maps, strings, and user-defined iterables.
  • Updates iterator documentation and adds benchmark coverage for concat workloads.

Testing

  • Not run (changes were reviewed from the patch only).
  • Expected verification: ./build.pas testrunner && ./build/TestRunner tests
  • Expected verification for iterator-specific coverage: ./build/TestRunner tests/built-ins/Iterator/concat.js
  • Expected verification for benchmark sanity: ./build/BenchmarkRunner benchmarks/iterators.js

- Implement lazy `Iterator.concat(...items)` for iterable sequencing
- Add JS coverage, benchmark cases, and built-in docs
- Register the new iterator concat value in the runtime
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 10, 2026

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: 28608f4e-23ee-41ac-9d33-c8fe288fa3da

📥 Commits

Reviewing files that changed from the base of the PR and between e3d16c2 and 2dabd0f.

📒 Files selected for processing (1)
  • units/Goccia.Values.Iterator.Concat.pas

📝 Walkthrough

Walkthrough

Implements Iterator.concat: adds a new Pascal unit and iterator class for lazy concatenation, registers a static Iterator.concat entrypoint, and adds tests, docs, and benchmarks. No existing runtime behavior was removed.

Changes

Cohort / File(s) Summary
Implementation
units/Goccia.Values.Iterator.Concat.pas, units/Goccia.Values.IteratorValue.pas
New TGocciaConcatIteratorValue and record for iterable entries; lazy opening of inner iterators, error-safe closing, GC marking; Iterator.concat static method collects/validates args (strings vs objects), resolves Symbol.iterator, and returns the concat iterator.
Tests
tests/built-ins/Iterator/concat.js
New comprehensive test suite for arrays, Sets, Maps, strings, mixed iterables, zero/single/multiple args, laziness, protocol compliance, chaining, argument validation, early termination, repeated next() behavior, and large counts.
Documentation
docs/built-ins.md
Added Iterator.Concat.pas to the Iterator section, changed “Static method” → “Static methods”, and documented Iterator.concat(...items) including upfront iterable validation and lazy semantics.
Benchmarks
benchmarks/iterators.js
Added Iterator.concat benchmark suite covering array/Set/string inputs, varying counts, and composition chains (filter/map/take + toArray).

Sequence Diagram

sequenceDiagram
    participant Client as Client Code
    participant Host as Iterator.concat
    participant ConcatIter as TGocciaConcatIteratorValue
    participant InnerIter as Inner Iterator
    participant Source as Source Iterable

    Client->>Host: call concat(item1, item2, ...)
    Host->>Host: validate args, resolve Symbol.iterator / strings
    Host->>ConcatIter: Create(iterables)
    Host-->>Client: return ConcatIter (iterator)

    Client->>ConcatIter: next()
    ConcatIter->>ConcatIter: if no active inner -> OpenNextIterator()
    ConcatIter->>Source: lazily obtain inner iterator
    ConcatIter->>InnerIter: next()
    InnerIter-->>ConcatIter: {value, done}
    alt done = false
        ConcatIter-->>Client: {value, done: false}
    else done = true
        ConcatIter->>ConcatIter: Close active inner, advance to next source or finish
        opt next source exists
            ConcatIter->>Source: open next inner iterator (lazily)
            ConcatIter->>InnerIter: next()
            InnerIter-->>ConcatIter: {value, done}
            ConcatIter-->>Client: {value/finished}
        end
        alt no sources left
            ConcatIter-->>Client: {value: undefined, done: true}
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Add iterators #20: Introduces the iterator framework and prototype methods that Iterator.concat extends; directly related to iterator value registration and patterns.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change—adding Iterator.concat support—and is concise and specific enough for a teammate to understand the primary contribution.
Description check ✅ Passed The description covers the change summary, implementation details, and testing approach; however, it does not complete the template checklist items despite mentioning expected verification commands.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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

@coderabbitai coderabbitai Bot added the new feature New feature or request label Apr 10, 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.

🧹 Nitpick comments (1)
units/Goccia.Values.Iterator.Concat.pas (1)

189-194: Consider nilling FCurrentIterator after Close for idempotency.

If Close is called twice, FCurrentIterator.Close will be invoked twice. While most iterator Close implementations are tolerant of this, setting FCurrentIterator := nil after closing would make the behavior more robust.

♻️ Optional fix for Close idempotency
 procedure TGocciaConcatIteratorValue.Close;
 begin
   inherited;
   if Assigned(FCurrentIterator) then
+  begin
     FCurrentIterator.Close;
+    FCurrentIterator := nil;
+  end;
 end;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@units/Goccia.Values.Iterator.Concat.pas` around lines 189 - 194, The Close
method of TGocciaConcatIteratorValue should be made idempotent by nulling
FCurrentIterator after closing it; update TGocciaConcatIteratorValue.Close to
check Assigned(FCurrentIterator), call FCurrentIterator.Close and then set
FCurrentIterator := nil so subsequent Close calls won't attempt to close the
same iterator again.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@units/Goccia.Values.Iterator.Concat.pas`:
- Around line 189-194: The Close method of TGocciaConcatIteratorValue should be
made idempotent by nulling FCurrentIterator after closing it; update
TGocciaConcatIteratorValue.Close to check Assigned(FCurrentIterator), call
FCurrentIterator.Close and then set FCurrentIterator := nil so subsequent Close
calls won't attempt to close the same iterator again.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 30d8ee6c-c811-44b6-9d8c-878656d35194

📥 Commits

Reviewing files that changed from the base of the PR and between c3d76f9 and 55991a3.

📒 Files selected for processing (5)
  • benchmarks/iterators.js
  • docs/built-ins.md
  • tests/built-ins/Iterator/concat.js
  • units/Goccia.Values.Iterator.Concat.pas
  • units/Goccia.Values.IteratorValue.pas

@frostney frostney added the spec compliance Mismatch against official JavaScript/TypeScript specification label Apr 10, 2026
- Nil out the current iterator after closing it
- Avoids retaining a stale iterator reference in concat iteration
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 10, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 4173 4173
Tests Passed 4132 ✅ 4173 ✅
Tests Skipped 41 0
Tests Test Duration 280.5ms 258.9ms
Tests Lex 76.9ms 52.2ms
Tests Parse 100.2ms 106.1ms
Tests Compile 60.2ms
Tests Execute 293.3ms 286.0ms
Tests Engine Total 470.4ms 504.5ms
Benchmarks Total 281 281
Benchmarks Duration 7.80min 7.16min

Measured on ubuntu-latest x64.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 10, 2026

Benchmark Results

281 benchmarks

Interpreted: 🟢 237 improved · 🔴 9 regressed · 🆕 7 new · 28 unchanged · avg +7.3%
Bytecode: 🟢 154 improved · 🔴 22 regressed · 🆕 7 new · 98 unchanged · avg +3.1%

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

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
units/Goccia.Values.Iterator.Concat.pas (1)

67-68: Use the repo’s ES spec annotation format consistently.

These comments are helpful, but the project requires // ESYYYY §X.Y.Z SpecMethodName(...) immediately above spec-driven implementations. Please convert these TC39 Iterator Sequencing comments and add the missing annotations for the other spec-facing methods in this unit. As per coding guidelines, "When implementing ECMAScript-specified behavior, annotate each function or method with a comment referencing the relevant spec section using format // ESYYYY §X.Y.Z SpecMethodName(specParams)."

Also applies to: 107-108, 146-147

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@units/Goccia.Values.Iterator.Concat.pas` around lines 67 - 68, Replace the
informal "TC39 Iterator Sequencing" comments with the project's ES spec
annotation format directly above each spec-driven implementation: use lines like
"// ES2020 §7.4.XX IteratorSequencing(OpenNextIterator)" (choose the correct ES
year and section number for the referenced behavior) immediately above
TGocciaConcatIteratorValue.OpenNextIterator; likewise add the same ESYYYY §X.Y.Z
SpecMethodName(params) style annotations above the other spec-facing methods in
this unit (the methods around the other reported spots, e.g., the functions at
the other comment locations and any iterator-related methods) so every
ECMAScript-implemented function (e.g.,
TGocciaConcatIteratorValue.OpenNextIterator and the other iterator methods) has
a single ES spec comment with the proper section and method signature.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@units/Goccia.Values.Iterator.Concat.pas`:
- Around line 137-142: When OpenNextIterator can raise, ensure the concat helper
is closed the same way as when the active inner iterator throws: in DirectNext,
wrap the OpenNextIterator call so that if it raises you set FDone := True before
re-raising (or returning the abrupt CreateIteratorResult), mirroring the
existing pattern used when the inner iterator throws; update the logic around
OpenNextIterator and the DirectNext method to set FDone and
return/CreateIteratorResult(TGocciaUndefinedLiteralValue.UndefinedValue, True)
on that error path so subsequent next() calls do not retry the failing iterable.
- Around line 84-88: The code currently hard-casts
FIterables[FCurrentIndex].IteratorMethod to TGocciaFunctionBase and calls .Call,
which fails for non-TGocciaFunctionBase callables; instead invoke the iterator
through the generic callable invocation path used elsewhere: keep creating
TGocciaArgumentsCollection, then obtain the callable from
FIterables[FCurrentIndex].IteratorMethod (respecting its IsCallable contract)
and call it via the common generic call helper/function used in other files (the
same mechanism that accepts any callable value), passing CallArgs and
FIterables[FCurrentIndex].Iterable; update the call site in Iterator.concat to
use that generic-call helper rather than TGocciaFunctionBase(...) so all
callable types are supported.

---

Nitpick comments:
In `@units/Goccia.Values.Iterator.Concat.pas`:
- Around line 67-68: Replace the informal "TC39 Iterator Sequencing" comments
with the project's ES spec annotation format directly above each spec-driven
implementation: use lines like "// ES2020 §7.4.XX
IteratorSequencing(OpenNextIterator)" (choose the correct ES year and section
number for the referenced behavior) immediately above
TGocciaConcatIteratorValue.OpenNextIterator; likewise add the same ESYYYY §X.Y.Z
SpecMethodName(params) style annotations above the other spec-facing methods in
this unit (the methods around the other reported spots, e.g., the functions at
the other comment locations and any iterator-related methods) so every
ECMAScript-implemented function (e.g.,
TGocciaConcatIteratorValue.OpenNextIterator and the other iterator methods) has
a single ES spec comment with the proper section and method signature.
🪄 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: 8f280b6d-6d45-47d5-b3d4-d0d8c0c03afa

📥 Commits

Reviewing files that changed from the base of the PR and between 55991a3 and e3d16c2.

📒 Files selected for processing (1)
  • units/Goccia.Values.Iterator.Concat.pas

Comment thread units/Goccia.Values.Iterator.Concat.pas
Comment thread units/Goccia.Values.Iterator.Concat.pas Outdated
- Update Iterator.concat spec annotations
- Mark concat iterators done when opening the next iterator fails
- Preserve failure cleanup in both next variants
@frostney frostney merged commit c948550 into main Apr 10, 2026
9 checks passed
@frostney frostney deleted the t3code/iterator-concat branch April 10, 2026 12:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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