Skip to content

perf(vm): unbox typed-array element reads and writes in the bytecode VM#900

Merged
frostney merged 8 commits into
mainfrom
claude/epic-shirley-b80900
Jun 28, 2026
Merged

perf(vm): unbox typed-array element reads and writes in the bytecode VM#900
frostney merged 8 commits into
mainfrom
claude/epic-shirley-b80900

Conversation

@frostney

@frostney frostney commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • Typed-array element access in the bytecode VM fell through to the generic TGocciaObjectValue computed-access branch, which allocated an IntToStr index name plus a heap TGocciaNumberLiteralValue on every read, and boxed the scalar via RegisterToValue on every write. Arithmetic and comparisons were already 100% scalar (ADR 0001 / ADR 0005), so these boundary boxings dominated allocation-heavy typed-array workloads — the root cause behind Reduce bytecode-VM value boxing so allocation-heavy conformance tests meet the per-test deadline #800's motivating test staging/sm/TypedArray/sort_large_countingsort.js.
  • Adds unboxed fast paths to ExecGetComputedProperty / ExecSetComputedProperty for TGocciaTypedArrayValue receivers at array-index keys (new TryReadIndexedScalar / TryWriteIndexedScalar + RegisterFromDouble): reads move the element straight into a register scalar; numeric-scalar writes store it directly. Also dedups the element store (integer NaN/Infinity coercion now lives only in WriteBinaryNumberElement) and single-validates the hot path via ReadElementUnchecked / WriteElementUnchecked.
  • Constraints / non-goals (preserved). All value semantics and the unboxed/boxed register model (ADR 0001, ADR 0005) are kept. The fast path fires only for non-BigInt kinds, array-index keys, and numeric-scalar write values. Reads fall through to the unchanged boxed slow path for BigInt kinds, non-index keys, and out-of-range / detached indices (yielding undefined); a non-BigInt scalar write is handled in place even for an out-of-range index or immutable buffer (store skipped, success reported per integer-indexed exotic [[Set]]) and only falls through for BigInt kinds (a Number value still throws TypeError), non-index keys, or non-scalar values (objects with valueOf, booleans, null/undefined). ToNumber on a Number is side-effect-free, so the observable conversion ordering of integer-indexed [[Set]] (ES2026 §10.4.5) is preserved. Not a JIT; the test and the 20s harness deadline are unchanged.

Results (prod, bytecode)

Context: the issue's ~31M-allocation / 36.8s-CI figures were accurate when filed (validated at #795). Intervening work (#802 argument arena, #818 unused-arguments elision) already cut this test to ~7.47M allocations and back under the deadline; this PR removes the remaining named lever — typed-array element boxing — as a durable, hardware-independent win.

Motivating test sort_large_countingsort.js:

Metric Before (current main) After Δ
Heap allocations 7,471,627 4,719,119 −36.8%
Runtime, x86_64 --jobs=4 @ --timeout-ms=20000 (CI-like) 14.1s ~10.4s −26% (margin under the 20s deadline ~6s → ~9.6s)
Runtime, M1 --jobs=1 ~7.6s ~7.5s within noise (M1 is allocation-cheap)

benchmarks/typed-arrays.js "TypedArray element access" (bytecode, vs main): sequential read +57%, sequential write +35%, Float64 write +26%; native methods (fill/reduce/sort/iteration) flat within run-to-run noise.

The 20s deadline is wall-clock on CI's x86_64 4-vCPU runner. M1 native is ~2× too fast to reproduce the timeout, so runtime was measured on an OrbStack x86_64 VM as a CI proxy; allocation count is the hardware-independent metric. CI's full test262 gate on this PR is the authoritative cross-corpus no-regression check.

Testing

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

Details:

  • Full JS suite: 11,009 / 11,009 pass in both interpreter and bytecode modes. New regression test tests/built-ins/TypedArray/element-access-unboxed.js covers −0 round-trips (float preserves, integer normalizes), unboxed reads feeding > / ===, register-resident scalar writes, Float16Array indices, non-scalar values routed through the slow path, a Number-into-BigInt TypeError, and large-array (counting-sort-scale) access.
  • test262 (prod, bytecode), before vs after — identical counts, 0 wrapper-infra: staging 1111/371, built-ins/TypedArray* 2183/1, built-ins/Array* 3121/208, built-ins/DataView 558/3.
  • ./format.pas --check clean; Pascal pre-commit hooks (trunc-guards, format) pass.
  • Native Pascal unit tests not run locally (left to CI); the JS suite + test262 exercise the changed value type and VM cores end-to-end.
  • The perf change itself applies ADR 0001 (number dual representation) and ADR 0005 (register VM) rather than introducing a decision; docs/bytecode-vm.md notes the fast path.
  • Adds ADR 0081 — Reject shared value caches as a runtime optimization, the durable outcome of a value-caching investigation done on this branch: a spiked small-integer/Infinity boxed-number cache cut allocations ~25% on the motivating test but produced no runtime gain (interleaved), and disabling the existing special-value singleton reuse costs only ~1.4–1.7% — so allocation-count reduction is not a runtime lever here. While verifying that, found and corrected a phantom "SmallInt 0-255 cache" that core-patterns.md/garbage-collector.md described but was never implemented (only the ADR 0002 special-value singletons exist).

Closes #800

frostney and others added 3 commits June 28, 2026 13:43
…access path

Typed-array element access in the bytecode VM fell through to the generic
TGocciaObjectValue computed-access branch, allocating an IntToStr index name plus
a heap TGocciaNumberLiteralValue on every read, and boxing the scalar via
RegisterToValue on every write. Arithmetic and comparisons were already 100%
scalar (ADR 0001/0005), so these boundary boxings dominated allocation-heavy
typed-array workloads (issue #800).

Add unboxed fast paths to ExecGetComputedProperty / ExecSetComputedProperty for
TGocciaTypedArrayValue receivers at array-index keys: reads go straight into a
register scalar via the new RegisterFromDouble; numeric-scalar writes store
directly (ToNumber on a Number is side-effect-free, so the spec's observable
conversion is preserved). BigInt kinds, non-index keys, non-scalar values, and
out-of-range / detached / immutable cases fall through to the unchanged boxed
path, so all value semantics are preserved.

Dedup the element store while here: integer NaN/Infinity coercion now lives only
in WriteBinaryNumberElement, and the element read/write paths single-validate via
ReadElementUnchecked / WriteElementUnchecked.

sort_large_countingsort.js (prod, bytecode): allocations 7,471,627 -> 4,719,119
(-36.8%); x86_64 jobs=4 at the 20s deadline 14.1s -> 10.4s. typed-arrays.js
element access: read +57%, write +35%, Float64 write +26%. No regressions: full
JS suite 11,009/11,009 in both modes; test262 staging, TypedArray, Array, and
DataView identical before/after.

Closes #800

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document the TryReadIndexedScalar/TryWriteIndexedScalar fast path on the
computed-access cores so the bytecode VM doc stays accurate after the
typed-array element unboxing change.

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 4:58pm

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: 7088a132-05af-4eb9-b93e-70cd3ffea6de

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4b371 and f718c41.

📒 Files selected for processing (4)
  • docs/adr/0081-reject-value-caches-for-allocation-reduction.md
  • docs/adr/README.md
  • docs/bytecode-vm.md
  • docs/core-patterns.md
💤 Files with no reviewable changes (1)
  • docs/adr/0081-reject-value-caches-for-allocation-reduction.md
✅ Files skipped from review due to trivial changes (3)
  • docs/adr/README.md
  • docs/bytecode-vm.md
  • docs/core-patterns.md

📝 Walkthrough

Walkthrough

Adds unboxed scalar fast paths for typed-array indexed reads and writes in the VM, plus a raw double-to-register helper. Typed-array element access gains unchecked helpers and scalar fast-path methods. Tests and docs were updated to cover the new behavior and related cache policy notes.

Changes

TypedArray Unboxed Fast Paths

Layer / File(s) Summary
TypedArrayValue unchecked accessors and scalar fast paths
source/units/Goccia.Values.TypedArrayValue.pas
Splits ReadElement/WriteElement into checked wrappers and new unchecked variants. Adds TryReadIndexedScalar and TryWriteIndexedScalar with BigInt, bounds, and immutable-buffer handling, and routes WriteNumberLiteral through the unchecked write path.
RegisterFromDouble helper
source/units/Goccia.VM.Registers.pas
Adds RegisterFromDouble(Double) and its implementation for converting raw doubles into registers, including integer-valued finite numbers, -0.0, and non-finite values.
VM fast-path dispatch for typed-array get/set
source/units/Goccia.VM.pas
Imports Goccia.Values.TypedArrayValue and adds early typed-array branches in ExecGetComputedProperty and ExecSetComputedProperty that use the scalar fast-path methods before falling back to boxed handling.
Tests and docs
tests/built-ins/TypedArray/element-access-unboxed.js, docs/bytecode-vm.md, docs/adr/0081-reject-value-caches-for-allocation-reduction.md, docs/adr/README.md, docs/core-patterns.md, docs/garbage-collector.md
Adds regression coverage for unboxed typed-array reads/writes and updates docs for the typed-array fast paths, RuntimeCopy, ADR 0081, and the value-cache guidance.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #800: Directly matches the typed-array unboxed read/write work aimed at reducing boxing on allocation-heavy typed-array workloads.
  • #860: Matches the same typed-array unboxed element access focus in the VM and TGocciaTypedArrayValue.

Possibly related PRs

  • frostney/GocciaScript#748: Both PRs change computed-property/indexed access execution in Goccia.VM.pas, with overlapping typed-array and opcode-path work.
  • frostney/GocciaScript#818: Both PRs modify TGocciaTypedArrayValue indexed read/write behavior and the VM code that uses those accessors.

Suggested labels

performance, documentation

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: unboxing typed-array computed access in the bytecode VM.
Description check ✅ Passed The description follows the template with a Summary and Testing section and includes the required implementation and validation details.
Linked Issues check ✅ Passed The changes address #800 by reducing typed-array boxing/allocation in the VM while preserving semantics and validating with tests and benchmarks.
Out of Scope Changes check ✅ Passed The added docs, ADR, and regression test all support the typed-array boxing performance work and do not appear unrelated.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

@github-actions

github-actions Bot commented Jun 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 20.73s 19.94s
Lex (cumulative) 529.6ms 557.7ms
Parse (cumulative) 378.8ms 400.3ms
Compile (cumulative) 842.5ms
Execute (cumulative) 99.9ms 46.39s
Engine Total (cumulative) 1.01s 48.19s
Lex (avg/worker) 132.4ms 139.4ms
Parse (avg/worker) 94.7ms 100.1ms
Compile (avg/worker) 210.6ms
Execute (avg/worker) 25.0ms 11.60s
Engine Total (avg/worker) 252.1ms 12.05s

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.68 MiB
GC Peak Live 336.60 MiB 335.42 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,578 2,167,482
Heap Start Allocated 182.6 KiB 182.6 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.91min 2.79min

Memory

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

Metric Interpreted Bytecode
GC Live 6.28 MiB 6.28 MiB
GC Peak Live 93.93 MiB 63.87 MiB
GC Allocated During Run 15.37 GiB 9.77 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 3,701 3,516
GC Collected Objects 244,285,877 225,283,404
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: 🟢 28 improved · 🔴 57 regressed · 352 unchanged · avg +0.9%
Bytecode: 🟢 54 improved · 🔴 30 regressed · 353 unchanged · avg +1.4%

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

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

Deterministic profile diff

Deterministic profile diff: no significant changes.

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

@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

test262 Conformance

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 ±0 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 +1 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 / -0)

Newly passing (1):

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

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

@frostney frostney marked this pull request as ready for review June 28, 2026 15:12
@coderabbitai coderabbitai Bot added the performance Performance improvement label 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.

Actionable comments posted: 1

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

Inline comments:
In `@docs/bytecode-vm.md`:
- Line 135: Update the computed-property access description to separate read and
write fallback behavior in the VM docs. In the `ClassifyPropertyKey` /
`ExecGetComputedProperty` / `ExecSetComputedProperty` /
`ExecDeleteComputedProperty` description, keep the read path saying out-of-range
or detached typed-array accesses fall back to the boxed path, but revise the
write path so `TryWriteIndexedScalar` is described as handling non-`BigInt`
writes directly even for out-of-range or immutable backing buffers. Make the
`TGocciaComputedAccessOptions` and `TGocciaTypedArrayValue` wording reflect this
split so the semantics match the `TryReadIndexedScalar`/`TryWriteIndexedScalar`
contracts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 40a6e302-da60-46b1-82e6-329ea3b725ff

📥 Commits

Reviewing files that changed from the base of the PR and between 0f2734d and 5bb736b.

📒 Files selected for processing (5)
  • docs/bytecode-vm.md
  • source/units/Goccia.VM.Registers.pas
  • source/units/Goccia.VM.pas
  • source/units/Goccia.Values.TypedArrayValue.pas
  • tests/built-ins/TypedArray/element-access-unboxed.js

Comment thread docs/bytecode-vm.md Outdated
Record ADR 0080 capturing why interning/pooling boxed TGocciaValue instances to
reduce allocation count does not improve runtime in this FPC codebase, so the
C/C++ "fewer allocations => faster" intuition is not imported a fourth time.

Generalizes ADR 0013 (reject string interning) to boxed numbers with the #900
spike data: a small-int + Infinity/NaN cache on the bytecode VM RegisterToValue
path cut allocations 25% but moved runtime +2.2% (flat-to-worse, interleaved
medians). Notes the narrow exceptions that do pay off (SmallInt 0-255, special
-value singletons / ADR 0002) and the interleaved-measurement guardrail, and
cross-links core-patterns.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai coderabbitai Bot added the internal Refactoring, CI, tooling, cleanup label Jun 28, 2026
frostney and others added 2 commits June 28, 2026 17:18
The docs (core-patterns.md, garbage-collector.md) described a "SmallInt cache
for 0-255" used by RuntimeCopy as an accepted, working optimization. It never
existed: there is no array-of-TGocciaNumberLiteralValue anywhere in git history,
and the claim was introduced by a docs-only commit (#302, Apr 2026) with no
implementation. The real number value-reuse is RuntimeCopy returning the
ADR 0002 special-value singletons (0, 1, NaN, +/-Infinity, -0); all other
numbers allocate via Create.

Correct both docs and ADR 0080 (which had repeated the phantom claim) to describe
only the singletons that actually exist, and note that a spiked 0-255 range cache
showed no runtime gain. Surfaced while verifying ADR 0080's "narrow exception".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Measured both sides of the boundary so the "kept exception" is data-backed, not
asserted: disabling the singleton reuse costs +786k allocations and ~1.4-1.7% on
the allocation-heavy counting-sort test (within noise on typical integer code),
while widening it to a small-integer range removed more allocations for no
runtime gain (+2.2%). Even the kept cache barely moves runtime — it is retained
because it is free, not because it is a meaningful speedup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai coderabbitai Bot removed the internal Refactoring, CI, tooling, cleanup label Jun 28, 2026
frostney and others added 2 commits June 28, 2026 17:51
Address PR review (coderabbitai): the computed-access note conflated the read and
write fast-path fallbacks. Reads fall through to the boxed path for BigInt kinds,
non-index keys, and out-of-range/detached indices; non-BigInt scalar writes are
handled in place even for out-of-range or immutable cases (store skipped, success
reported) and only fall through for BigInt kinds, non-index keys, or non-scalar
values. Wording now matches the TryReadIndexedScalar/TryWriteIndexedScalar
contracts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation and removed documentation Improvements or additions to documentation labels Jun 28, 2026
@frostney frostney merged commit 2c1b629 into main Jun 28, 2026
15 checks passed
@frostney frostney deleted the claude/epic-shirley-b80900 branch June 28, 2026 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduce bytecode-VM value boxing so allocation-heavy conformance tests meet the per-test deadline

1 participant