Skip to content

refactor(engine): unify embedded-data caches onto a lock-free publication primitive#902

Merged
frostney merged 4 commits into
mainfrom
claude/distracted-mendeleev-034991
Jun 28, 2026
Merged

refactor(engine): unify embedded-data caches onto a lock-free publication primitive#902
frostney merged 4 commits into
mainfrom
claude/distracted-mendeleev-034991

Conversation

@frostney

@frostney frostney commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • Introduces TLazyPublishedCache<T> (source/shared/LazyPublishedCache.pas): a generic record that bundles Data + Loaded/Available flags + Lock and owns the lazy one-shot load plus barrier-correct lock-free publication (double-checked: WriteBarrier before publishing Loaded, matching ReadBarrier on the warm read) in a single Ensure(key, loader).
  • Migrates all eight embedded-data caches across five units onto it: TimeZone resource blob, CLDR resource blob, RegExp UCD blob + case-fold pairs + non-Unicode-uppercase pairs, identifier ID_Start/ID_Continue ranges, and the available-locale list. Each unit keeps a small per-cache loader; the barrier discipline now lives in one place and a mismatched (data, flag, lock) pairing is a compile-time error.
  • Generalizes the #813/perf(regexp): serve case-fold tables lock-free on the icase hot path #895 idiom: previously TimeZone/CLDR were unsynchronized (cold-load data race + publication gap on weakly-ordered targets), while the UCD blob, identifier ranges, and locale list were always-locked and copied their array out per call. Hot readers (identifier ranges, case-fold pairs) now read .Data in place via a const argument, so the lexer identifier path is lock-free and zero-copy.
  • A failed loader can no longer publish a partially-filled Data: Ensure clears the slot (Data := Default(T)) when the loader returns False, so a resource read that sizes its buffer before a failing ReadBuffer cannot leave a stale blob resident (addresses CodeRabbit review).
  • Constraints / non-goals: behavior-preserving — the only semantic change is publication ordering. TimeZone/CLDR additionally gain a one-shot cold-load lock (closes the data race) and now memoize load failure (previously retried). The weak-memory race is non-deterministic and not reproducible by a JavaScript test, so the primitive's functional contract is locked in by a Pascal gate instead. FPC lowers the barriers to dmb ishld/dmb ishst on AArch64 (verified) and to compiler barriers on x86 (TSO).
  • Scope note: IntlLocaleResolver (the available-locale list) is the same-shape cache surfaced by the issue's audit bullet, not named in the body/comment; included here and trivially separable. The audit excludes Goccia.Temporal.TimeZone's threadvar caches (per-thread, no cross-thread publication) and the ICU EnsureLoaded FFI binds (library-load, not an immutable data table).
  • Records the decision in ADR 0082 (renumbered as perf(engine): speed up FormatDouble shortest-representation scan #899/perf(vm): unbox typed-array element reads and writes in the bytecode VM #900 landed ADRs 0080/0081), including the rejected alternatives (per-unit duplication; two-phase no-callback API; concrete-only resource helper).

Closes #894

Testing

  • Verified no regressions and confirmed the new feature or bugfix in end-to-end JavaScript/TypeScript tests — full suite 11046/11046 (100%) in both interpreter and bytecode modes (after merging origin/main through perf(vm): unbox typed-array element reads and writes in the bytecode VM #900).
  • Updated documentation — ADR 0082 + index entry; the new primitive carries a full doc-comment. No user-facing API/behavior change, so language.md/built-ins.md are unaffected.
  • Optional: Verified no regressions and confirmed the new feature or bugfix in native Pascal tests — gate source/shared/LazyPublishedCache.Test.pas (load-once, memoize-failure, drops-partial-data-on-failure, key-passthrough, payload-agnostic) passes 5/5; full ./build.pas tests builds clean. ./format.pas --check: 376 files clean.
  • Optional: Verified no benchmark regressions or confirmed benchmark coverage for the change — not run; the change removes per-call locks/copies on the affected paths (no expected regression).

…tion primitive

#813 gave the RegExp case-fold tables a barrier-correct double-checked
publication, but the sibling embedded-data caches kept the old shapes: the
TimeZone and CLDR resource readers were unsynchronized (cold-load data race plus
a publication gap on weakly-ordered targets), while the UCD blob, the identifier
ID_Start/ID_Continue ranges, and the available-locale list entered a critical
section and copied their array out on every call.

Introduce TLazyPublishedCache<T> (source/shared/LazyPublishedCache.pas): a
generic record that bundles Data, the Loaded/Available flags and the Lock, and
owns the lazy one-shot load plus barrier-correct lock-free publication in one
Ensure(key, loader). All eight caches across five units now consume it via a
small per-cache loader; hot readers (identifier ranges, case-fold pairs) read
.Data in place via a const argument, so the lexer identifier path is now
lock-free and zero-copy. The barrier discipline lives in one place and a
mismatched (data, flag, lock) pairing is a compile-time error.

Behavior-preserving: full JS suite passes in both interpreter and bytecode
modes; TimeZone/CLDR additionally gain a cold-load lock and memoize load
failure. The weak-memory ordering is not JS-testable, so the primitive's
functional contract is locked in by the Pascal gate LazyPublishedCache.Test.
The audit excludes the TimeZone threadvar caches (per-thread) and the ICU
EnsureLoaded FFI binds (different shape). See ADR 0080.

Closes #894

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

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
gocciascript-homepage Ignored Ignored Preview Jun 28, 2026 6:16pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fcf911c9-bd61-48b5-83cd-d69b3f47cebf

📥 Commits

Reviewing files that changed from the base of the PR and between f7944a8 and 74a25c0.

📒 Files selected for processing (2)
  • docs/adr/0082-lazy-published-cache-primitive.md
  • docs/adr/README.md
💤 Files with no reviewable changes (1)
  • docs/adr/0082-lazy-published-cache-primitive.md
✅ Files skipped from review due to trivial changes (1)
  • docs/adr/README.md

📝 Walkthrough

Walkthrough

Introduces TLazyPublishedCache<T>, a new generic record in source/shared/LazyPublishedCache.pas implementing double-checked locking with memory barriers. Five engine units (Goccia.Identifier, Goccia.Intl.CLDRData, Goccia.RegExp.UnicodeData, Goccia.Temporal.TimeZoneData, IntlLocaleResolver) migrate their manual critical-section caches onto this primitive. A test suite and ADR 0082 are added.

Changes

TLazyPublishedCache primitive and migration

Layer / File(s) Summary
TLazyPublishedCache<T> definition and Ensure
source/shared/LazyPublishedCache.pas
Defines the generic record with TLoader callback type, Init/Done lifecycle, and Ensure implementing double-checked locking with ReadBarrier/WriteBarrier; resets Data to Default(T) on failed loads before publishing Loaded := True.
Test suite
source/shared/LazyPublishedCache.Test.pas
Five-case suite covering: load-once warm reads, memoized failure, partial-write-then-fail drops payload, key forwarding to loader, and generic type correctness across TBytes and array of Integer.
Goccia.Identifier migration
source/units/Goccia.Identifier.pas
Replaces IdentifierRangeLock and manual Loaded/Available state with IdentifierStartCache/IdentifierPartCache; rewrites IsIdentifierStart/PartCodePoint to call cache.Ensure and updates Init/Done lifecycle.
Goccia.Intl.CLDRData migration
source/units/Goccia.Intl.CLDRData.pas
Introduces CLDRResourceCache and LoadCLDRResource; rewrites TryReadEmbeddedResource to use cache.Ensure; adds Init/Done lifecycle under GOCCIA_INTL_EMBEDDED_CLDR.
Goccia.RegExp.UnicodeData migration
source/units/Goccia.RegExp.UnicodeData.pas
Replaces manual cached-resource bytes and EnsureEmbeddedPairsReady with UCDResourceCache, CaseFoldPairsCache, and NonUnicodeUppercasePairsCache; updates all lookup and reduction sites to read from *.Data; replaces critical-section Init/Done.
Goccia.Temporal.TimeZoneData migration
source/units/Goccia.Temporal.TimeZoneData.pas
Introduces TZResourceCache and LoadTZResource; rewrites TryReadEmbeddedResource to delegate to cache.Ensure; adds Init/Done lifecycle under GOCCIA_TEMPORAL_EMBEDDED_TZDATA.
IntlLocaleResolver migration
source/shared/IntlLocaleResolver.pas
Replaces AvailableLocalesCache/Loaded/Lock with TLazyPublishedCache<TStringArray>; introduces LoadAvailableLocales returning always-True; updates AvailableLocaleList and Init/Done lifecycle.
ADR 0082
docs/adr/0082-lazy-published-cache-primitive.md, docs/adr/README.md
Documents prior synchronization issues, the new barrier discipline, affected caches, and registers the ADR in the index.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • frostney/GocciaScript#778: Both PRs modify IntlLocaleResolver.pas's AvailableLocaleList load/cache mechanism and locale population logic.
  • frostney/GocciaScript#895: Both PRs modify Goccia.RegExp.UnicodeData.pas to provide a lock-free warm path for case-fold/uppercase pair tables using a "loaded published last" pattern.

Suggested labels

new feature, performance, internal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, specific, and accurately summarizes the main refactor to a lock-free publication primitive.
Description check ✅ Passed The description matches the template with Summary and Testing sections, includes constraints, issue link, and testing notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Suite Timing

Test Runner (interpreted: 11,046 passed; bytecode: 11,046 passed)
Metric Interpreted Bytecode
Total 11046 11046
Passed 11046 ✅ 11046 ✅
Workers 4 4
Test Duration 19.53s 15.12s
Lex (cumulative) 503.7ms 331.1ms
Parse (cumulative) 380.3ms 263.3ms
Compile (cumulative) 520.4ms
Execute (cumulative) 57.2ms 39.88s
Engine Total (cumulative) 941.2ms 40.99s
Lex (avg/worker) 125.9ms 82.8ms
Parse (avg/worker) 95.1ms 65.8ms
Compile (avg/worker) 130.1ms
Execute (avg/worker) 14.3ms 9.97s
Engine Total (avg/worker) 235.3ms 10.25s

Memory

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

Metric Interpreted Bytecode
GC Live 283.78 MiB 281.18 MiB
GC Peak Live 321.06 MiB 302.04 MiB
GC Allocated During Run 531.00 MiB 474.99 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 195 195
GC Collected Objects 2,605,578 2,172,695
Heap Start Allocated 182.6 KiB 182.6 KiB
Heap End Allocated 3.66 MiB 3.66 MiB
Heap Delta Allocated 3.48 MiB 3.48 MiB
Heap Delta Free 1.68 MiB 1.68 MiB
Benchmarks (interpreted: 437; bytecode: 437)
Metric Interpreted Bytecode
Total 437 437
Workers 4 4
Duration 3.01min 2.70min

Memory

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

Metric Interpreted Bytecode
GC Live 6.28 MiB 6.28 MiB
GC Peak Live 97.73 MiB 68.93 MiB
GC Allocated During Run 17.03 GiB 9.89 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 3,881 3,509
GC Collected Objects 268,493,932 225,438,474
Heap Start Allocated 3.36 MiB 3.36 MiB
Heap End Allocated 3.36 MiB 3.36 MiB
Heap Delta Allocated 128 B 128 B

Measured on ubuntu-latest x64.

@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

437 benchmarks · PR vs same-runner main build

Interpreted: 🟢 25 improved · 🔴 49 regressed · 363 unchanged · avg -0.4%
Bytecode: 🟢 32 improved · 🔴 34 regressed · 371 unchanged · avg +0.2%

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

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

Deterministic profile diff

Deterministic profile diff: no significant changes.

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

@frostney frostney marked this pull request as ready for review June 28, 2026 16:10
@coderabbitai coderabbitai Bot added internal Refactoring, CI, tooling, cleanup performance Performance improvement labels Jun 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
source/shared/LazyPublishedCache.Test.pas (1)

47-64: 🩺 Stability & Availability | 🔵 Trivial | 🏗️ Heavy lift

Add a cold-load contention test for the cache contract.

The suite covers sequential memoization, but not the PR’s core concurrency guarantee. Add a test where multiple threads call Ensure on the same cold cache and assert the loader ran once and every reader sees initialized data.

🤖 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/shared/LazyPublishedCache.Test.pas` around lines 47 - 64, The current
TLazyPublishedCacheTests suite covers warm reads and memoization but misses the
cold-load contention contract. Add a new test method in
TLazyPublishedCacheTests, register it in SetupTests, and use the existing Ensure
path on a shared cold cache from multiple threads to verify the loader executes
only once and every caller observes initialized data. Reuse the cache’s
published state and loader hooks so the test asserts both single execution and
correct visibility under contention.
🤖 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/shared/LazyPublishedCache.pas`:
- Around line 87-89: The shared cache publish path in LazyPublishedCache should
not let a failed loader leave partial data in the Data slot. Update the load
flow around the Available := ALoader(AKey, Data) call so the loader writes into
a temporary buffer and Data is assigned only when the load succeeds, or
explicitly clear Data before publishing a failure. Use the existing
LazyPublishedCache load/publish logic and the ALoader callback as the main
touchpoints.

---

Nitpick comments:
In `@source/shared/LazyPublishedCache.Test.pas`:
- Around line 47-64: The current TLazyPublishedCacheTests suite covers warm
reads and memoization but misses the cold-load contention contract. Add a new
test method in TLazyPublishedCacheTests, register it in SetupTests, and use the
existing Ensure path on a shared cold cache from multiple threads to verify the
loader executes only once and every caller observes initialized data. Reuse the
cache’s published state and loader hooks so the test asserts both single
execution and correct visibility under contention.
🪄 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: 52b2494d-71a0-4fbe-bebe-012a634f83cf

📥 Commits

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

📒 Files selected for processing (9)
  • docs/adr/0080-lazy-published-cache-primitive.md
  • docs/adr/README.md
  • source/shared/IntlLocaleResolver.pas
  • source/shared/LazyPublishedCache.Test.pas
  • source/shared/LazyPublishedCache.pas
  • source/units/Goccia.Identifier.pas
  • source/units/Goccia.Intl.CLDRData.pas
  • source/units/Goccia.RegExp.UnicodeData.pas
  • source/units/Goccia.Temporal.TimeZoneData.pas

Comment thread source/shared/LazyPublishedCache.pas
@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

test262 Conformance

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

Areas closest to 100%

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

Newly passing (2):

  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js
  • staging/sm/extensions/recursion.js

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

frostney and others added 3 commits June 28, 2026 17:35
…deleev-034991

# Conflicts:
#	docs/adr/README.md
CodeRabbit flagged that TLazyPublishedCache.Ensure let the loader write
straight into the shared Data slot before the outcome was known: a loader that
sized its payload and then failed (e.g. LoadTZResource sizing the byte buffer
before a failing ReadBuffer) left that partial blob resident for the process
lifetime, since Loaded stays True and the slot is never reloaded. Reads were
already gated on Available, so this was a memory-hygiene gap rather than a
correctness bug.

Clear Data (Data := Default(T)) whenever the loader returns False, before the
publish, so a failed load publishes an empty value. Fixing it in the primitive
covers every consumer's loader rather than patching each resource reader. Add a
LazyPublishedCache.Test case that fills a non-empty buffer then fails and
asserts the published Data is empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…deleev-034991

# Conflicts:
#	docs/adr/README.md
@coderabbitai coderabbitai Bot added the new feature New feature or request label Jun 28, 2026
@frostney frostney merged commit b42672c into main Jun 28, 2026
15 checks passed
@frostney frostney deleted the claude/distracted-mendeleev-034991 branch June 28, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal Refactoring, CI, tooling, cleanup new feature New feature or request performance Performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf/correctness: unify embedded-data caches onto barrier-correct lock-free publication

1 participant