Skip to content

refactor(engine): migrate per-thread cache clears into the cleanup registry (#893)#903

Merged
frostney merged 4 commits into
mainfrom
claude/jovial-lewin-4ed28a
Jun 29, 2026
Merged

refactor(engine): migrate per-thread cache clears into the cleanup registry (#893)#903
frostney merged 4 commits into
mainfrom
claude/jovial-lewin-4ed28a

Conversation

@frostney

@frostney frostney commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

Completes the thread-cleanup migration that ADR 0078 deferred to this issue. #891 added Goccia.ThreadCleanupRegistry for the ~64 member-definition threadvars but left seven per-thread cache/memo clears as explicit calls inside Goccia.Threading.ShutdownThreadRuntime (ClearImportMetaCache, ShutdownAtomicsWaitersForCurrentThread, ClearDisposableStackSlotMap, ClearSemverHosts, ClearTimeZoneCache, ClearRegExpInputMemo, ClearAsciiMemo) — two cleanup idioms on the worker-exit path, and a uses-clause coupling Goccia.Threading to seven cache-owning units.

Each unit now registers its clear with the registry from its own initialization (the established pattern), and ShutdownThreadRuntime drops the seven explicit calls — keeping only the RunThreadvarCleanups drain before the ordered GC / CallStack / MicrotaskQueue shutdowns (so ClearImportMetaCache's GC unpin still runs while the collector is alive). Goccia.Threading no longer uses any of the seven units.

Key implementation decisions (also recorded in ADR 0083):

  • Atomics is a shared, lock-guarded global, not a managed threadvar. The per-thread ShutdownAtomicsWaitersForCurrentThread is registered for the worker path; the unit's own finalization keeps the all-threads ShutdownAtomicsWaiters + lock teardown for the main thread (the per-thread/all-threads distinction the issue calls out). Because the registry finalizes after this unit, its main-thread drain would call the per-thread proc after the lock is destroyed — a pre-lock if not Assigned(GAtomicsWaiters) guard makes that a safe no-op. The registry's callback contract is broadened to cover "a thread's own entries in a shared lock-guarded structure."
  • TextSemantics is generic source/shared/ infrastructure with no engine dependency. To keep it engine-free, its is-ASCII memo clear is registered from Goccia.RegExp.VM (every engine binary links the regex VM) for the worker path, and its own main-thread finalization is retained — the JSON/numeric/config tools and TextSemantics.Test link it without the regex VM and would otherwise leak the memo on the main thread.
  • ImportMeta keeps ClearImportMetaCache exported (the engine also calls it directly during teardown).

Non-goals: no runtime behaviour or conformance change — this is the cleanliness/embeddability follow-up, not a perf change. The symbol-registry threadvar audit (#892) stays a separate follow-up.

A new Goccia.ThreadCleanupLeak.Test gate pins each of the seven registrations via a small IsThreadvarCleanupRegistered helper, so a dropped RegisterThreadvarCleanup fails loudly. The branch is merged up to origin/main; the ADR was renumbered to 0083 after #899/#902 landed ADRs 0080–0082 concurrently.

Closes #893

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

Verification (clean build, post-merge with origin/main):

  • ./build.pas testrunner && ./build/GocciaTestRunner tests11046/11046 (AST)
  • ./build/GocciaTestRunner tests --mode=bytecode11046/11046 (bytecode)
  • All 41 Pascal unit tests pass, including the named gates Goccia.ThreadCleanupLeak.Test (with the new TestMigratedCacheCleanupsAreRegistered) and Goccia.Threading.Test (ShutdownThreadRuntime drains the registry once per worker), plus the shared-consumer tests TextSemantics.Test / JSONParser.Test / NumericText.Test / CLI.ConfigFile.Test.
  • ./format.pas --check → clean (376 files).

Not benchmarked: no hot-path or allocation change (teardown-only plumbing).

frostney and others added 2 commits June 28, 2026 17:56
…gistry (#893)

Follow-up to #885/#891. PR #891 added Goccia.ThreadCleanupRegistry for the ~64
member-definition threadvars but left seven per-thread cache/memo clears as
explicit calls inside Goccia.Threading.ShutdownThreadRuntime, leaving two
cleanup idioms coexisting on the worker-exit path and coupling Goccia.Threading
to seven cache-owning units.

Each unit now registers its clear with the registry from its own initialization
(matching the established pattern), and ShutdownThreadRuntime drops the explicit
calls — keeping only the RunThreadvarCleanups drain before the ordered
GC/CallStack/MicrotaskQueue shutdowns. Goccia.Threading no longer uses any of
the seven units.

- Atomics: register the per-thread ShutdownAtomicsWaitersForCurrentThread; keep
  the all-threads ShutdownAtomicsWaiters + lock teardown in the unit
  finalization (per-thread/all-threads distinction preserved); guard the
  per-thread proc against the registry's post-teardown main-thread drain.
- TextSemantics (generic shared infra): register its is-ASCII memo clear from
  Goccia.RegExp.VM to keep the shared unit engine-free, and retain its own
  main-thread finalization for binaries that link it without the regex VM.
- Broaden the registry callback contract to cover a thread's own entries in a
  shared lock-guarded structure (Atomics), not only managed threadvars.
- Add a Goccia.ThreadCleanupLeak.Test gate pinning each of the seven
  registrations, plus ADR 0080.

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

vercel Bot commented Jun 28, 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 28, 2026 9:01pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 89b63aac-7362-43b1-b37c-4abf69ddb0fd

📥 Commits

Reviewing files that changed from the base of the PR and between 6154452 and f02fbe4.

📒 Files selected for processing (1)
  • source/units/Goccia.RegExp.VM.pas

📝 Walkthrough

Walkthrough

Seven per-thread cache and memo cleanup callbacks are registered during unit initialization, ShutdownThreadRuntime removes its explicit per-thread clear calls, and a regression helper plus test verify the registrations. ADR 0083 and the ADR index are updated to match the new cleanup flow.

Changes

Registry-driven thread cleanup migration

Layer / File(s) Summary
Registry helper and contract
source/units/Goccia.ThreadCleanupRegistry.pas
Expands the threadvar cleanup contract comment and adds IsThreadvarCleanupRegistered for checking whether a cleanup callback was registered.
ShutdownThreadRuntime cleanup drain
source/units/Goccia.Threading.pas
Updates ShutdownThreadRuntime to describe draining Goccia.ThreadCleanupRegistry before later runtime shutdowns and removes the explicit per-thread cache and memo clear calls.
Unit cleanup registrations
source/units/Goccia.Builtins.Atomics.pas, source/units/Goccia.Builtins.DisposableStack.pas, source/units/Goccia.Builtins.Semver.pas, source/units/Goccia.ImportMeta.pas, source/units/Goccia.RegExp.VM.pas, source/units/Goccia.Temporal.TimeZone.pas, source/shared/TextSemantics.pas
Registers the moved cleanup callbacks from unit initialization, updates related comments, and adds the Atomics lock-state guard and TextSemantics worker-thread cleanup routing through RegExp.VM.
Verification and ADR update
source/units/Goccia.ThreadCleanupLeak.Test.pas, docs/adr/0083-migrate-cache-clears-into-cleanup-registry.md, docs/adr/README.md
Adds a regression test that checks the migrated cleanup callbacks are registered, expands its unit references, and updates ADR 0083 plus the ADR records list.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • frostney/GocciaScript#891: Introduces Goccia.ThreadCleanupRegistry and the initial ShutdownThreadRuntime drain; this PR migrates the remaining explicit cache clears into that same registry.
  • frostney/GocciaScript#805: Touches Goccia.RegExp.VM.pas around ClearRegExpInputMemo, which this PR routes through the cleanup registry.
  • frostney/GocciaScript#717: Changes Atomics waiter shutdown behavior, which this PR updates again to add the registry registration and the early-exit guard.

Suggested labels

documentation, internal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: moving per-thread cache clears into the cleanup registry.
Description check ✅ Passed The description follows the template with Summary and Testing sections and includes implementation details and verification.
Linked Issues check ✅ Passed The PR matches #893 by removing the explicit ShutdownThreadRuntime clears, registering the migrated cleanups, and adding regression tests.
Out of Scope Changes check ✅ Passed The added ADR/docs and comment updates support the cleanup-registry migration and do not appear unrelated to the PR objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

@frostney frostney marked this pull request as ready for review June 28, 2026 17:06
@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation internal Refactoring, CI, tooling, cleanup labels Jun 28, 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
source/units/Goccia.RegExp.VM.pas (1)

1070-1073: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the stale memo cleanup comment.

This still describes the old finalization-only cleanup and bounded worker residual; the memo is now registered with Goccia.ThreadCleanupRegistry and cleared on worker exit.

Proposed comment update
-// FPC does not auto-finalize managed threadvars at thread exit, so the unit
-// finalization below clears the main-thread memo on shutdown; a worker thread's
-// last-held pair is a bounded residual, the same as the engine's other managed
-// threadvars (e.g. each builtin's FStaticMembers).
+// FPC does not auto-finalize managed threadvars at thread exit, so
+// ClearRegExpInputMemo is registered with Goccia.ThreadCleanupRegistry to clear
+// the calling thread's retained pair on worker exit and main-thread shutdown.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/units/Goccia.RegExp.VM.pas` around lines 1070 - 1073, Update the stale
memo cleanup comment in the unit finalization area to match the current
behavior: the memo is no longer cleared only by main-thread finalization, but is
now registered with Goccia.ThreadCleanupRegistry and cleared on worker exit.
Locate the comment near the memo cleanup logic in Goccia.RegExp.VM.pas and
revise it so it accurately describes the registry-based cleanup path and no
longer mentions the old bounded worker residual behavior.
🤖 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.

Outside diff comments:
In `@source/units/Goccia.RegExp.VM.pas`:
- Around line 1070-1073: Update the stale memo cleanup comment in the unit
finalization area to match the current behavior: the memo is no longer cleared
only by main-thread finalization, but is now registered with
Goccia.ThreadCleanupRegistry and cleared on worker exit. Locate the comment near
the memo cleanup logic in Goccia.RegExp.VM.pas and revise it so it accurately
describes the registry-based cleanup path and no longer mentions the old bounded
worker residual behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d96e5ea-6c4a-4383-871c-b396109878ab

📥 Commits

Reviewing files that changed from the base of the PR and between 45194c5 and f558c17.

📒 Files selected for processing (12)
  • docs/adr/0081-migrate-cache-clears-into-cleanup-registry.md
  • docs/adr/README.md
  • source/shared/TextSemantics.pas
  • source/units/Goccia.Builtins.Atomics.pas
  • source/units/Goccia.Builtins.DisposableStack.pas
  • source/units/Goccia.Builtins.Semver.pas
  • source/units/Goccia.ImportMeta.pas
  • source/units/Goccia.RegExp.VM.pas
  • source/units/Goccia.Temporal.TimeZone.pas
  • source/units/Goccia.ThreadCleanupLeak.Test.pas
  • source/units/Goccia.ThreadCleanupRegistry.pas
  • source/units/Goccia.Threading.pas

@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Suite Timing

Test Runner (interpreted: 11,046 passed; bytecode: 11,046 passed)
Metric Interpreted Bytecode
Total 11046 11046
Passed 11046 ✅ 11046 ✅
Workers 4 4
Test Duration 17.63s 19.44s
Lex (cumulative) 467.8ms 478.2ms
Parse (cumulative) 367.4ms 375.4ms
Compile (cumulative) 761.6ms
Execute (cumulative) 74.3ms 48.26s
Engine Total (cumulative) 909.5ms 49.87s
Lex (avg/worker) 117.0ms 119.6ms
Parse (avg/worker) 91.8ms 93.9ms
Compile (avg/worker) 190.4ms
Execute (avg/worker) 18.6ms 12.06s
Engine Total (avg/worker) 227.4ms 12.47s

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 283.78 MiB 281.18 MiB
GC Peak Live 347.56 MiB 324.79 MiB
GC Allocated During Run 531.00 MiB 474.99 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 195 195
GC Collected Objects 2,605,579 2,172,696
Heap Start Allocated 182.7 KiB 182.7 KiB
Heap End Allocated 3.66 MiB 3.66 MiB
Heap Delta Allocated 3.48 MiB 3.48 MiB
Heap Delta Free 1.68 MiB 1.68 MiB
Benchmarks (interpreted: 437; bytecode: 437)
Metric Interpreted Bytecode
Total 437 437
Workers 4 4
Duration 2.98min 2.75min

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.28 MiB 6.28 MiB
GC Peak Live 93.65 MiB 62.53 MiB
GC Allocated During Run 16.05 GiB 9.59 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 3,700 3,443
GC Collected Objects 251,963,947 216,269,264
Heap Start Allocated 3.36 MiB 3.36 MiB
Heap End Allocated 3.36 MiB 3.36 MiB
Heap Delta Allocated 128 B 128 B

Measured on ubuntu-latest x64.

@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

437 benchmarks · PR vs same-runner main build

Interpreted: 🟢 32 improved · 🔴 24 regressed · 381 unchanged · avg +1.6%
Bytecode: 🟢 71 improved · 🔴 29 regressed · 337 unchanged · avg +2.1%

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

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

Deterministic profile diff

Deterministic profile diff: no significant changes.

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

@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

test262 Conformance

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

Category Run Passed Δ Pass Failed Pass-rate Δ Rate
built-ins 23,643 22,619 +1 1,024 95.7% ±0pp
harness 116 116 ±0 0 100.0% ±0pp
intl402 3,341 3,334 -1 7 99.8% ±0pp
language 23,711 23,711 ±0 0 100.0% ±0pp
staging 1,482 1,111 ±0 371 75.0% ±0pp
total 52,293 50,891 ±0 1,402 97.3% ±0pp

Areas closest to 100%

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

Newly failing (1):

  • intl402/DateTimeFormat/prototype/formatToParts/compare-to-temporal.js

Newly passing (1):

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

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

frostney and others added 2 commits June 28, 2026 20:21
The memo declaration comment still described the pre-registry lifecycle: it
claimed the unit finalization clears the main-thread memo and that a worker
thread's last-held pair is a bounded residual. After the #893 migration the
memo is registered with Goccia.ThreadCleanupRegistry, so the drain clears it on
worker exit and at main-thread shutdown — no residual. Comment-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@frostney frostney merged commit c493518 into main Jun 29, 2026
14 of 15 checks passed
@frostney frostney deleted the claude/jovial-lewin-4ed28a branch June 29, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation internal Refactoring, CI, tooling, cleanup

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate explicit ShutdownThreadRuntime cache clears into the thread-cleanup registry

1 participant