Skip to content

fix(sandbox): reject host symlinks during seed imports#793

Merged
frostney merged 3 commits into
mainfrom
claude/ecstatic-knuth-8008af
Jun 24, 2026
Merged

fix(sandbox): reject host symlinks during seed imports#793
frostney merged 3 commits into
mainfrom
claude/ecstatic-knuth-8008af

Conversation

@frostney

@frostney frostney commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • GocciaSandboxRunner host seed imports (--seed and --seed-config from) read files through TFileStream, which dereferences symlinks. A symlink inside a seeded directory — or named directly as a seed — copied bytes from outside the requested seed root into the sandbox VFS, contrary to the sandbox-first, reduced-attack-surface posture in VISION.md. The VFS itself deliberately does not support symlinks.
  • Adds a cross-platform HostPathIsSymlink helper to the shared FileUtils unit (POSIX lstat + S_ISLNK; Windows reparse points / junctions via faSymLink) and rejects host symlinks at two seams in GocciaSandboxRunner.dpr: the seed leaf (SeedHostPath) and every descendant of a seeded directory (ImportDirectoryContents). On encounter it fails closed — aborts with exit code 1 and an error naming the path: Seed path is a symlink (not supported): <path>.
  • A trailing separator is stripped before the check, because POSIX lstat follows a final symlink when the path ends in / (so --seed=linkdir/ is rejected just like --seed=linkdir). This bypass was caught by the pre-handoff /code-review pass and is covered by a dedicated regression test.
  • Non-goals (documented in ADR 0071): preserving symlinks as first-class VFS nodes; rejecting symlinks that appear as ancestor components of a host-supplied seed path (indistinguishable from benign system symlinks such as macOS /var/private/var, so rejecting them would refuse ordinary temp paths); and full real-path containment.
  • Windows: the guard uses FileGetAttr + faSymLink (reparse points / junctions). File-symlink tests need elevation on windows-latest, so they are POSIX-guarded; a separate win32-only test seeds a directory junction (a reparse point that needs no elevation) and asserts the same rejection, so the Windows branch is exercised by the cli CI job on windows-latest. macOS validated empirically; Linux uses the same POSIX path.

Closes #786

Testing

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

Details:

  • ./build.pas sandboxrunner + reproduced all four leak vectors → each rejects with exit 1, names the path, and leaks nothing: nested symlink in a seeded dir, direct symlink as --seed, --seed-config from dir with a symlink, and a trailing slash on a symlinked dir. The positive case (normal dir/file seed, including a trailing slash) still imports.
  • bun run scripts/test-cli-apps.ts — all pass, including 5 new GocciaSandboxRunner symlink/junction regressions (4 POSIX-guarded + 1 win32-only junction; 13 SandboxRunner cases total; existing seed tests unchanged).
  • DoD JS suite gate green after merging origin/main: GocciaTestRunner tests and --mode=bytecode both 10,821 passing (100%, no failed tests).
  • ./format.pas --check clean; pre-commit hooks (markdownlint, doc links/symbols, format) green.

Reviewer notes

No tests/*.js was added: this is a CLI host-app security guard with no JS-language API surface, so docs/testing.md routes coverage to scripts/test-cli-apps.ts alongside the existing sandbox seed tests.

GocciaSandboxRunner --seed and --seed-config host imports read files
through TFileStream, which dereferences symlinks, so a symlink inside a
seeded directory (or named directly as a seed) copied bytes from outside
the requested seed root into the sandbox VFS — contrary to the
sandbox-first, reduced-attack-surface posture in VISION.md.

Reject host symlinks at the seed leaf and every descendant of a seeded
directory via a cross-platform HostPathIsSymlink helper in the shared
FileUtils unit (POSIX lstat+S_ISLNK; Windows reparse points/junctions
via faSymLink), failing closed with an error that names the path.
Trailing separators are stripped before the check so a trailing slash
cannot make lstat follow a symlinked leaf. Ancestor symlinks in the
host-supplied path (e.g. macOS /var) and full real-path containment are
documented non-goals.

Adds ADR 0070, a docs/build-system.md note, and POSIX-guarded CLI
regressions covering all four leak vectors.

Closes #786

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

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

Request Review

@coderabbitai

coderabbitai Bot commented Jun 24, 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

Run ID: a4c9f295-eb29-4e5a-890a-76490f2b8f06

📥 Commits

Reviewing files that changed from the base of the PR and between cc3cba3 and ddf08a0.

📒 Files selected for processing (3)
  • docs/adr/0071-reject-symlinks-in-sandbox-seed-imports.md
  • docs/adr/README.md
  • scripts/test-cli-apps.ts
✅ Files skipped from review due to trivial changes (2)
  • docs/adr/README.md
  • docs/adr/0071-reject-symlinks-in-sandbox-seed-imports.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/test-cli-apps.ts

📝 Walkthrough

Walkthrough

Adds a cross-platform symlink check, uses it to reject symlinked host seed inputs in SandboxRunner, and adds regression tests plus ADR/build-system documentation for the rejection policy.

Changes

Symlink rejection in sandbox seed imports

Layer / File(s) Summary
HostPathIsSymlink cross-platform helper
source/shared/FileUtils.pas
Adds BaseUnix conditionally and implements HostPathIsSymlink with fpLStat/fpS_ISLNK on UNIX and FileGetAttr/faSymLink on non-UNIX.
SandboxRunner seed import checks
source/app/GocciaSandboxRunner.dpr
Checks imported host child paths and trims trailing separators from single seed paths before calling HostPathIsSymlink, then raises on symlinked inputs.
Regression tests and documentation
scripts/test-cli-apps.ts, docs/adr/0071-reject-symlinks-in-sandbox-seed-imports.md, docs/build-system.md, docs/adr/README.md
Adds CLI regression tests for symlinked seed inputs, including a Windows junction case, and updates ADR 0071, build-system guidance, and the ADR index.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • frostney/GocciaScript#772: Introduces GocciaSandboxRunner and the seed-import path that this PR now guards with symlink rejection.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: rejecting host symlinks during sandbox seed imports.
Description check ✅ Passed The description follows the template with Summary and Testing sections and includes related issue and test details.
Linked Issues check ✅ Passed The changes implement the requested symlink rejection for --seed and seed-config imports with cross-platform checks and regression tests.
Out of Scope Changes check ✅ Passed All code and doc changes support symlink rejection in sandbox seed imports; no unrelated additions stand out.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Suite Timing

Test Runner (interpreted: 10,821 passed; bytecode: 10,821 passed)
Metric Interpreted Bytecode
Total 10821 10821
Passed 10821 ✅ 10821 ✅
Workers 4 4
Test Duration 16.93s 12.31s
Lex (cumulative) 547.3ms 392.2ms
Parse (cumulative) 396.9ms 288.8ms
Compile (cumulative) 561.5ms
Execute (cumulative) 172.6ms 25.87s
Engine Total (cumulative) 1.12s 27.11s
Lex (avg/worker) 136.8ms 98.1ms
Parse (avg/worker) 99.2ms 72.2ms
Compile (avg/worker) 140.4ms
Execute (avg/worker) 43.1ms 6.47s
Engine Total (avg/worker) 279.2ms 6.78s

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 271.71 MiB 269.47 MiB
GC Peak Live 298.33 MiB 297.77 MiB
GC Allocated During Run 433.98 MiB 425.69 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 188 188
GC Collected Objects 1,283,192 1,254,807
Heap Start Allocated 179.2 KiB 179.2 KiB
Heap End Allocated 3.65 MiB 3.65 MiB
Heap Delta Allocated 3.47 MiB 3.47 MiB
Heap Delta Free 1.65 MiB 1.65 MiB
Benchmarks (interpreted: 430; bytecode: 430)
Metric Interpreted Bytecode
Total 430 430
Workers 4 4
Duration 2.80min 2.81min

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.08 MiB 6.08 MiB
GC Peak Live 88.71 MiB 88.01 MiB
GC Allocated During Run 13.79 GiB 10.39 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 3,636 3,562
GC Collected Objects 217,377,367 232,488,029
Heap Start Allocated 3.35 MiB 3.35 MiB
Heap End Allocated 3.35 MiB 3.35 MiB
Heap Delta Allocated 128 B 128 B

Measured on ubuntu-latest x64.

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

430 benchmarks

Interpreted: 🟢 31 improved · 🔴 32 regressed · 367 unchanged · avg -0.0%
Bytecode: 🟢 7 improved · 🔴 371 regressed · 52 unchanged · avg -21.1%

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

Deterministic profile diff

Deterministic profile diff: no significant changes.

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

@frostney frostney marked this pull request as ready for review June 24, 2026 18:24
@coderabbitai coderabbitai Bot added bug Something isn't working documentation Improvements or additions to documentation labels Jun 24, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@scripts/test-cli-apps.ts`:
- Line 2745: Add Windows regression coverage for the new symlink policy by
updating the symlink-related tests in test-cli-apps.ts so the win32 branch is
exercised instead of fully skipped. Keep the existing non-Windows assertions,
and add at least one Windows-specific case using a junction created with
symlinkSync(..., "junction") that verifies the same rejection behavior as the
other symlink tests. Use the existing test blocks around the affected symlink
policy checks to locate the right place and ensure the new Windows case covers
the same security contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1d09da77-4967-4209-bc05-988ca6b587e1

📥 Commits

Reviewing files that changed from the base of the PR and between 5319ade and cc3cba3.

📒 Files selected for processing (6)
  • docs/adr/0070-reject-symlinks-in-sandbox-seed-imports.md
  • docs/adr/README.md
  • docs/build-system.md
  • scripts/test-cli-apps.ts
  • source/app/GocciaSandboxRunner.dpr
  • source/shared/FileUtils.pas

Comment thread scripts/test-cli-apps.ts
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

test262 Conformance

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

Category Run Passed Δ Pass Failed Pass-rate Δ Rate
built-ins 23,643 22,519 +1 1,124 95.2% ±0pp
harness 116 116 ±0 0 100.0% ±0pp
intl402 3,341 3,332 -2 9 99.7% -0.1pp
language 23,711 23,706 +34 5 100.0% +0.1pp
staging 1,482 1,103 ±0 377 74.4% ±0pp
total 52,293 50,776 +33 1,515 97.1% +0.1pp

Areas closest to 100%

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

Newly failing (2):

  • intl402/Temporal/ZonedDateTime/prototype/hoursInDay/dst-less-than-hour.js
  • intl402/Temporal/ZonedDateTime/prototype/hoursInDay/same-date-starts-twice.js

Newly passing (35):

  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js
  • language/expressions/call/tco-call-args.js
  • language/expressions/call/tco-member-args.js
  • language/expressions/call/tco-non-eval-function-dynamic.js
  • language/expressions/call/tco-non-eval-function.js
  • language/expressions/call/tco-non-eval-global.js
  • language/expressions/call/tco-non-eval-with.js
  • language/expressions/coalesce/tco-pos-null.js
  • language/expressions/coalesce/tco-pos-undefined.js
  • language/expressions/comma/tco-final.js
  • language/expressions/conditional/tco-cond.js
  • language/expressions/conditional/tco-pos.js
  • language/expressions/logical-and/tco-right.js
  • language/expressions/logical-or/tco-right.js
  • language/expressions/tagged-template/tco-call.js
  • language/expressions/tagged-template/tco-member.js
  • language/expressions/tco-pos.js
  • language/statements/block/tco-stmt-list.js
  • language/statements/block/tco-stmt.js
  • language/statements/do-while/tco-body.js
  • language/statements/for/tco-const-body.js
  • language/statements/for/tco-let-body.js
  • language/statements/for/tco-lhs-body.js
  • language/statements/for/tco-var-body.js
  • language/statements/if/tco-else-body.js
  • language/statements/if/tco-if-body.js
  • language/statements/labeled/tco.js
  • language/statements/return/tco.js
  • language/statements/switch/tco-case-body-dflt.js
  • language/statements/switch/tco-case-body.js
  • language/statements/switch/tco-dftl-body.js
  • language/statements/try/tco-catch-finally.js
  • language/statements/try/tco-catch.js
  • language/statements/try/tco-finally.js
  • language/statements/while/tco-body.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 24, 2026 21:02
The four POSIX symlink seed tests skip on win32 (file symlinks need
elevation on CI runners), leaving the Windows branch of the guard
unverified. Add a win32-only case that seeds a directory junction
(a reparse point that needs no elevation) and asserts the same
rejection and no-leak contract, exercising the FileGetAttr + faSymLink
path on the windows-latest CI runners.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@frostney frostney merged commit d2259cb into main Jun 24, 2026
13 of 14 checks passed
@frostney frostney deleted the claude/ecstatic-knuth-8008af branch June 24, 2026 21:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reject or preserve symlinks during sandbox seed imports

1 participant