Skip to content

Recognize LS/PS as line terminators in lexer (ES2026 §12.3)#285

Merged
frostney merged 3 commits into
mainfrom
fix/lexer-unicode-line-terminators
Apr 12, 2026
Merged

Recognize LS/PS as line terminators in lexer (ES2026 §12.3)#285
frostney merged 3 commits into
mainfrom
fix/lexer-unicode-line-terminators

Conversation

@frostney
Copy link
Copy Markdown
Owner

Summary

The lexer only recognized LF (U+000A) and CR (U+000D) as line terminators, missing LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029) required by ES2026 §12.3. Since FPC operates on AnsiString (UTF-8 bytes), LS/PS arrive as 3-byte sequences (E2 80 A8 / E2 80 A9) that a single-byte CharInSet check cannot detect.

  • Add IsLineTerminator / IsUnicodeLineTerminator / ConsumeUnicodeLineTerminator helpers with named UTF-8 byte constants
  • Update SkipHashbang (§12.5), SkipComment (§12.4), SkipWhitespace, and SkipBlockComment to handle all four spec-defined line terminators
  • Add ES2026 spec annotations to SkipHashbang and SkipComment

Testing

  • Existing hashbang tests extended with LS and PS line break variants
  • Existing line-number-preservation tests extended with LS and PS variants
  • New TestCommentTerminatedByUnicodeLineTerminators test added
  • All 3 lexer Pascal unit tests pass
  • All 267 Pascal unit tests pass (16 suites, zero failures)
  • All 5130 JavaScript end-to-end tests pass (zero regressions)

🤖 Generated with Claude Code

The lexer only recognized LF and CR as line terminators, missing the two
Unicode line terminators required by ES2026 §12.3. Since FPC operates on
AnsiString (UTF-8 bytes), LS/PS arrive as 3-byte sequences (E2 80 A8 /
E2 80 A9) that a single-byte CharInSet check cannot detect.

Add IsLineTerminator / IsUnicodeLineTerminator helpers and update
SkipHashbang (§12.5), SkipComment (§12.4), SkipWhitespace, and
SkipBlockComment to handle all four spec-defined line terminators.

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

coderabbitai Bot commented Apr 12, 2026

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: b8a5e2bd-34d0-460e-8353-3ef0486a1447

📥 Commits

Reviewing files that changed from the base of the PR and between adc2fd1 and d4dda44.

📒 Files selected for processing (1)
  • units/Goccia.Lexer.pas

📝 Walkthrough

Walkthrough

Adds ES2026 Unicode line-terminator support (U+2028/U+2029) to the lexer: recognizes UTF‑8 LS/PS and CR/CRLF as line terminators, updates line/column tracking, adjusts whitespace/hashbang/comment/template/regex scanning, and adds tests for CR, CRLF, and Unicode terminators.

Changes

Cohort / File(s) Summary
Lexer Implementation
units/Goccia.Lexer.pas
Added IsLineTerminator, IsUnicodeLineTerminator, ConsumeUnicodeLineTerminator and UTF‑8 LS/PS constants; updated SkipWhitespace, SkipHashbang, SkipComment, SkipBlockComment, ScanTemplate, and ScanRegexLiteral to treat CR/CRLF and UTF‑8 LS/PS as line terminators and to update FLine/FColumn correctly.
Lexer Tests
units/Goccia.Lexer.Test.pas
Added AssertCommentTerminatedBy helper and registered tests for Unicode line terminators (LS/PS), CR behavior in whitespace and block comments; extended existing hashbang tests to include CR and UTF‑8 LS/PS cases.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding support for LS/PS Unicode line terminators in the lexer per ES2026 specification.
Description check ✅ Passed The description covers all required template sections: clear summary with spec reference and implementation context, comprehensive testing checklist with all items marked complete, and linked issue.
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.

@coderabbitai coderabbitai Bot added bug Something isn't working spec compliance Mismatch against official JavaScript/TypeScript specification labels Apr 12, 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.

Caution

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

⚠️ Outside diff range comments (1)
units/Goccia.Lexer.pas (1)

228-235: ⚠️ Potential issue | 🟡 Minor

Handle standalone CR as a line terminator in line/column tracking.

Line 228 treats #13 (CR) as plain whitespace and only calls Advance, unlike #10 (LF) which increments FLine. This means a source with standalone CR line breaks advances position without updating FLine, causing incorrect line numbering for subsequent tokens. The same issue occurs in SkipBlockComment at line 293.

The IsLineTerminator function (line 199) correctly identifies CR as a line terminator, but the whitespace-skipping and comment-handling paths do not treat it as such. Implement CR handling consistently with ScanTemplate's pattern (lines 724–733): consume the CR (and optional following LF as a single break), then increment FLine.

Add regression coverage with explicit #13 inputs (both standalone and CRLF sequences) to ensure line tracking is correct.

Proposed fix
 procedure TGocciaLexer.SkipWhitespace;
 begin
   while not IsAtEnd do
   begin
     case Peek of
-      ' ', `#13`, `#9`:
+      ' ', `#9`:
         Advance;
+      `#13`:
+        begin
+          Advance;
+          if Peek = `#10` then
+            Advance;
+          Inc(FLine);
+          FColumn := 0;
+        end;
       `#10`:
         begin
           Inc(FLine);
           FColumn := 0;
           Advance;
         end;

Also in SkipBlockComment:

-    else if Peek = `#10` then
+    else if Peek = `#13` then
+    begin
+      Advance;
+      if Peek = `#10` then
+        Advance;
+      Inc(FLine);
+      FColumn := 0;
+    end
+    else if Peek = `#10` then
     begin
       Inc(FLine);
       FColumn := 0;
       Advance;
     end

Also applies to: 293–301

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@units/Goccia.Lexer.pas` around lines 228 - 235, Whitespace and comment
handling treats CR (`#13`) as plain whitespace and fails to increment FLine,
causing incorrect line numbers; update the whitespace-skipping branch (the case
handling ' ', `#13`, `#9` and the `#10` block) to treat CR like LF: consume CR,
increment FLine, reset FColumn, and if the next char is LF consume it as part of
the same break (mirror ScanTemplate logic from ScanTemplate around lines
724–733), and apply the same change inside SkipBlockComment so CR and CRLF both
advance the line counter correctly; ensure you use Advance, Inc(FLine) and
FColumn := 0 in the updated branches and add regression tests feeding standalone
`#13` and CRLF sequences to validate line/column tracking.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@units/Goccia.Lexer.pas`:
- Around line 228-235: Whitespace and comment handling treats CR (`#13`) as plain
whitespace and fails to increment FLine, causing incorrect line numbers; update
the whitespace-skipping branch (the case handling ' ', `#13`, `#9` and the `#10`
block) to treat CR like LF: consume CR, increment FLine, reset FColumn, and if
the next char is LF consume it as part of the same break (mirror ScanTemplate
logic from ScanTemplate around lines 724–733), and apply the same change inside
SkipBlockComment so CR and CRLF both advance the line counter correctly; ensure
you use Advance, Inc(FLine) and FColumn := 0 in the updated branches and add
regression tests feeding standalone `#13` and CRLF sequences to validate
line/column tracking.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9efce9d8-01d6-4287-ac3c-fb530592b4e2

📥 Commits

Reviewing files that changed from the base of the PR and between b5ab652 and 5e7011f.

📒 Files selected for processing (2)
  • units/Goccia.Lexer.Test.pas
  • units/Goccia.Lexer.pas

SkipWhitespace treated CR (#13) as plain whitespace without incrementing
FLine, causing incorrect line numbers after standalone CR line endings.
SkipBlockComment had the same gap — CR inside a block comment did not
advance the line counter.

Split CR out of the whitespace branch and mirror the ScanTemplate
pattern: consume CR, optionally consume a following LF (so CRLF counts
as a single line break), then increment FLine and reset FColumn.

Add regression tests feeding standalone CR and CRLF sequences to both
whitespace and block-comment contexts and verifying line/column tracking.

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

github-actions Bot commented Apr 12, 2026

Benchmark Results

364 benchmarks

Interpreted: 🟢 76 improved · 🔴 202 regressed · 86 unchanged · avg -2.1%
Bytecode: 🟢 34 improved · 🔴 183 regressed · 147 unchanged · avg -1.3%

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

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 Apr 12, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 5218 5218
Tests Passed 5177 ✅ 5218 ✅
Tests Skipped 41 0
Tests Test Duration 385.1ms 340.9ms
Tests Lex 101.0ms 69.9ms
Tests Parse 132.8ms 135.5ms
Tests Compile 80.0ms
Tests Execute 404.2ms 378.0ms
Tests Engine Total 638.1ms 663.4ms
Benchmarks Total 364 364
Benchmarks Duration 9.92min 8.22min

Measured on ubuntu-latest x64.

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: 2

🧹 Nitpick comments (1)
units/Goccia.Lexer.pas (1)

216-220: Name the UTF-8 sequence length instead of inlining 3.

Inc(FCurrent, 3) is part of the LS/PS encoding contract too. A UTF8_LINE_TERMINATOR_BYTE_COUNT constant would keep this helper consistent with the byte constants above.

As per coding guidelines, "Extract bare numeric literals in implementation sections into named constants; only trivial self-explanatory literals (0, 1, -1, '', True, False) may be left as-is."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@units/Goccia.Lexer.pas` around lines 216 - 220, Replace the magic literal in
TGocciaLexer.ConsumeUnicodeLineTerminator with a named constant: define
UTF8_LINE_TERMINATOR_BYTE_COUNT (value 3) in the implementation section (near
the other UTF-8/LS/PS byte constants) and use Inc(FCurrent,
UTF8_LINE_TERMINATOR_BYTE_COUNT) so the method
(TGocciaLexer.ConsumeUnicodeLineTerminator) and the LS/PS encoding contract
consistently reference the same symbolic byte-count constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@units/Goccia.Lexer.pas`:
- Around line 193-221: The regex and template scanners (ScanRegexLiteral and
ScanTemplate) still only treat `#10/`#13 as line terminators; update them to use
the new helpers so they recognize U+2028/U+2029 too: replace direct checks for
`#10/`#13 with calls to IsLineTerminator, and when a terminator is found,
increment position/line using the existing ConsumeUnicodeLineTerminator for
multi-byte Unicode terminators or the existing single-byte logic for LF/CR
(update FLine and FColumn accordingly). Ensure ScanRegexLiteral raises an error
when IsLineTerminator is true inside the regex body, and ensure ScanTemplate
updates FLine/FColumn via the same branching so raw U+2028/U+2029 are treated
consistently.
- Around line 207-213: Add an explicit short-circuit evaluation directive and
replace the magic UTF‑8 byte-count literal with a named constant: add {$B-} to
the unit header or Goccia.inc to ensure boolean short-circuiting for safety in
TGocciaLexer.IsUnicodeLineTerminator, and declare a constant (e.g.
UTF8_LS_PS_BYTE_ADVANCE = 3) and use that constant wherever Inc(FCurrent, 3) is
used so the UTF‑8 byte-advance semantics are clear and maintainable.

---

Nitpick comments:
In `@units/Goccia.Lexer.pas`:
- Around line 216-220: Replace the magic literal in
TGocciaLexer.ConsumeUnicodeLineTerminator with a named constant: define
UTF8_LINE_TERMINATOR_BYTE_COUNT (value 3) in the implementation section (near
the other UTF-8/LS/PS byte constants) and use Inc(FCurrent,
UTF8_LINE_TERMINATOR_BYTE_COUNT) so the method
(TGocciaLexer.ConsumeUnicodeLineTerminator) and the LS/PS encoding contract
consistently reference the same symbolic byte-count constant.
🪄 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: 1693dc09-d483-41f2-a152-f0712fd39471

📥 Commits

Reviewing files that changed from the base of the PR and between 5e7011f and adc2fd1.

📒 Files selected for processing (2)
  • units/Goccia.Lexer.Test.pas
  • units/Goccia.Lexer.pas
✅ Files skipped from review due to trivial changes (1)
  • units/Goccia.Lexer.Test.pas

Comment thread units/Goccia.Lexer.pas
Comment thread units/Goccia.Lexer.pas
ScanRegexLiteral only rejected LF inside regex bodies; now checks
IsLineTerminator before each character so CR, LS, and PS also raise
"Unterminated regular expression literal" per ES2026 §12.9.5.

ScanTemplate only tracked CR and LF for line counting; add a LS/PS
branch that preserves the original code point in both TV and TRV
(ES2026 §12.9.6) and increments the line counter.

Extract UTF8_LINE_TERMINATOR_BYTE_LENGTH constant for the magic 3 in
ConsumeUnicodeLineTerminator.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney merged commit 8c5ad7e into main Apr 12, 2026
54 checks passed
@frostney frostney deleted the fix/lexer-unicode-line-terminators branch April 12, 2026 18:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working spec compliance Mismatch against official JavaScript/TypeScript specification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant