Skip to content

Add TextEncoder and TextDecoder built-ins#272

Merged
frostney merged 4 commits intomainfrom
feature/text-encoder-decoder
Apr 11, 2026
Merged

Add TextEncoder and TextDecoder built-ins#272
frostney merged 4 commits intomainfrom
feature/text-encoder-decoder

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Apr 11, 2026

Summary

  • Added TextEncoder and TextDecoder globals with native constructors, prototype exposure, and toStringTag support.
  • Implemented TextEncoder.prototype.encode, TextEncoder.prototype.encodeInto, and TextDecoder.prototype.decode with UTF-8 handling and BOM/fatal option support.
  • Registered the new constructor/property names in the shared constants and wired both built-ins into engine initialization.
  • Added end-to-end tests covering constructor behavior, encoding/decoding paths, options, and error cases.

Testing

  • Existing test coverage added for tests/built-ins/TextEncoder/** and tests/built-ins/TextDecoder/**.
  • Manual checks implied by the diff: constructor creation, UTF-8 encoding/decoding, encodeInto boundary handling, BOM stripping, and fatal-mode errors.

Implements the WHATWG Encoding §8 TextEncoder and TextDecoder APIs.

TextEncoder (always UTF-8):
- encode(string) → Uint8Array
- encodeInto(string, Uint8Array) → {read, written}
- encoding getter → 'utf-8'

TextDecoder (UTF-8 only; RangeError for other labels):
- new TextDecoder([label, {fatal, ignoreBOM}])
- decode([BufferSource]) → string
- encoding, fatal, ignoreBOM getters
- UTF-8 BOM stripping (EF BB BF) unless ignoreBOM is set
- Fatal mode: validates byte sequences and throws TypeError on invalid UTF-8

Both are in DefaultGlobals and registered via the standard
RegisterBuiltinConstructors/RegisterTypeDefinition pipeline.

69 new tests across 9 files covering constructor, encode, encodeInto,
decode, encoding/fatal/ignoreBOM getters.

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

coderabbitai Bot commented Apr 11, 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: b416cbfd-8f81-47d6-8098-7b3e0660f67c

📥 Commits

Reviewing files that changed from the base of the PR and between 5f877bb and bee404c.

📒 Files selected for processing (5)
  • tests/built-ins/TextDecoder/prototype/decode.js
  • tests/built-ins/TextEncoder/prototype/encode.js
  • tests/built-ins/TextEncoder/prototype/encoding.js
  • units/Goccia.Values.TextDecoderValue.pas
  • units/Goccia.Values.TextEncoderValue.pas
✅ Files skipped from review due to trivial changes (1)
  • tests/built-ins/TextEncoder/prototype/encoding.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/built-ins/TextEncoder/prototype/encode.js
  • tests/built-ins/TextDecoder/prototype/decode.js

📝 Walkthrough

Walkthrough

Adds WHATWG-style TextEncoder and TextDecoder: constructors, prototypes (encode/encodeInto/decode), accessor properties (encoding, fatal, ignoreBOM), engine/bootstrap registration, class/value implementations, and comprehensive Jest tests for behavior and error cases.

Changes

Cohort / File(s) Summary
TextDecoder tests
tests/built-ins/TextDecoder/constructor.js, tests/built-ins/TextDecoder/prototype/decode.js, tests/built-ins/TextDecoder/prototype/encoding.js, tests/built-ins/TextDecoder/prototype/fatal.js, tests/built-ins/TextDecoder/prototype/ignoreBOM.js
New test suites covering constructor behavior, label normalization, fatal/ignoreBOM accessors, decode semantics (BOM handling, valid/invalid UTF‑8, buffer/typed-array inputs) and prototype descriptors.
TextEncoder tests
tests/built-ins/TextEncoder/constructor.js, tests/built-ins/TextEncoder/prototype/encode.js, tests/built-ins/TextEncoder/prototype/encodeInto.js, tests/built-ins/TextEncoder/prototype/encoding.js
New tests for constructor, encoding accessor, encode (ASCII/multibyte/surrogate handling) and encodeInto (boundary/truncation/read/written semantics and error cases).
Constructor/Property constants
units/Goccia.Constants.ConstructorNames.pas, units/Goccia.Constants.PropertyNames.pas
Added CONSTRUCTOR_TEXT_ENCODER/CONSTRUCTOR_TEXT_DECODER and property-name constants (encoding, fatal, ignoreBOM, encode, encodeInto, decode).
Value implementations
units/Goccia.Values.TextEncoderValue.pas, units/Goccia.Values.TextDecoderValue.pas
New native instance classes: TextEncoder implements encoding, encode, encodeInto; TextDecoder implements constructor arg parsing, encoding normalization (UTF‑8 only), accessors, decode with BOM handling and optional fatal validation, and ToStringTag.
Global builtins
units/Goccia.Builtins.GlobalTextEncoder.pas, units/Goccia.Builtins.GlobalTextDecoder.pas
New builtin classes that register native constructor functions and expose the corresponding prototypes.
Engine/bootstrap wiring
units/Goccia.Engine.pas, units/Goccia.Runtime.Bootstrap.pas, units/Goccia.Values.ClassValue.pas
Engine and bootstrap updated to include new global flags, register constructors/types, add class-value factories, expose prototypes, and manage builtin allocation/lifetime.

Sequence Diagram(s)

sequenceDiagram
    participant JS as JS caller
    participant Global as GlobalConstructor (TextDecoder)
    participant Engine as Engine/BuiltinRegistrar
    participant Instance as TextDecoderInstance
    participant Validator as UTF8Validator

    JS->>Global: new TextDecoder(label?, options?)
    Global->>Engine: request create instance
    Engine->>Instance: InitializeNativeFromArguments(label, options)
    JS->>Instance: instance.decode(buffer)
    Instance->>Validator: (if fatal) validate UTF-8 / strip BOM
    Validator-->>Instance: validated or throws
    Instance-->>JS: return decoded JS string
Loading

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 TextEncoder and TextDecoder as global built-ins.
Description check ✅ Passed The description includes most required sections but lacks explicit testing checklist confirmation. The summary, implementation details, and testing notes are present but testing checkboxes are not marked.
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 new feature New feature or request spec compliance Mismatch against official JavaScript/TypeScript specification labels Apr 11, 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: 4

🧹 Nitpick comments (2)
units/Goccia.Builtins.GlobalTextDecoder.pas (1)

35-37: Replace hardcoded constructor name with shared constant.

Line 36 hardcodes 'TextDecoder'; use CONSTRUCTOR_TEXT_DECODER for consistency and drift prevention.

♻️ Proposed refactor
 uses
   Goccia.Arguments.Collection,
   Goccia.Builtins.Base,
+  Goccia.Constants.ConstructorNames,
   Goccia.Error.ThrowErrorCallback,
   Goccia.Scope,
   Goccia.Values.NativeFunction,
   Goccia.Values.Primitives,
   Goccia.Values.TextDecoderValue;
@@
   FTextDecoderConstructor := TGocciaNativeFunctionValue.Create(
-    TextDecoderConstructorFn, 'TextDecoder', 0);
+    TextDecoderConstructorFn, CONSTRUCTOR_TEXT_DECODER, 0);

As per coding guidelines, use runtime constant units instead of hardcoded string literals for constructor names (Goccia.Constants.ConstructorNames).

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

In `@units/Goccia.Builtins.GlobalTextDecoder.pas` around lines 35 - 37, Replace
the hardcoded constructor name string in the TGocciaNativeFunctionValue.Create
call with the shared constant; change the second argument passed in the
FTextDecoderConstructor initialization (where
TGocciaNativeFunctionValue.Create(TextDecoderConstructorFn, 'TextDecoder', 0) is
used) to use CONSTRUCTOR_TEXT_DECODER from Goccia.Constants.ConstructorNames,
and keep the subsequent
TGocciaTextDecoderValue.ExposePrototype(FTextDecoderConstructor) call unchanged
so the prototype exposure still references the same FTextDecoderConstructor.
units/Goccia.Values.TextDecoderValue.pas (1)

209-210: Replace hardcoded prototype method name with property-name constant

Line 209 uses 'decode' as a literal in AddNamedMethod. Please source this from Goccia.Constants.PropertyNames (e.g., PROP_DECODE) to keep runtime names centralized.

🔧 Suggested change
-      Members.AddNamedMethod('decode', Decode, 1, gmkPrototypeMethod,
+      Members.AddNamedMethod(PROP_DECODE, Decode, 1, gmkPrototypeMethod,
         [gmfNoFunctionPrototype]);

As per coding guidelines, use runtime constant units instead of hardcoded string literals: Goccia.Constants.PropertyNames for property names.

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

In `@units/Goccia.Values.TextDecoderValue.pas` around lines 209 - 210, Replace the
hardcoded 'decode' literal passed to Members.AddNamedMethod with the centralized
property-name constant: use Goccia.Constants.PropertyNames.PROP_DECODE (or the
equivalent exported constant) instead of the string; update the call where
Members.AddNamedMethod('decode', Decode, 1, gmkPrototypeMethod,
[gmfNoFunctionPrototype]) to reference PROP_DECODE so the runtime name for the
Decode method is sourced from the Goccia.Constants.PropertyNames unit and stays
consistent.
🤖 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.Builtins.GlobalTextEncoder.pas`:
- Around line 35-37: Replace the hardcoded 'TextEncoder' literal passed to
TGocciaNativeFunctionValue.Create with the shared constant
CONSTRUCTOR_TEXT_ENCODER from Goccia.Constants.ConstructorNames: locate where
FTextEncoderConstructor is initialized (the call to
TGocciaNativeFunctionValue.Create with TextEncoderConstructorFn) and change the
second argument to use the constant, then keep the subsequent
TGocciaTextEncoderValue.ExposePrototype(FTextEncoderConstructor) intact so the
prototype registration still uses the same constructor symbol.

In `@units/Goccia.Values.TextDecoderValue.pas`:
- Around line 154-193: Replace the manual argument checks in
TGocciaTextDecoderValue.InitializeNativeFromArguments with
TGocciaArgumentValidator usage: use the validator to read/validate the optional
label as a string and the optional options as an object (or undefined), then if
the validated label is present call NormalizeEncodingLabel and assign FEncoding
(throw on empty), and if the validated options object is present read PROP_FATAL
and PROP_IGNORE_BOM and assign FFatal and FIgnoreBOM accordingly; remove the
explicit instance/type checks and use TGocciaArgumentValidator methods to
centralize validation while keeping PROP_FATAL, PROP_IGNORE_BOM, FEncoding,
FFatal and FIgnoreBOM as the target fields.
- Around line 110-136: The current UTF-8 validation loop only checks
continuation-byte form and thus allows overlong, surrogate and out-of-range
sequences; update the decoder routine that contains variables I, SeqLen, B,
AData, AOffset, ALength and Result to enforce stricter initial-byte dependent
checks: after computing SeqLen and before accepting the sequence, read the
second continuation byte (AData[I+1]) and add these guards—if SeqLen=3 then if
B=$E0 ensure AData[I+1] >= $A0; if B=$ED ensure AData[I+1] <= $9F; if SeqLen=4
then if B=$F0 ensure AData[I+1] >= $90; if B=$F4 ensure AData[I+1] <= $8F; keep
the existing continuation-byte loop and still fail (Result:=False; Exit) when
any of these guards are violated so overlong, surrogate and >U+10FFFF sequences
are rejected.

In `@units/Goccia.Values.TextEncoderValue.pas`:
- Around line 56-65: The StringToUTF8Bytes helper (used by Encode and EncodeInto
when reading ToStringLiteral.Value) does raw byte copying and does not perform
USVString normalization, so lone surrogates are encoded incorrectly; update the
flow to normalize to a well-formed scalar-value string before UTF-8 conversion
either by adding a normalization step to StringToUTF8Bytes (iterating code units
and replacing lone surrogates with U+FFFD, similar to
StringObjectValue.toWellFormed) or by calling that normalization from Encode and
EncodeInto prior to calling StringToUTF8Bytes; ensure you reference the existing
toWellFormed logic in StringObjectValue.pas to implement the surrogate-to-FFFD
replacement so inputs like "\uD800" produce the UTF-8 for U+FFFD.

---

Nitpick comments:
In `@units/Goccia.Builtins.GlobalTextDecoder.pas`:
- Around line 35-37: Replace the hardcoded constructor name string in the
TGocciaNativeFunctionValue.Create call with the shared constant; change the
second argument passed in the FTextDecoderConstructor initialization (where
TGocciaNativeFunctionValue.Create(TextDecoderConstructorFn, 'TextDecoder', 0) is
used) to use CONSTRUCTOR_TEXT_DECODER from Goccia.Constants.ConstructorNames,
and keep the subsequent
TGocciaTextDecoderValue.ExposePrototype(FTextDecoderConstructor) call unchanged
so the prototype exposure still references the same FTextDecoderConstructor.

In `@units/Goccia.Values.TextDecoderValue.pas`:
- Around line 209-210: Replace the hardcoded 'decode' literal passed to
Members.AddNamedMethod with the centralized property-name constant: use
Goccia.Constants.PropertyNames.PROP_DECODE (or the equivalent exported constant)
instead of the string; update the call where Members.AddNamedMethod('decode',
Decode, 1, gmkPrototypeMethod, [gmfNoFunctionPrototype]) to reference
PROP_DECODE so the runtime name for the Decode method is sourced from the
Goccia.Constants.PropertyNames unit and stays consistent.
🪄 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: 83a8c19c-709d-4d2c-b4f3-b0194b3c3545

📥 Commits

Reviewing files that changed from the base of the PR and between e4e09c5 and 38ffad7.

📒 Files selected for processing (17)
  • tests/built-ins/TextDecoder/constructor.js
  • tests/built-ins/TextDecoder/prototype/decode.js
  • tests/built-ins/TextDecoder/prototype/encoding.js
  • tests/built-ins/TextDecoder/prototype/fatal.js
  • tests/built-ins/TextDecoder/prototype/ignoreBOM.js
  • tests/built-ins/TextEncoder/constructor.js
  • tests/built-ins/TextEncoder/prototype/encode.js
  • tests/built-ins/TextEncoder/prototype/encodeInto.js
  • tests/built-ins/TextEncoder/prototype/encoding.js
  • units/Goccia.Builtins.GlobalTextDecoder.pas
  • units/Goccia.Builtins.GlobalTextEncoder.pas
  • units/Goccia.Constants.ConstructorNames.pas
  • units/Goccia.Constants.PropertyNames.pas
  • units/Goccia.Engine.pas
  • units/Goccia.Values.ClassValue.pas
  • units/Goccia.Values.TextDecoderValue.pas
  • units/Goccia.Values.TextEncoderValue.pas

Comment thread units/Goccia.Builtins.GlobalTextEncoder.pas
Comment thread units/Goccia.Values.TextDecoderValue.pas
Comment thread units/Goccia.Values.TextDecoderValue.pas
Comment thread units/Goccia.Values.TextEncoderValue.pas Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 11, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 4698 4698
Tests Passed 4657 ✅ 4698 ✅
Tests Skipped 41 0
Tests Test Duration 388.7ms 324.9ms
Tests Lex 87.9ms 61.9ms
Tests Parse 119.1ms 119.4ms
Tests Compile 73.9ms
Tests Execute 405.4ms 356.3ms
Tests Engine Total 612.4ms 611.5ms
Benchmarks Total 364 364
Benchmarks Duration 10.29min 8.52min

Measured on ubuntu-latest x64.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 11, 2026

Benchmark Results

364 benchmarks

Interpreted: 🟢 243 improved · 🔴 54 regressed · 67 unchanged · avg +3.9%
Bytecode: 🟢 80 improved · 🔴 123 regressed · 161 unchanged · avg -0.7%

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

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.

frostney and others added 2 commits April 11, 2026 18:19
The WHATWG Encoding built-ins were only registered in TGocciaEngine
(interpreter path). The bytecode backend uses TGocciaRuntimeBootstrap
as its shared initialization layer, so TextEncoder/TextDecoder were
undefined in --mode=bytecode.

Mirror all six registration steps into Goccia.Runtime.Bootstrap.pas:
interface uses, field declarations, destructor cleanup, RegisterBuiltIns
creation, ExposePrototype helpers, and RegisterBuiltinConstructors
TypeDef registrations.

All 69 TextEncoder/TextDecoder tests now pass in both interpreted and
bytecode execution modes.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…dUTF8

Four actionable issues from CodeRabbit PR #272:

1. Replace hardcoded 'TextEncoder'/'TextDecoder' string literals in
   GlobalTextEncoder/GlobalTextDecoder constructors with
   CONSTRUCTOR_TEXT_ENCODER / CONSTRUCTOR_TEXT_DECODER from
   Goccia.Constants.ConstructorNames — prevents drift across registration paths.

2. Add PROP_ENCODE, PROP_ENCODE_INTO, PROP_DECODE to
   Goccia.Constants.PropertyNames and use them in AddNamedMethod calls
   in TextEncoderValue and TextDecoderValue.

3. Fix IsValidUTF8: add missing second-byte range checks required by
   RFC 3629 to reject overlong sequences (E0 < A0, F0 < 90), UTF-16
   surrogates (ED > 9F), and code points above U+10FFFF (F4 > 8F).
   Fatal mode now correctly rejects E0 80 80, ED A0 80, F0 80 80 80,
   F4 90 80 80 and similar sequences. Six new tests verify this.

4. Fix StringToUTF8Bytes: normalise lone surrogates (U+D800-U+DFFF,
   encoded as ED A0-BF xx in WTF-8/CESU-8) to U+FFFD (EF BF BD) per
   WHATWG Encoding §8.3.2 USVString requirement. Replacement is in-place
   since both encodings are exactly 3 bytes. Two new tests verify this.

Skipped: TGocciaArgumentValidator refactor — that class only validates
argument counts; the manual checks in InitializeNativeFromArguments
perform type/value validation on optional arguments where count
validation alone would not help.

Co-Authored-By: Claude Sonnet 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.

Actionable comments posted: 2

🤖 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.Values.TextDecoderValue.pas`:
- Around line 355-364: The current decode path bypasses validation when
Obj.FFatal is false and casts raw bytes to UTF8String, which does not implement
U+FFFD replacement for malformed sequences; replace that branch with a proper
UTF‑8 decoding routine that produces replacement characters for ill-formed
sequences (e.g., call or implement a helper like DecodeUTF8WithReplacement(Data,
Offset, DataLen) instead of raw string(U8)), keep the fatal branch using
IsValidUTF8/ThrowTypeError, and return the decoded string via
TGocciaStringLiteralValue.Create; also add explicit assertions in
tests/built-ins/TextDecoder/prototype/decode.js to verify replacement behavior
(e.g., new TextDecoder().decode(new Uint8Array([0xFF])) === "\uFFFD").

In `@units/Goccia.Values.TextEncoderValue.pas`:
- Around line 181-276: The prototype methods EncodingGetter, Encode and
EncodeInto must reject non-TextEncoder receivers: at the start of
TGocciaTextEncoderValue.EncodingGetter, TGocciaTextEncoderValue.Encode and
TGocciaTextEncoderValue.EncodeInto check that AThisValue is a
TGocciaTextEncoderValue (or use the same illegal-invocation guard used in
TextDecoder) and call ThrowTypeError with an "Illegal invocation" message when
it is not; add this guard before any use of AThisValue so detached calls like
TextEncoder.prototype.encode.call({}) throw instead of proceeding.
🪄 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: 64b8cab8-7f99-4f48-83ca-dbaca88991bb

📥 Commits

Reviewing files that changed from the base of the PR and between 38ffad7 and 5f877bb.

📒 Files selected for processing (8)
  • tests/built-ins/TextDecoder/prototype/decode.js
  • tests/built-ins/TextEncoder/prototype/encode.js
  • units/Goccia.Builtins.GlobalTextDecoder.pas
  • units/Goccia.Builtins.GlobalTextEncoder.pas
  • units/Goccia.Constants.PropertyNames.pas
  • units/Goccia.Runtime.Bootstrap.pas
  • units/Goccia.Values.TextDecoderValue.pas
  • units/Goccia.Values.TextEncoderValue.pas
✅ Files skipped from review due to trivial changes (3)
  • units/Goccia.Builtins.GlobalTextDecoder.pas
  • tests/built-ins/TextEncoder/prototype/encode.js
  • units/Goccia.Constants.PropertyNames.pas

Comment thread units/Goccia.Values.TextDecoderValue.pas Outdated
Comment thread units/Goccia.Values.TextEncoderValue.pas
… receiver guards

Two new actionable comments from CodeRabbit on PR #272:

1. Non-fatal decode mode now implements WHATWG U+FFFD replacement semantics
   (TextDecoderValue.pas line 364).

   The previous implementation did a raw byte copy in non-fatal mode, which
   passes invalid bytes through unchanged instead of replacing them with
   U+FFFD as the WHATWG Encoding §4.1 spec requires.

   Added DecodeUTF8WithReplacement: a byte-level state machine that mirrors
   the WHATWG UTF-8 decoder algorithm — each ill-formed byte (invalid leading
   byte, truncated sequence, overlong, surrogate, or >U+10FFFF) emits U+FFFD
   and advances the cursor by one byte. The fatal path continues to use the
   existing IsValidUTF8 + raw copy approach.

   New tests verify: 0xFF → U+FFFD, truncated 0xC3 → U+FFFD, surrogate
   ED A0 80 → U+FFFD×3 (per WHATWG spec: the leading byte fails at its second
   byte, then each orphaned continuation byte also fails individually), and
   valid bytes preserved between invalid ones.

2. TextEncoder prototype methods now reject non-TextEncoder receivers
   (TextEncoderValue.pas line 276).

   EncodingGetter, Encode, and EncodeInto previously ignored AThisValue,
   so detached calls like TextEncoder.prototype.encode.call({}, "x") would
   succeed. Added illegal-invocation guards matching the TextDecoder pattern.
   Tests cover encode and the encoding getter.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney merged commit 65514aa into main Apr 11, 2026
9 checks passed
@frostney frostney deleted the feature/text-encoder-decoder branch April 11, 2026 18:18
frostney added a commit that referenced this pull request Apr 11, 2026
Incorporates 5 commits from main:
- TextEncoder and TextDecoder built-ins (#272)
- Make import.meta tests account for Windows drive letters (#274)
- Fixes tagged template object identity (#275)
- Add Goccia.build platform metadata (#276)
- Add ToObject coercion for primitives across all Object.* static methods (#271)

Conflict resolution in 3 files (all "both sides added" — keep both):

Goccia.Engine.pas / Goccia.Runtime.Bootstrap.pas:
  - Added ggTextEncoder and ggTextDecoder to TGocciaGlobalBuiltin enum
  - Added both to DefaultGlobals alongside ggURL
  - Added FBuiltinTextEncoder/FBuiltinTextDecoder fields, Free calls,
    registration blocks, Expose* helpers, and constructor TypeDef blocks
    alongside the existing URL equivalents

Goccia.Values.ClassValue.pas:
  - Added TGocciaTextEncoderClassValue and TGocciaTextDecoderClassValue
    declarations, impl uses, and CreateNativeInstance implementations
    alongside the existing URL equivalents

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature New feature or request spec compliance Mismatch against official JavaScript/TypeScript specification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant