Skip to content

Implement IsRegExp check via Symbol.match#624

Merged
frostney merged 4 commits into
mainfrom
t3code/issue-610-implementation
May 10, 2026
Merged

Implement IsRegExp check via Symbol.match#624
frostney merged 4 commits into
mainfrom
t3code/issue-610-implementation

Conversation

@frostney
Copy link
Copy Markdown
Owner

Summary

  • Implement the ES2026 §7.2.8 IsRegExp abstract operation, which detects regexp-like objects via Symbol.match instead of a property-based brand check.
  • Rename IsRegExpValueIsRegExpInstance for clarity: the brand check is now distinct from the spec's IsRegExp (Symbol.match lookup).
  • Update the RegExp constructor (new RegExp(...) and RegExp(...)) to use IsRegExp, so objects with a truthy Symbol.match have their .source/.flags read, and objects with a falsy Symbol.match are stringified.
  • Add IsRegExp guards to String.prototype.{startsWith, endsWith, includes} that throw TypeError for regexp-like arguments, per spec.
  • Update replaceAll/matchAll global-flag checks to use IsRegExp and read the flags property (per spec) instead of the .global accessor.
  • Closes RegExp constructor: implement IsRegExp check via Symbol.match #610

Testing

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

Replace IsRegExpValue with two distinct operations: IsRegExpInstance
(brand check for RegExp prototype methods) and IsRegExp (Symbol.match
lookup for the RegExp constructor and String.prototype guards). The
RegExp constructor now reads .source/.flags from any object with a
truthy Symbol.match, and String.prototype.{startsWith,endsWith,includes}
reject regexp-like arguments via the same check. The replaceAll/matchAll
global-flag guards now read the flags property per spec instead of the
.global accessor.

Closes #610

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 10, 2026

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 May 10, 2026 3:00pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 10, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 91e7e536-40c1-45c0-a207-f5be6b903909

📥 Commits

Reviewing files that changed from the base of the PR and between fda2c80 and 9972310.

📒 Files selected for processing (1)
  • source/units/Goccia.Values.StringObjectValue.pas
🚧 Files skipped from review as they are similar to previous changes (1)
  • source/units/Goccia.Values.StringObjectValue.pas

📝 Walkthrough

Walkthrough

This PR implements Symbol.match-based RegExp detection throughout the engine: replaces IsRegExpValue with IsRegExp/IsRegExpInstance, marks created RegExp objects, updates RegExp constructor/construct, updates RegExp.prototype receiver checks, adjusts String methods to validate/extract flags per spec, adds error strings, and extends tests.

Changes

RegExp Symbol.match Detection

Layer / File(s) Summary
RegExp Type Predicates
source/units/Goccia.RegExp.Runtime.pas, source/units/Goccia.Values.ObjectValue.pas
Introduces IsRegExpInstance (instance marker via HasRegExpData) and IsRegExp (checks Symbol.match then falls back to instance marker); CreateRegExpObject marks instances.
RegExp Constructor
source/units/Goccia.Builtins.GlobalRegExp.pas
RegExpConstructorFn and RegExpConstruct refactored to use IsRegExp for pattern detection, read PROP_SOURCE/PROP_FLAGS via PropVal, and handle non-construct/early-return paths.
RegExp Prototype Validation
source/units/Goccia.Builtins.GlobalRegExp.pas
RequireRegExpThis and RegExp.prototype methods (exec, test, toString, @@match, @@matchall, @@replace, @@search, @@split) now validate receivers with IsRegExpInstance.
String Methods Early Validation
source/units/Goccia.Values.StringObjectValue.pas
includes, startsWith, endsWith now throw TypeError when searchString is RegExp-like (IsRegExp) before coercion.
String Methods RegExp Dispatch
source/units/Goccia.Values.StringObjectValue.pas
replace, replaceAll, split, matchAll updated to detect RegExp-like via IsRegExp, extract/validate flags (throw on null/undefined), enforce 'g' when required, and use IsRegExpInstance for coercion/fast-paths.
Error Messages & Utilities
source/units/Goccia.Error.Messages.pas, source/units/Goccia.Error.Suggestions.pas, source/units/Goccia.REPL.Formatter.pas, source/units/Goccia.Builtins.TestingLibrary.pas
Added SErrorFirstArgMustNotBeRegExp and SSuggestUseMatchOrSearch; updated REPL formatter and TestingLibrary.ToMatch to use IsRegExpInstance.
Test Coverage
tests/built-ins/RegExp/constructor.js, tests/built-ins/String/prototype/{includes,startsWith,endsWith,replaceAll,matchAll}.js
New and extended tests validate RegExp constructor Symbol.match detection, String method early TypeError rejection, and global-flag validation for replaceAll/matchAll.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested labels

spec compliance, internal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: implementing the IsRegExp check via Symbol.match, which is the primary focus across all modified files.
Description check ✅ Passed The PR description follows the template structure with a clear Summary section and Testing checklist. It explains the change, links the related issue (#610), and documents which test categories were verified.
Linked Issues check ✅ Passed The PR fully implements the objectives from issue #610: replaces IsRegExpValue with IsRegExp (Symbol.match lookup) [#610], updates RegExp constructor to read .source/.flags from Symbol.match objects [#610], adds IsRegExp guards to String methods [#610], and updates global-flag checks [#610].
Out of Scope Changes check ✅ Passed All changes are directly related to implementing IsRegExp via Symbol.match: core RegExp runtime changes, constructor updates, String method guards, and comprehensive test coverage align with issue #610 scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

Suite Timing

Test Runner (interpreted: 9,242 passed; bytecode: 9,242 passed)
Metric Interpreted Bytecode
Total 9242 9242
Passed 9242 ✅ 9242 ✅
Workers 4 4
Test Duration 2.20s 2.20s
Lex (cumulative) 250.3ms 167.6ms
Parse (cumulative) 275.9ms 276.0ms
Compile (cumulative) 562.6ms
Execute (cumulative) 2.48s 2.21s
Engine Total (cumulative) 3.01s 3.22s
Lex (avg/worker) 62.6ms 41.9ms
Parse (avg/worker) 69.0ms 69.0ms
Compile (avg/worker) 140.7ms
Execute (avg/worker) 620.5ms 552.3ms
Engine Total (avg/worker) 752.1ms 803.8ms

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 244.45 MiB 238.88 MiB
GC Peak Live 244.46 MiB 238.89 MiB
GC Allocated During Run 248.36 MiB 242.77 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 1 1
GC Collected Objects 88 88
Heap Start Allocated 149.3 KiB 149.3 KiB
Heap End Allocated 2.54 MiB 2.54 MiB
Heap Delta Allocated 2.39 MiB 2.39 MiB
Heap Delta Free 140.1 KiB 140.1 KiB
Benchmarks (interpreted: 407; bytecode: 407)
Metric Interpreted Bytecode
Total 407 407
Workers 4 4
Duration 2.53min 2.41min

Memory

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

Metric Interpreted Bytecode
GC Live 3.65 MiB 3.64 MiB
GC Peak Live 110.22 MiB 77.56 MiB
GC Allocated During Run 16.88 GiB 9.80 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 2,829 2,638
GC Collected Objects 311,699,636 231,676,870
Heap Start Allocated 2.29 MiB 2.29 MiB
Heap End Allocated 2.29 MiB 2.29 MiB
Heap Delta Allocated 128 B 128 B

Measured on ubuntu-latest x64.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

Benchmark Results

407 benchmarks

Interpreted: 🟢 9 improved · 🔴 380 regressed · 18 unchanged · avg -12.2%
Bytecode: 🟢 132 improved · 🔴 27 regressed · 248 unchanged · avg +2.1%

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

Deterministic profile diff

Deterministic profile diff: no significant changes.

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

test262 Conformance

Category Run Passed Δ Pass Failed Pass-rate Δ Rate
built-ins 23,449 14,627 +20 8,818 62.4% +0.1pp
harness 116 71 ±0 45 61.2% ±0pp
intl402 3,324 691 ±0 2,633 20.8% ±0pp
language 23,635 12,575 ±0 11,060 53.2% ±0pp
staging 1,484 485 ±0 997 32.7% ±0pp
total 52,008 28,449 +20 23,553 54.7% ±0pp

Areas closest to 100%

Area Pass rate Δ vs main Passing
built-ins/WeakSet 98.8% ±0pp 84 / 85
built-ins/WeakMap 98.6% ±0pp 139 / 141
language/asi 97.1% ±0pp 99 / 102
Per-test deltas (+20 / -0)

Newly passing (20):

  • built-ins/Number/prototype/toExponential/undefined-fractiondigits.js
  • built-ins/RegExp/call_with_non_regexp_same_constructor.js
  • built-ins/RegExp/call_with_regexp_match_falsy.js
  • built-ins/RegExp/call_with_regexp_not_same_constructor.js
  • built-ins/RegExp/from-regexp-like-get-ctor-err.js
  • built-ins/RegExp/from-regexp-like-get-flags-err.js
  • built-ins/RegExp/from-regexp-like-short-circuit.js
  • built-ins/RegExp/prototype/no-regexp-matcher.js
  • built-ins/String/prototype/endsWith/return-abrupt-from-searchstring-regexp-test.js
  • built-ins/String/prototype/endsWith/searchstring-is-regexp-throws.js
  • built-ins/String/prototype/includes/return-abrupt-from-searchstring-regexp-test.js
  • built-ins/String/prototype/includes/searchstring-is-regexp-throws.js
  • built-ins/String/prototype/replaceAll/getSubstitution-0x0024-0x003C.js
  • built-ins/String/prototype/replaceAll/getSubstitution-0x0024N.js
  • built-ins/String/prototype/replaceAll/getSubstitution-0x0024NN.js
  • built-ins/String/prototype/replaceAll/searchValue-flags-null-undefined-throws.js
  • built-ins/String/prototype/replaceAll/searchValue-flags-toString-abrupt.js
  • built-ins/String/prototype/replaceAll/searchValue-tostring-regexp.js
  • built-ins/String/prototype/startsWith/return-abrupt-from-searchstring-regexp-test.js
  • built-ins/String/prototype/startsWith/searchstring-is-regexp-throws.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.

…l cleanup

- RegExpConstructorFn step 2b now checks pattern.constructor === RegExp
  before returning pattern as-is, per §22.2.3.1 step 2.b.i–ii.
- replaceAll/matchAll flag checks now throw TypeError via
  RequireObjectCoercible(flags) when flags is null/undefined, before
  the 'g' check, per §22.1.3.20 step 2.b.ii.
- matchAll caches AArgs.GetElement(0) in a local variable instead of
  re-evaluating it multiple times.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney marked this pull request as ready for review May 10, 2026 14:15
@coderabbitai coderabbitai Bot added spec compliance Mismatch against official JavaScript/TypeScript specification internal Refactoring, CI, tooling, cleanup labels May 10, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
source/units/Goccia.Values.StringObjectValue.pas (2)

126-141: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

CoerceRegExpValue no longer matches RegExpCreate semantics.

Switching this helper to IsRegExpInstance makes truthy-Symbol.match objects fall back to stringification instead of using their .source/.flags, and it still ignores ANewFlags for real RegExp instances. That breaks the fallback paths for String.prototype.match, matchAll, search, and split once the well-known symbol method is absent. A case like "abc".match({ source: "a", flags: "", [Symbol.match]: true }) will now build /[object Object]/ instead of /a/.

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

In `@source/units/Goccia.Values.StringObjectValue.pas` around lines 126 - 141,
CoerceRegExpValue must follow RegExpCreate semantics: when AValue is a real
RegExp instance or an object that claims to be a RegExp via a truthy
Symbol.match, use that object's .source and .flags rather than stringifying it;
only use CloneRegExpObject when AValue is a RegExp instance and ANewFlags is
empty — otherwise call CreateRegExpObject with the extracted source and either
ANewFlags (if provided) or the object's flags. Update CoerceRegExpValue to
detect RegExp instances (IsRegExpInstance) and Symbol.match-claiming objects,
extract .source/.flags, respect ANewFlags, and only fall back to ToStringLiteral
when neither case applies.

1089-1129: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t keep RegExp replacement semantics after @@replace lookup fails.

At this point GetMethod(searchValue, @@replace) has already returned undefined, so the spec fallback is the plain string-replacement path. This branch still performs regex replacement for actual RegExp instances, which makes const r = /a/; r[Symbol.replace] = undefined; "a".replace(r, "x") replace when it should treat r as the search string. The same issue is repeated in StringReplaceAllMethod below.

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

In `@source/units/Goccia.Values.StringObjectValue.pas` around lines 1089 - 1129,
The code treats any RegExp instance as needing RegExp replacement even when the
@@replace method lookup returned undefined; change the condition that enters the
RegExp branch so it only runs when the object's @@replace method is not
undefined (i.e. check the previously obtained ReplaceMethod or call
GetMethod(SearchArg, PROP_REPLACE) and ensure it is not nil/undefined before
doing the RegExp-specific logic in the current replace implementation and
likewise update StringReplaceAllMethod to use the same guard).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@source/units/Goccia.RegExp.Runtime.pas`:
- Around line 121-126: IsRegExpInstance is spoofable because it only checks
HasOwnProperty(PROP_SOURCE) and PROP_FLAGS; change it to test a real internal
brand/internal slot instead of public property presence: add an internal
non-enumerable marker (e.g., a hidden/internal flag on TGocciaObjectValue such
as FIsRegExp or a hidden PROP_REGEXP_BRAND) and update IsRegExpInstance to
return that internal flag (use a new TGocciaObjectValue method like
HasInternalFlag/IsRegExpBrand), then ensure the RegExp creation path (the RegExp
constructor/factory) sets that internal brand on instances while keeping it
non-writable and invisible to HasOwnProperty so ordinary objects like
{source,flags} cannot spoof it.

---

Outside diff comments:
In `@source/units/Goccia.Values.StringObjectValue.pas`:
- Around line 126-141: CoerceRegExpValue must follow RegExpCreate semantics:
when AValue is a real RegExp instance or an object that claims to be a RegExp
via a truthy Symbol.match, use that object's .source and .flags rather than
stringifying it; only use CloneRegExpObject when AValue is a RegExp instance and
ANewFlags is empty — otherwise call CreateRegExpObject with the extracted source
and either ANewFlags (if provided) or the object's flags. Update
CoerceRegExpValue to detect RegExp instances (IsRegExpInstance) and
Symbol.match-claiming objects, extract .source/.flags, respect ANewFlags, and
only fall back to ToStringLiteral when neither case applies.
- Around line 1089-1129: The code treats any RegExp instance as needing RegExp
replacement even when the @@replace method lookup returned undefined; change the
condition that enters the RegExp branch so it only runs when the object's
@@replace method is not undefined (i.e. check the previously obtained
ReplaceMethod or call GetMethod(SearchArg, PROP_REPLACE) and ensure it is not
nil/undefined before doing the RegExp-specific logic in the current replace
implementation and likewise update StringReplaceAllMethod to use the same
guard).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f46549b9-d4ed-45f5-a2fd-7c62309d2617

📥 Commits

Reviewing files that changed from the base of the PR and between 7cd1a08 and ab1f257.

📒 Files selected for processing (13)
  • source/units/Goccia.Builtins.GlobalRegExp.pas
  • source/units/Goccia.Builtins.TestingLibrary.pas
  • source/units/Goccia.Error.Messages.pas
  • source/units/Goccia.Error.Suggestions.pas
  • source/units/Goccia.REPL.Formatter.pas
  • source/units/Goccia.RegExp.Runtime.pas
  • source/units/Goccia.Values.StringObjectValue.pas
  • tests/built-ins/RegExp/constructor.js
  • tests/built-ins/String/prototype/endsWith.js
  • tests/built-ins/String/prototype/includes.js
  • tests/built-ins/String/prototype/matchAll.js
  • tests/built-ins/String/prototype/replaceAll.js
  • tests/built-ins/String/prototype/startsWith.js

Comment thread source/units/Goccia.RegExp.Runtime.pas Outdated
IsRegExpInstance now checks the internal HasRegExpData flag (set by
CreateRegExpObject) instead of probing for own source/flags properties.
Plain objects like {source: 'a', flags: ''} can no longer spoof a
RegExp instance past prototype method guards.

String.prototype.replace and replaceAll no longer fall through to regex
execution when @@replace is undefined — per §22.1.3.19 step 4, the
searchValue is ToString'd and treated as a plain string when the Symbol
method lookup fails.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
source/units/Goccia.Values.StringObjectValue.pas (2)

126-141: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Honor IsRegExp, not just branded instances, in fallback coercion.

This helper now stringifies regexp-like objects with a truthy Symbol.match unless they also carry the internal brand. That breaks the RegExpCreate-style fallback used by String.prototype.match, search, and matchAll, so inputs like { [Symbol.match]: true, source: 'a', flags: '' } no longer participate as regexes there.

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

In `@source/units/Goccia.Values.StringObjectValue.pas` around lines 126 - 141, The
fallback coercion in CoerceRegExpValue incorrectly checks only for branded
regexp instances via IsRegExpInstance, causing objects that are RegExp-like
(truthy Symbol.match) to be treated as strings; change the initial branch to use
IsRegExp(AValue) instead of IsRegExpInstance(AValue) so
CloneRegExpObject/CreateRegExpObject paths honor RegExp-like objects (e.g.,
objects with Symbol.match true and source/flags properties) when deciding
whether to clone or construct a RegExp.

1397-1437: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't keep regex semantics after @@split is absent.

By the time execution reaches this branch, GetMethod(separator, @@split) has already returned undefined. Spec fallback from there is string splitting, but this IsRegExpInstance path still executes regex splitting for branded regexes, so overriding or deleting Symbol.split on a RegExp instance won't take effect.

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

In `@source/units/Goccia.Values.StringObjectValue.pas` around lines 1397 - 1437,
This branch treats a separator as a RegExp even when its @@split method was
resolved to undefined earlier; ensure regex semantics are only used if the
object's GetMethod(separator, @@split) returned a callable. Modify the logic
around IsRegExpInstance / CoerceRegExpValue so that before calling
CoerceRegExpValue and MatchRegExpObjectValue you also check the
previously-resolved split method (Symbol.split/@@split) and skip this RegExp
branch when that method was undefined, preserving ordinary string-splitting
semantics when @@split was removed or overridden.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@source/units/Goccia.Values.StringObjectValue.pas`:
- Around line 126-141: The fallback coercion in CoerceRegExpValue incorrectly
checks only for branded regexp instances via IsRegExpInstance, causing objects
that are RegExp-like (truthy Symbol.match) to be treated as strings; change the
initial branch to use IsRegExp(AValue) instead of IsRegExpInstance(AValue) so
CloneRegExpObject/CreateRegExpObject paths honor RegExp-like objects (e.g.,
objects with Symbol.match true and source/flags properties) when deciding
whether to clone or construct a RegExp.
- Around line 1397-1437: This branch treats a separator as a RegExp even when
its @@split method was resolved to undefined earlier; ensure regex semantics are
only used if the object's GetMethod(separator, @@split) returned a callable.
Modify the logic around IsRegExpInstance / CoerceRegExpValue so that before
calling CoerceRegExpValue and MatchRegExpObjectValue you also check the
previously-resolved split method (Symbol.split/@@split) and skip this RegExp
branch when that method was undefined, preserving ordinary string-splitting
semantics when @@split was removed or overridden.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c72fcabd-f95c-4102-a61b-267f7685c1a3

📥 Commits

Reviewing files that changed from the base of the PR and between ab1f257 and fda2c80.

📒 Files selected for processing (4)
  • source/units/Goccia.RegExp.Runtime.pas
  • source/units/Goccia.Values.ObjectValue.pas
  • source/units/Goccia.Values.StringObjectValue.pas
  • tests/built-ins/RegExp/constructor.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/built-ins/RegExp/constructor.js

CoerceRegExpValue now checks IsRegExp (Symbol.match) instead of
IsRegExpInstance (brand), and reads .source/.flags with undefined
handling. ANewFlags is applied when provided, fixing the matchAll
fallback which previously ignored the forced 'g' flag on clones.

StringSplit no longer falls through to regex execution when @@split
is undefined — per §22.1.3.23 step 5, the separator is ToString'd
and used as a plain string delimiter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney merged commit e9de1f5 into main May 10, 2026
14 checks passed
@frostney frostney deleted the t3code/issue-610-implementation branch May 10, 2026 20:19
@coderabbitai coderabbitai Bot mentioned this pull request May 14, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal Refactoring, CI, tooling, cleanup spec compliance Mismatch against official JavaScript/TypeScript specification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RegExp constructor: implement IsRegExp check via Symbol.match

1 participant