Skip to content

feat(engine): add deterministic and custom host environments#968

Merged
frostney merged 5 commits into
mainfrom
codex/issue-881-deterministic-execution
Jul 15, 2026
Merged

feat(engine): add deterministic and custom host environments#968
frostney merged 5 commits into
mainfrom
codex/issue-881-deterministic-execution

Conversation

@frostney

@frostney frostney commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add an engine-owned TGocciaHostEnvironment with injectable clock and random providers, plus a portable SplitMix64 implementation.
  • Add --deterministic and "deterministic": true: JavaScript-visible epoch and monotonic time are fixed at 0, the explicit time-zone override is UTC, and the random seed is unsigned 64-bit 0.
  • Add GocciaScriptLoader --host-environment=<module> and the equivalent config key. Provider modules export callable epochNanoseconds, monotonicNanoseconds, timeZoneIdentifier, and random functions and load before the runtime profile captures performance.timeOrigin.
  • Route Math.random, Date/Temporal.Now, implicit Intl.DateTimeFormat time, and performance through the host environment. Child ShadowRealm, Test262, and sandbox executions receive stable distinct RNG streams.
  • Preserve each API's established default time-zone behavior when no override is configured: Temporal and Date use the system zone, while Intl.DateTimeFormat remains UTC. This fixes the interpreter, bytecode, and Test262 regression caused by Linux reporting Etc/UTC.
  • Keep timeouts, profiling, GC, benchmark measurement, and Test262 agent coordination on live infrastructure clocks. Harden performance midpoint and nanosecond conversion arithmetic for realistic custom epochs, and use the shared portable Int64ToDouble conversion for seeded random values.
  • Document the Pascal and JavaScript provider APIs, including a runnable custom provider example.
  • Closes Add a deterministic execution mode (injectable clock + seeded RNG) #881.

Testing

  • Verified no regressions and confirmed the new feature or bugfix in end-to-end JavaScript/TypeScript tests
    • ./build/GocciaTestRunner tests --output=compact-json — 11,364/11,364 passed
    • ./build/GocciaTestRunner tests --mode=bytecode --output=compact-json — 11,364/11,364 passed
    • bun scripts/test-cli-config.ts
    • Custom JavaScript host provider invoked after explicit Goccia.gc() in interpreted and bytecode modes
  • Updated documentation
    • Documentation links, symbols, duplication, length, Markdown lint, and Pascal formatting checks passed
  • Optional: Verified no regressions and confirmed the new feature or bugfix in native Pascal tests (if AST, scope, evaluator, or value types changed)
    • Goccia.HostEnvironment.Test — 5/5 passed on macOS arm64
  • Optional: Verified no benchmark regressions or confirmed benchmark coverage for the change

@vercel

vercel Bot commented Jul 14, 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 Jul 14, 2026 8:06pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds an engine-owned host environment for JavaScript-visible time, time zones, and randomness. It supports deterministic profiles, custom JavaScript providers, child-realm stream derivation, CLI/configuration wiring, runtime integration, documentation, and end-to-end tests.

Changes

Engine-owned host environment

Layer / File(s) Summary
Host providers and deterministic profiles
source/units/Goccia.HostEnvironment.pas, source/units/Goccia.HostEnvironment.Test.pas
Adds injectable clock and random providers, fixed deterministic values, forked child streams, and unit coverage.
Runtime integration
source/units/Goccia.Engine.pas, source/units/Goccia.Builtins.*.pas, source/units/Goccia.Values.IntlDateTimeFormat.pas
Routes Math.random, Temporal, Intl date formatting, and Performance timing through each engine’s host environment.
JavaScript provider injection
source/units/Goccia.HostEnvironment.JavaScript.pas, examples/custom-host-environment.js
Loads and validates custom provider exports for epoch time, monotonic time, time zone, and random streams.
CLI, sandbox, and realm wiring
source/app/*, source/app/GocciaScriptLoader*.dpr
Adds deterministic and host-environment options and propagates host environments through sandbox, ShadowRealm, and Test262 execution.
Documentation and validation
README.md, docs/*, scripts/test-cli*.ts
Documents configuration and provider contracts and tests deterministic output across execution modes, realms, configurations, and timeout behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: new feature, documentation, internal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR implements #881’s deterministic mode, injectable clock seam, portable seeded RNG, UTC behavior, and child-stream reproducibility.
Out of Scope Changes check ✅ Passed The docs, example, and tests are all directly tied to the new host-environment and deterministic execution feature set.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title is concise and accurately summarizes the main change: deterministic and custom host environments.
Description check ✅ Passed The description matches the required template with Summary and Testing sections and includes the key implementation notes and results.

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

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Web Tooling Benchmark

Workload Status Goccia
acorn pass 0.01 runs/s
babel pass 0.01 runs/s
babel-minify pass 0.10 runs/s
babylon pass 0.03 runs/s
buble pass 0.08 runs/s
chai pass 0.10 runs/s
coffeescript pass 0.01 runs/s
espree pass 0.01 runs/s
esprima pass 0.01 runs/s
jshint pass 0.02 runs/s
lebab pass 0.09 runs/s
postcss pass 0.01 runs/s
prepack pass 0.11 runs/s
prettier pass 0.07 runs/s
source-map pass 0.03 runs/s
terser pass 212 runs/s
typescript pass 0.09 runs/s
uglify-js pass 107 runs/s

18 pinned Web Tooling workloads; 18 workloads produced at least one Goccia sample. Raw results from 1 sample per workload; full stdout/stderr for failures and min/max/CV stay in the web-tooling-report artifact. This lane is Goccia-only by design.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Suite Timing

Test Runner (interpreted: 11,364 passed; bytecode: 11,364 passed)
Metric Interpreted Bytecode
Total 11364 11364
Passed 11364 ✅ 11364 ✅
Workers 4 4
Test Duration 6.32s 6.21s
Lex (cumulative) 673.6ms 666.6ms
Parse (cumulative) 497.6ms 488.3ms
Compile (cumulative) 1.00s
Execute (cumulative) 287.5ms 14.63s
Engine Total (cumulative) 1.46s 16.79s
Lex (avg/worker) 168.4ms 166.6ms
Parse (avg/worker) 124.4ms 122.1ms
Compile (avg/worker) 250.5ms
Execute (avg/worker) 71.9ms 3.66s
Engine Total (avg/worker) 364.7ms 4.20s

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 53.48 MiB 49.33 MiB
GC Peak Live 194.44 MiB 170.55 MiB
GC Allocated During Run 416.52 MiB 358.17 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 205 205
GC Collected Objects 3,833,884 3,344,648
Heap Start Allocated 186.3 KiB 186.3 KiB
Heap End Allocated 1.61 MiB 1.61 MiB
Heap Delta Allocated 1.42 MiB 1.42 MiB
Heap Delta Free 653.0 KiB 653.0 KiB
Benchmarks (interpreted: 437; bytecode: 437)
Metric Interpreted Bytecode
Total 437 437
Workers 4 4
Duration 3.22min 2.96min

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 3.49 MiB 110.3 KiB
GC Peak Live 136.08 MiB 97.40 MiB
GC Allocated During Run 15.92 GiB 17.33 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 4,095 6,537
GC Collected Objects 243,561,394 386,516,131
Heap Start Allocated 1.33 MiB 1.33 MiB
Heap End Allocated 1.33 MiB 1.33 MiB
Heap Delta Allocated 128 B 128 B
Boot
Metric Interpreted Bytecode
Boot (median) 6.0ms 6.1ms
Boot (min) 5.6ms 5.7ms

Empty-script (0;) end-to-end process wall-clock for GocciaScriptLoader, min and median over 60 runs after 10 warmups. Includes a fixed process / dynamic-loader floor that does not shrink, so it understates the engine-boot speedup; treat as practical boot time, not pure engine work.

Measured on ubuntu-latest x64.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

437 benchmarks · PR vs same-runner main build

Interpreted: 🟢 38 improved · 🔴 11 regressed · 388 unchanged · avg +1.2%
Bytecode: 🟢 75 improved · 🔴 30 regressed · 332 unchanged · avg +2.0%

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

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

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 Jul 14, 2026

Copy link
Copy Markdown
Contributor

test262 Conformance

9 timeout(s) — counted separately from ordinary conformance failures; inspect the full artifact for affected tests.

Category Run Passed Δ Pass Failed Timeouts Δ Timeout Wrap-Infra Pass-rate Δ Rate
built-ins 23,668 23,668 +33 0 0 -2 0 100.0% +0.1pp
harness 116 116 ±0 0 0 ±0 0 100.0% ±0pp
intl402 3,341 3,338 ±0 3 0 ±0 0 99.9% ±0pp
language 23,713 23,712 ±0 1 0 ±0 0 100.0% ±0pp
staging 1,482 1,384 +1 89 9 -1 0 93.4% +0.1pp
total 52,320 52,218 +34 93 9 -3 0 99.8% +0.1pp

Areas closest to 100%

Area Pass rate Δ vs main Passing
language/expressions 100.0% ±0pp 11,101 / 11,102
intl402/NumberFormat 99.6% ±0pp 248 / 249
intl402/Locale 99.3% ±0pp 151 / 152
Per-test deltas (+31 / -0 / timeout +0 / -3)

Newly passing (31):

  • built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js
  • built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js
  • built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed.js
  • built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js
  • built-ins/FinalizationRegistry/proto-from-ctor-realm.js
  • built-ins/Infinity/S15.1.1.2_A2_T2.js
  • built-ins/Iterator/zipKeyed/iterables-iteration-undefined.js
  • built-ins/Iterator/zipKeyed/results-object-has-no-undefined-iterables-properties.js
  • built-ins/NaN/S15.1.1.1_A2_T2.js
  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js
  • built-ins/Promise/allKeyed/invoke-resolve-get-once.js
  • built-ins/Promise/allSettledKeyed/invoke-resolve-get-once.js
  • built-ins/Promise/allSettledKeyed/reject-from-same-thenable.js
  • built-ins/Promise/allSettledKeyed/resolve-from-same-thenable.js
  • built-ins/Promise/allSettledKeyed/result-property-descriptors.js
  • built-ins/RegExp/property-escapes/generated/Changes_When_NFKC_Casefolded.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Balinese.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Beria_Erfe.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Common.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Egyptian_Hieroglyphs.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Inherited.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kawi.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Khitan_Small_Script.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Sidetic.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js
  • built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tolong_Siki.js
  • built-ins/StringIteratorPrototype/next/next-iteration-surrogate-pairs.js
  • built-ins/undefined/15.1.1.3-1.js
  • built-ins/undefined/15.1.1.3-3.js
  • built-ins/WeakRef/proto-from-ctor-realm.js

Resolved timeouts (3):

  • built-ins/decodeURI/S15.1.3.1_A2.5_T1.js
  • built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js
  • staging/sm/extensions/recursion.js

Steady-state failures and timeouts are non-blocking; PASS → non-timeout failure transitions 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.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

JetStream 3 Performance Barometer

Workload Status Goccia main Goccia PR QuickJS Node.js vs QuickJS vs Node.js
hash-map pass 0.60 0.60 15.64 355.18 26.11× 593.15×
ai-astar pass 1.61 1.66 40.28 336.21 24.21× 202.10×
gaussian-blur pass 0.37 0.36 7.72 291.58 21.18× 800.15×
raytrace-public-class-fields pass 0.44 0.44 11.54 206.77 26.06× 467.02×
sync-fs pass 1.61 1.63 46.69 307.15 28.59× 188.12×
lazy-collections pass 2.08 2.13 68.29 152.43 32.07× 71.58×

Geomean reference ratio: QuickJS 26.15×; Node.js 290.68×.

1.00× means aligned; values above 1.00× mean Goccia was proportionally slower after normalizing JetStream’s higher-is-better score. This is a directional barometer across runtimes with different goals, not a product ranking. Raw samples and failure details remain in the jetstream-report artifact.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

AWFY Results

Target Status Goccia main Goccia PR QuickJS 2026-06-04 NodeJS v26.5.0 Δ PR vs main
Bounce pass 19.06ms 19.14ms 0.90ms 1.01ms ~ overlap (-0.42%)
CD pass 186.54ms 186.64ms 9.54ms 9.03ms ~ overlap (-0.05%)
DeltaBlue pass 4.35ms 4.36ms 258.85µs 1.56ms ~ overlap (-0.14%)
Havlak pass 72.90s 73.30s 3750.46ms 202.86ms 🔴 -0.55%
Json pass 300.42ms 304.69ms 12.30ms 4.09ms 🔴 -1.42%
List pass 14.34ms 15.46ms 0.80ms 0.66ms 🔴 -7.86%
Mandelbrot pass 25.23µs 25.47µs 4.91µs 85.12µs ~ overlap (-0.95%)
NBody pass 308.85µs 308.66µs 24.56µs 350.22µs ~ overlap (+0.06%)
Permute pass 35.48ms 35.21ms 1.65ms 0.72ms ~ overlap (+0.76%)
Queens pass 18.84ms 18.83ms 1.00ms 0.95ms ~ overlap (+0.03%)
Richards pass 863.41ms 872.39ms 43.52ms 6.16ms 🔴 -1.04%
Sieve pass 11.15ms 11.12ms 458.13µs 494.83µs ~ overlap (+0.24%)
Storage pass 27.31ms 27.63ms 2.37ms 0.92ms 🔴 -1.16%
Towers pass 54.80ms 53.89ms 2.55ms 1.08ms 🟢 +1.65%

Geomean Ratios

Ratio (row / column) Goccia main Goccia PR QuickJS 2026-06-04 NodeJS v26.5.0
Goccia main 1.000 0.993 17.116 18.927
Goccia PR 1.008 1.000 17.245 19.070
QuickJS 2026-06-04 0.058 0.058 1.000 1.106
NodeJS v26.5.0 0.053 0.052 0.904 1.000

14 pinned AWFY benchmarks. Medians from 5 interleaved samples per engine; raw JSON includes min/max/CV and is attached as the awfy-report artifact. Δ compares PR Goccia median against the same-runner main Goccia median; overlapping min/max ranges are treated as unchanged noise. Rows below 0.5ms are timer-floor sensitive.

@frostney frostney changed the title feat(engine): add deterministic execution mode feat(engine): add deterministic and custom host environments Jul 14, 2026
@frostney
frostney marked this pull request as ready for review July 14, 2026 18:49
@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation new feature New feature or request labels Jul 14, 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: 2

🧹 Nitpick comments (3)
source/units/Goccia.HostEnvironment.Test.pas (1)

114-121: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test sibling stream uniqueness from the same parent.

Both children currently receive stream ID 1 from separate parents. Derive two children from one parent, then reproduce both positions from a second deterministic parent to cover the distinct-and-repeatable stream contract.

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

In `@source/units/Goccia.HostEnvironment.Test.pas` around lines 114 - 121, Update
the test setup around ConfigureAsChildOf so ChildA and ChildB derive from the
same deterministic parent, then create a second equivalent parent and reproduce
both child positions from it. Assert the two sibling RandomDouble values are
distinct while the corresponding values from the second parent match, preserving
the existing deterministic expectations where applicable.
source/units/Goccia.HostEnvironment.JavaScript.pas (1)

197-206: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

DeriveStreamId implements only a partial SplitMix64 finalizer.

Canonical SplitMix64 does add-increment → (z^(z>>30))*C1 → (z^(z>>27))*C2 → z^(z>>31) (two multiply-xorshift rounds plus a final xorshift). This implementation stops after the first multiply-xorshift round and omits both the second multiplication (0x94D049BB133111EB) and the final xor (z shr 31), weakening avalanche/decorrelation between derived child stream IDs.

♻️ Align with the canonical SplitMix64 finalizer
+const
+  STREAM_HASH_MULTIPLIER_2 = QWord($94D049BB133111EB);
+
 class function TGocciaJavaScriptHostRandom.DeriveStreamId(
   const AParentStreamId, AChildStreamId: QWord): QWord;
 begin
   Result := (AParentStreamId xor STREAM_HASH_INCREMENT) + AChildStreamId;
   Result := (Result xor (Result shr 30)) * STREAM_HASH_MULTIPLIER;
-  Result := Result xor (Result shr 27);
+  Result := (Result xor (Result shr 27)) * STREAM_HASH_MULTIPLIER_2;
+  Result := Result xor (Result shr 31);
 end;

Based on the reference SplitMix64 implementation (z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; return z ^ (z >> 31);).

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

In `@source/units/Goccia.HostEnvironment.JavaScript.pas` around lines 197 - 206,
Update TGocciaJavaScriptHostRandom.DeriveStreamId to implement the complete
SplitMix64 finalizer: retain the increment and first multiply-xorshift, then add
the second multiply-xorshift using 0x94D049BB133111EB and finish with xor
against Result shifted right by 31. Preserve the existing overflow-check
suppression and QWord return behavior.
README.md (1)

105-116: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mention the --host-environment/--deterministic mutual exclusivity.

GocciaScriptLoader rejects combining --host-environment with --deterministic at the config-resolution step. This section documents both flags side by side without noting they're mutually exclusive, so a reader could try to combine them and hit a parse error with no warning here.

📝 Suggested addition
 For custom providers, pass a JavaScript module to `--host-environment` or implement the Pascal host interfaces. See [Host Environment](docs/host-environment.md) for both examples and the provider contract.
+
+`--host-environment` and `--deterministic` are mutually exclusive; deterministic mode always uses the pinned providers.

This may already be covered in docs/host-environment.md, which isn't in this review batch.

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

In `@README.md` around lines 105 - 116, Update the “Reproduce An Execution”
section to state that --host-environment and --deterministic are mutually
exclusive and cannot be combined. Clarify that GocciaScriptLoader rejects this
combination during configuration resolution, while preserving the existing
guidance for using either deterministic defaults or custom host providers.
🤖 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 `@source/units/Goccia.HostEnvironment.JavaScript.pas`:
- Around line 36-65: Root the provider callables before assigning them to the
fields in TGocciaJavaScriptHostClock and TGocciaJavaScriptHostRandom. Update
their constructors and lifetime management so each stored TGocciaValue remains
in the GC root set for as long as the host object may invoke it, and release the
roots when the corresponding object is destroyed.

In `@source/units/Goccia.HostEnvironment.pas`:
- Around line 170-176: The NextDouble method currently multiplies RandomBits as
Int64 directly by RANDOM_DOUBLE_SCALE, which can produce target-dependent
results. Convert RandomBits with Int64ToDouble before multiplying by
RANDOM_DOUBLE_SCALE, leaving the seeded state and mixing logic unchanged.

---

Nitpick comments:
In `@README.md`:
- Around line 105-116: Update the “Reproduce An Execution” section to state that
--host-environment and --deterministic are mutually exclusive and cannot be
combined. Clarify that GocciaScriptLoader rejects this combination during
configuration resolution, while preserving the existing guidance for using
either deterministic defaults or custom host providers.

In `@source/units/Goccia.HostEnvironment.JavaScript.pas`:
- Around line 197-206: Update TGocciaJavaScriptHostRandom.DeriveStreamId to
implement the complete SplitMix64 finalizer: retain the increment and first
multiply-xorshift, then add the second multiply-xorshift using
0x94D049BB133111EB and finish with xor against Result shifted right by 31.
Preserve the existing overflow-check suppression and QWord return behavior.

In `@source/units/Goccia.HostEnvironment.Test.pas`:
- Around line 114-121: Update the test setup around ConfigureAsChildOf so ChildA
and ChildB derive from the same deterministic parent, then create a second
equivalent parent and reproduce both child positions from it. Assert the two
sibling RandomDouble values are distinct while the corresponding values from the
second parent match, preserving the existing deterministic expectations where
applicable.
🪄 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: 5e57d7dc-8119-44af-b4d2-5ba0b9230093

📥 Commits

Reviewing files that changed from the base of the PR and between 2e32d9e and 293d785.

📒 Files selected for processing (30)
  • CONTEXT.md
  • README.md
  • docs/adr/0093-engine-owned-host-environment.md
  • docs/adr/README.md
  • docs/architecture.md
  • docs/build-system.md
  • docs/embedding.md
  • docs/host-environment.md
  • examples/custom-host-environment.js
  • scripts/test-cli-apps.ts
  • scripts/test-cli-config.ts
  • scripts/test-cli.ts
  • source/app/Goccia.CLI.Application.pas
  • source/app/Goccia.CLI.Options.pas
  • source/app/GocciaSandboxRunner.dpr
  • source/app/GocciaScriptLoader.dpr
  • source/app/GocciaScriptLoaderBare.dpr
  • source/units/Goccia.Builtins.GlobalShadowRealm.pas
  • source/units/Goccia.Builtins.Intl.pas
  • source/units/Goccia.Builtins.Math.pas
  • source/units/Goccia.Builtins.Performance.pas
  • source/units/Goccia.Builtins.Temporal.pas
  • source/units/Goccia.Engine.pas
  • source/units/Goccia.HostEnvironment.JavaScript.pas
  • source/units/Goccia.HostEnvironment.Test.pas
  • source/units/Goccia.HostEnvironment.pas
  • source/units/Goccia.RuntimeExtensions.Performance.pas
  • source/units/Goccia.Utils.pas
  • source/units/Goccia.Values.ArrayValue.pas
  • source/units/Goccia.Values.IntlDateTimeFormat.pas
💤 Files with no reviewable changes (1)
  • source/units/Goccia.Values.ArrayValue.pas

Comment thread source/units/Goccia.HostEnvironment.JavaScript.pas
Comment thread source/units/Goccia.HostEnvironment.pas Outdated
frostney added 2 commits July 14, 2026 20:57
Route seeded random bits through the shared Int64 conversion helper so
Free Pascal produces the same sequence across supported architectures.
@coderabbitai coderabbitai Bot added the internal Refactoring, CI, tooling, cleanup label Jul 14, 2026
@frostney
frostney merged commit 30c10eb into main Jul 15, 2026
48 checks passed
@frostney
frostney deleted the codex/issue-881-deterministic-execution branch July 15, 2026 10:35
@frostney frostney mentioned this pull request Jul 21, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation internal Refactoring, CI, tooling, cleanup new feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a deterministic execution mode (injectable clock + seeded RNG)

1 participant