Skip to content

perf(json): make deeply nested JSON.stringify O(depth^2)#887

Merged
frostney merged 3 commits into
mainfrom
claude/sad-bose-758787
Jun 27, 2026
Merged

perf(json): make deeply nested JSON.stringify O(depth^2)#887
frostney merged 3 commits into
mainfrom
claude/sad-bose-758787

Conversation

@frostney

@frostney frostney commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Summary

JSON.stringify pretty-printing of deeply nested values was O(depth³) from two independent terms. This PR fixes both, bringing deep pretty-print to O(depth²) — the unavoidable size of the indentation that must appear in the output.

  1. Indent construction. MakeIndent built the indent with Result := Result + FGap in a loop (O(level²) per call, called per node). Replaced with DupeString(FGap, ALevel) — a single SetLength+Move pass (O(level)).
  2. Result assembly. Each nesting level rebuilt its serialized string via SB.ToString and the parent re-appended it, re-copying the deepest content once per ancestor level. Replaced by threading one shared TStringBuffer through the recursion (WriteValue/WriteObject/WriteArray) so every value is written once and the root calls ToString once.
  • Byte-identical output — ES2026 §25.5.4.5/§25.5.4.6 define the indent at depth d as the gap repeated d times; framing is reproduced incrementally (deferred opening newline, JSON5 trailing comma, empty {}/[]) with no output change.
  • Removed the now-dead private StringifyValue.
  • The assembly rewrite also fixes a latent traversal-stack leak: LengthOfArrayLike now runs inside the try/finally, so a throwing .length coercion no longer leaks a stack entry.
  • Constraints honored: byte-identical across JSON & JSON5, gap & no-gap, replacer functions, toJSON, RawJSON, and circular-reference detection; the stringifier's re-entrancy (FGap/stack save-restore) is preserved.

Closes #811

Testing

  • Verified no regressions and confirmed the new feature or bugfix in end-to-end JavaScript/TypeScript tests
  • Updated documentation — N/A (internal perf refactor; no behavior, API, or language-surface change)
  • Optional: Verified no regressions and confirmed the new feature or bugfix in native Pascal tests — N/A (JSON built-in only; no AST/scope/evaluator/value-type change)
  • Optional: Verified no benchmark regressions or confirmed benchmark coverage for the change

Details:

  • Full suite 10956/10956 passing in both interpreted and bytecode modes.

  • ./format.pas --check: 370 files, all formatted correctly.

  • Byte-identical cross-check: the new framing tests pass against both the pre-rewrite and post-rewrite code (old behavior == new behavior).

  • New regression tests: deep nested object/array per-level indentation, multi-character gap, depth-30 indent-width scaling, deep no-gap object/array, interleaved object/array, and a deep JSON5 pretty-print (trailing comma per level). New depth-50 object/array and depth-200 object indent benchmarks; all execute.

  • Performance (clean --prod A/B, depth 120/240/480, 40 reps, min of 5):

    depth indent-only (perf(json): JSON.stringify pretty-print indent is O(depth^2) #811) + buffer (this PR) speedup
    120 15.3 ms 7.3 ms 2.1×
    240 74.1 ms 19.3 ms 3.8×
    480 583.4 ms 62.0 ms 9.4×

    Per-doubling scaling falls from ~8× (O(depth³)) to ~3× (O(depth²)).

  • Code review: /code-review (4 independent finder passes) — no defects.

MakeIndent built the pretty-print indent with `Result := Result + FGap`
in a loop (O(level^2) per call) and was called twice per object/array
node, so deeply nested values spent O(depth^3) building indentation.
Replace the accumulator loop with DupeString(FGap, ALevel), a single
SetLength+Move pass (O(level)). Output is byte-identical (ES2026
§25.5.4.5/§25.5.4.6: the indent at depth d is the gap repeated d times),
and DupeString returns '' for level <= 0 and for an empty gap, so the
previous guards are no longer needed.

Add exact-output regression tests (deep object, deep array, multi-char
gap, depth-30 per-level indent width) and depth-50 indent benchmarks for
both object and array nesting.

Closes #811

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
gocciascript-homepage Ignored Ignored Preview Jun 27, 2026 4:38pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d97eb294-aa72-443b-944b-f7b5aef1e042

📥 Commits

Reviewing files that changed from the base of the PR and between 2398f2f and 5914f61.

📒 Files selected for processing (4)
  • benchmarks/json.js
  • source/units/Goccia.JSON.pas
  • tests/built-ins/JSON/stringify.js
  • tests/built-ins/JSON5/stringify.js

📝 Walkthrough

Walkthrough

Refactors TGocciaJSONStringifier in Goccia.JSON.pas from recursive string-returning methods to TStringBuffer-based writer procedures, fixing an O(depth²) MakeIndent via DupeString. Adds deep-nesting correctness tests for JSON.stringify and JSON5.stringify, and three new benchmarks for deep nesting.

JSON Stringify Buffered Writer Refactor

Layer / File(s) Summary
Interface and dependency updates
source/units/Goccia.JSON.pas
StringBuffer moved to interface uses, StrUtils added to implementation uses, and private methods changed from string-returning (StringifyPreparedValue, StringifyObject, StringifyArray) to TStringBuffer-writer procedures (WriteValue, WriteObject, WriteArray).
Buffered writers and MakeIndent fix
source/units/Goccia.JSON.pas
MakeIndent reimplemented with DupeString(FGap, ALevel). Stringify allocates a TStringBuffer and calls WriteValue. WriteValue, WriteObject, and WriteArray implement all serialization logic writing into the buffer with indentation.
Deep-nesting tests and benchmarks
tests/built-ins/JSON/stringify.js, tests/built-ins/JSON5/stringify.js, benchmarks/json.js
New JSON.stringify tests cover deep object/array indentation with numeric and string space, no-gap compaction, and mixed structures. A JSON5.stringify test checks trailing commas in deep nesting. Three benchmark suites measure 50-level object, 50-level array, and 200-level object stringify.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • frostney/GocciaScript#756: Modifies the same TGocciaJSONStringifier serialization pipeline including StringifyPreparedValue logic that this PR replaces with the buffered writer.
  • frostney/GocciaScript#758: Changes TGocciaJSONStringifier.Stringify root handling and array traversal semantics in the same core stringify entry point refactored here.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the performance fix for deeply nested JSON.stringify pretty-printing.
Description check ✅ Passed The description follows the template with Summary and Testing sections, includes the issue link, and covers key constraints and validation.
Linked Issues check ✅ Passed The PR implements the requested pretty-print indentation fix for #811 by replacing repeated concatenation with DupeString while preserving behavior.
Out of Scope Changes check ✅ Passed The buffer rewrite, tests, and benchmarks are consistent with the stated performance fix and validation goals.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Suite Timing

Test Runner (interpreted: 10,956 passed; bytecode: 10,956 passed)
Metric Interpreted Bytecode
Total 10956 10956
Passed 10956 ✅ 10956 ✅
Workers 4 4
Test Duration 18.63s 18.83s
Lex (cumulative) 482.0ms 521.7ms
Parse (cumulative) 351.3ms 369.4ms
Compile (cumulative) 746.3ms
Execute (cumulative) 156.2ms 44.84s
Engine Total (cumulative) 989.6ms 46.48s
Lex (avg/worker) 120.5ms 130.4ms
Parse (avg/worker) 87.8ms 92.3ms
Compile (avg/worker) 186.6ms
Execute (avg/worker) 39.1ms 11.21s
Engine Total (avg/worker) 247.4ms 11.62s

Memory

GC rows aggregate the main thread plus all worker thread-local GCs. Test runner worker shutdown frees thread-local heaps in bulk; that shutdown reclamation is not counted as GC collections or collected objects.

Metric Interpreted Bytecode
GC Live 282.87 MiB 280.29 MiB
GC Peak Live 345.74 MiB 327.97 MiB
GC Allocated During Run 528.58 MiB 472.86 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 195 195
GC Collected Objects 2,593,727 2,164,801
Heap Start Allocated 181.0 KiB 181.0 KiB
Heap End Allocated 3.65 MiB 3.65 MiB
Heap Delta Allocated 3.48 MiB 3.48 MiB
Heap Delta Free 1.68 MiB 1.68 MiB
Benchmarks (interpreted: 433; bytecode: 433)
Metric Interpreted Bytecode
Total 433 433
Workers 4 4
Duration 2.86min 2.79min

Memory

GC rows aggregate the main thread plus all worker thread-local GCs. Benchmark runner performs explicit between-file collections, so collection and collected-object counts can be much higher than the test runner.

Metric Interpreted Bytecode
GC Live 6.09 MiB 6.09 MiB
GC Peak Live 113.55 MiB 77.06 MiB
GC Allocated During Run 15.01 GiB 10.08 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 3,592 3,572
GC Collected Objects 233,226,624 226,811,665
Heap Start Allocated 3.36 MiB 3.36 MiB
Heap End Allocated 3.36 MiB 3.36 MiB
Heap Delta Allocated 128 B 128 B

Measured on ubuntu-latest x64.

@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

433 benchmarks · PR vs same-runner main build

Interpreted: 🟢 23 improved · 🔴 35 regressed · 375 unchanged · avg +1.3%
Bytecode: 🟢 40 improved · 🔴 44 regressed · 349 unchanged · avg +2.1%

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

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

Deterministic profile diff

Deterministic profile diff: no significant changes.

Measured on ubuntu-latest x64. Each PR run also builds the main base and benchmarks it back-to-back on the same runner after a warm-up discard, so the ranges compare two runs measured under the same conditions; overlapping min/max ranges are treated as unchanged noise. Percentage deltas are secondary context. See docs/adr/0076.

@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

test262 Conformance

Category Run Passed Δ Pass Failed Pass-rate Δ Rate
built-ins 23,643 22,609 +1 1,034 95.6% ±0pp
harness 116 116 ±0 0 100.0% ±0pp
intl402 3,341 3,334 ±0 7 99.8% ±0pp
language 23,711 23,711 ±0 0 100.0% ±0pp
staging 1,482 1,109 ±0 373 74.8% ±0pp
total 52,293 50,879 +1 1,414 97.3% ±0pp

Areas closest to 100%

Area Pass rate Δ vs main Passing
built-ins/TypedArray 99.9% ±0pp 1,445 / 1,446
intl402/Temporal 99.9% ±0pp 2,026 / 2,029
built-ins/Object 99.7% ±0pp 3,401 / 3,411
Per-test deltas (+1 / -0)

Newly passing (1):

  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js

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

frostney and others added 2 commits June 27, 2026 17:16
The recursive serializer built a result string per object/array level
(SB.ToString) that the parent re-appended into its own buffer, re-copying
the deepest content once per ancestor level — an O(depth^3) term that
dominated deep stringify even after the indent fix in the previous commit.

Thread a single TStringBuffer through the recursion (WriteValue/WriteObject/
WriteArray) so every value is written once; the root calls ToString once.
This drops deep pretty-print from O(depth^3) to O(depth^2) (the unavoidable
indentation-output size): a clean --prod A/B at depth 480 goes 583ms -> 62ms
(~9.4x), per-doubling scaling falls from ~8x to ~3x. Output is byte-identical
across JSON/JSON5, gap/no-gap, replacer, toJSON, RawJSON, and circular
detection. Removes the now-dead StringifyValue.

Add deep no-gap object/array, interleaved object/array, and JSON5 deep
pretty-print regression tests, plus a depth-200 indent benchmark.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@frostney frostney changed the title perf(json): build JSON.stringify pretty-print indent in one pass perf(json): make deeply nested JSON.stringify O(depth^2) Jun 27, 2026
@frostney frostney marked this pull request as ready for review June 27, 2026 17:00
@frostney frostney merged commit 47c7a04 into main Jun 27, 2026
15 checks passed
@frostney frostney deleted the claude/sad-bose-758787 branch June 27, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(json): JSON.stringify pretty-print indent is O(depth^2)

1 participant