Skip to content

Replace VM register arrays with contiguous stack (+28% bytecode throughput)#235

Merged
frostney merged 1 commit into
mainfrom
perf/register-stack
Apr 9, 2026
Merged

Replace VM register arrays with contiguous stack (+28% bytecode throughput)#235
frostney merged 1 commit into
mainfrom
perf/register-stack

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Apr 8, 2026

Summary

  • Replace per-call TGocciaRegisterArray (dynamic array) allocation with a contiguous register stack and PGocciaRegister typed pointer
  • Same pattern for local cell arrays
  • Eliminates all FPC dynamic array refcount management from the bytecode call path

Problem

Profiling the production bytecode VM with macOS sample revealed that FPC's automatic dynamic array refcounting consumed 16.6% of execution time:

FPC runtime function Samples What it does
FPC_DYNARRAY_CLEAR 103 Decrement refcount, free if zero
FPC_DYNARRAY_ASSIGN 93 Copy reference, increment refcount
FPC_DYNARRAY_INCR_REF 43 Increment refcount
FPC_DYNARR_SETLENGTH 52 Allocate/resize array
FPC_FINALIZE 57 Finalize managed types
Total 348 / 1755 16.6% of CPU time

Every function call saved/restored FRegisters (a dynamic array), triggering 4+ refcount operations. For fib(20) with 21,891 calls, that's ~87,000 refcount operations.

Solution

Replace the per-call dynamic array with a single growing stack:

FRegisterStack: TGocciaRegisterArray;  // one contiguous array
FRegisterBase: Integer;                 // current frame's start index
FRegisters: PGocciaRegister;           // typed pointer = @FRegisterStack[FRegisterBase]
FRegisterCount: Integer;               // current frame's capacity

Save/restore becomes integer index copies (zero refcounting):

// Save: just copy integers
SavedRegisterBase := FRegisterBase;
SavedRegisterCount := FRegisterCount;

// Restore: copy integers back, recompute pointer
FRegisterBase := SavedRegisterBase;
FRegisterCount := SavedRegisterCount;
FRegisters := @FRegisterStack[FRegisterBase];

All 507 FRegisters[X] access sites in the dispatch loop work unchanged — pointer indexing has the same syntax as array indexing in FPC.

Measurements (production build, macOS AArch64)

Metric Before After Change
fib(20) per-call (bytecode, median of 10) 405 ns 291 ns -28%
fib(25) × 20 total execution 2100 ms 1605 ms -24%

Profiler confirmation — all dynamic array functions eliminated:

Function Before After
FPC_DYNARRAY_CLEAR 103 samples 0
FPC_DYNARRAY_ASSIGN 93 samples 0
FPC_DYNARRAY_INCR_REF 43 samples 0
FPC_DYNARR_SETLENGTH 52 samples 0
FPC_FINALIZE 57 samples 0

Test plan

  • All Pascal unit tests pass
  • All JS tests pass in bytecode mode (3815/3827, 12 pre-existing FFI/ASI failures)
  • All JS tests pass in interpreted mode
  • Closure capture correctness verified (counter pattern, for-of captured variables)
  • Deep recursion verified (5000 levels)
  • Exception handling verified (null access, throw, nested try/catch)

🤖 Generated with Claude Code

Replace TGocciaRegisterArray (dynamic array) with a contiguous stack and
typed pointer (PGocciaRegister) for the VM register file. Same for local
cells. This eliminates FPC's automatic refcount management
(FPC_DYNARRAY_ASSIGN, FPC_DYNARRAY_CLEAR, FPC_DYNARRAY_INCR_REF,
FPC_DYNARR_SETLENGTH, FPC_FINALIZE) which profiling showed consumed
16.6% of production execution time.

Design:
- FRegisterStack: single growing TGocciaRegisterArray (initial 4096 slots)
- FRegisterBase: integer index into the stack for the current frame
- FRegisters: PGocciaRegister pointer (= @FRegisterStack[FRegisterBase])
- Save/restore saves integer indices, not array references — no refcounting
- All 507 FRegisters[X] access sites work unchanged (pointer indexing)
- Same pattern for FLocalCellStack / FLocalCells

Measured impact (production build, fib(20) bytecode):
- Before: 405 ns/call (median of 10 runs)
- After:  291 ns/call (median of 10 runs)
- Improvement: 28%

Profiler confirmation (macOS sample tool):
- FPC_DYNARRAY_CLEAR:     103 samples → 0
- FPC_DYNARRAY_ASSIGN:     93 samples → 0
- FPC_DYNARRAY_INCR_REF:   43 samples → 0
- FPC_DYNARR_SETLENGTH:    52 samples → 0
- FPC_FINALIZE:             57 samples → 0
- Total execution: 2100ms → 1605ms (-24%)

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

coderabbitai Bot commented Apr 8, 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: 99576468-29bc-484e-bc4f-5b56331bbe81

📥 Commits

Reviewing files that changed from the base of the PR and between edaf928 and 2cc42cb.

📒 Files selected for processing (2)
  • units/Goccia.VM.Registers.pas
  • units/Goccia.VM.pas

📝 Walkthrough

Walkthrough

The PR refactors register and local cell management in the VM to use preallocated growable stacks with base/count offset tracking and pointer windows instead of dynamic arrays, with pointer arithmetic support enabled via compiler directives.

Changes

Cohort / File(s) Summary
Register/Cell Memory Management Refactoring
units/Goccia.VM.Registers.pas, units/Goccia.VM.pas
Added {$POINTERMATH ON} directives and pointer type aliases (PGocciaRegister, PGocciaBytecodeCell). Replaced FRegisters/FLocalCells array fields with FRegisterStack/FLocalCellStack plus base/count tracking. Converted AcquireRegisters/AcquireLocalCells from array-returning functions to base/count-setting procedures; removed corresponding release functions. Updated EnsureRegisterCapacity/EnsureLocalCapacity to grow stacks with selective zero-fill. Modified bounds checking and pointer dereferencing throughout opcodes, closure execution, and upvalue closing to use base-relative windows.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

implement-feedback

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: replacing VM register arrays with a contiguous stack and documenting the performance improvement (+28% throughput).
Description check ✅ Passed The description is comprehensive and well-structured, covering the problem, solution, measurements, and test plan. All major template sections are addressed with detailed information.
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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

Benchmark Results

274 benchmarks

Interpreted: 🟢 21 improved · 🔴 134 regressed · 119 unchanged · avg -1.7%
Bytecode: 🟢 108 improved · 🔴 104 regressed · 62 unchanged · avg +2.0%

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

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 Apr 8, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 3891 3891
Tests Passed 3850 ✅ 3891 ✅
Tests Skipped 41 0
Tests Test Duration 271.9ms 246.6ms
Tests Lex 75.2ms 51.1ms
Tests Parse 95.3ms 98.6ms
Tests Compile 57.1ms
Tests Execute 288.4ms 275.4ms
Tests Engine Total 458.9ms 482.3ms
Benchmarks Total 274 274
Benchmarks Duration 7.42min 6.25min

Measured on ubuntu-latest x64.

@frostney frostney merged commit 363b454 into main Apr 9, 2026
9 checks passed
@frostney frostney deleted the perf/register-stack branch April 9, 2026 06:40
@frostney frostney added the performance Performance improvement label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant