Skip to content

Add tagged template literal support#267

Merged
frostney merged 4 commits intomainfrom
t3code/tagged-templates-raw
Apr 11, 2026
Merged

Add tagged template literal support#267
frostney merged 4 commits intomainfrom
t3code/tagged-templates-raw

Conversation

@frostney
Copy link
Copy Markdown
Owner

  • Parse, evaluate, and compile tagged templates
  • Add String.raw and raw template coverage
  • Update docs, benchmarks, and language restrictions

- Parse, evaluate, and compile tagged templates
- Add String.raw and raw template coverage
- Update docs, benchmarks, and language restrictions
@frostney frostney added new feature New feature or request spec compliance Mismatch against official JavaScript/TypeScript specification labels Apr 11, 2026
@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: 6de5c6f1-5451-446d-a693-3924e40eef31

📥 Commits

Reviewing files that changed from the base of the PR and between 1ae9196 and dc6f557.

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

📝 Walkthrough

Walkthrough

Adds ES2015 tagged template literal parsing, AST, compilation, VM evaluation, and a String.raw builtin; updates lexer to emit cooked+raw template data; adds tests, benchmarks, and documentation entries for tagged templates and String.raw.

Changes

Cohort / File(s) Summary
Documentation
docs/built-ins.md, docs/bytecode-vm.md, docs/language-restrictions.md
Documented String.raw; named shared opcode OP_COLLECTION_OP; refined opcode design guidance; declared tagged-template support in language docs.
Benchmarks
benchmarks/strings.js
Added tagged templates benchmark suite with multiple tag workloads (identity, custom join variants, String.raw, .raw access, member-expression tag).
Tests
tests/built-ins/String/raw.js, tests/language/expressions/string/tagged-templates.js
New tests covering String.raw behavior and comprehensive tagged-template semantics (raw vs cooked, immutability, property attributes, call ordering, this binding, coercions, edge cases).
Lexer
units/Goccia.Lexer.pas
ScanTemplate now constructs parallel cooked and raw buffers and emits template token with a TEMPLATE_RAW_SEPARATOR to carry raw data.
Parser
units/Goccia.Parser.pas
Added ParseTaggedTemplate, integrated tagged-template parsing into call loop, splits cooked/raw segments and parses interpolation expressions via nested lexer/parser.
AST
units/Goccia.AST.Expressions.pas
Added TGocciaTaggedTemplateExpression and TGocciaTemplateStrings to represent tag, cooked/raw segments, and substitution expressions; lifecycle and Evaluate override added.
Compiler
units/Goccia.Compiler.Expressions.pas, units/Goccia.Compiler.pas
Added CompileTaggedTemplate and helpers to build frozen cooked/raw arrays, define non-enumerable .raw, emit OP_CALL/OP_CALL_METHOD, and handle constant-pool bounds and arg-count checks; compiler dispatch updated to call it.
Evaluator / Builtins
units/Goccia.Evaluator.pas, units/Goccia.Builtins.GlobalString.pas
Added EvaluateTaggedTemplate runtime path to build/freeze template object, evaluate substitutions and dispatch tag calls; added StringRaw builtin implementing raw interleaving semantics.
Constants
units/Goccia.Constants.PropertyNames.pas
Added PROP_FREEZE = 'freeze' and PROP_RAW = 'raw'.
VM
units/Goccia.VM.pas
Minor formatting change in OP_COLLECTION_OP spread-into-array branch (no semantic change).

Sequence Diagram(s)

sequenceDiagram
    participant Source as Source
    participant Lexer as Lexer
    participant Parser as Parser
    participant AST as AST
    participant Compiler as Compiler
    participant Bytecode as Bytecode
    participant VM as VM
    participant Evaluator as Evaluator
    participant Tag as TagFunction

    Source->>Lexer: encounter tagged template `tag\`...\``
    Lexer-->>Parser: token (cooked#1raw)
    Parser->>AST: TGocciaTaggedTemplateExpression(tag, cooked[], raw[], exprs)
    AST->>Compiler: CompileTaggedTemplate(...)
    Compiler->>Compiler: build cooked/raw arrays, define non-enumerable `.raw`, freeze
    Compiler->>Bytecode: emit OP_CALL or OP_CALL_METHOD + args
    Bytecode-->>VM: execute emitted code
    VM->>Evaluator: evaluate tagged template runtime
    Evaluator->>Evaluator: create/freeze template object, evaluate substitutions
    Evaluator->>Tag: call(tag, templateObj, ...subs)
    Tag-->>Evaluator: return value
    Evaluator-->>VM: final result
Loading
sequenceDiagram
    participant Code as Code
    participant Parser as Parser
    participant Evaluator as Evaluator
    participant StringRaw as String.raw
    participant Result as Result

    Code->>Parser: String.raw`\n\t${x}`
    Parser-->>Evaluator: tagged-template node (String.raw)
    Evaluator->>Evaluator: build cooked & raw arrays
    Note over Evaluator: raw = ["\\n\\t"]\ncooked = [newline, tab]
    Evaluator->>StringRaw: call(String.raw, templateObj, x)
    StringRaw->>StringRaw: interleave templateObj.raw with args
    StringRaw-->>Result: string preserving raw escapes
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description provides a concise summary of changes but lacks the detailed structure, testing checklist completion, and proper issue linking required by the repository's template. Expand the description to follow the template structure: add a detailed 'Summary' section explaining the change and constraints, complete the 'Testing' checklist with specific verification details, and include issue links if applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add tagged template literal support' directly and clearly describes the main feature addition across the entire changeset, covering parser, evaluator, compiler, tests, and documentation updates.
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.

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

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

472-475: Add the function-level ES annotation above ScanTemplate.

The inline step comment is useful, but the repo rule also asks for the // ES2026 §... annotation immediately above the function body itself.

As per coding guidelines "When implementing ECMAScript-specified behavior, annotate each function or method with a comment referencing the relevant spec section using the format // ESYYYY §X.Y.Z SpecMethodName(specParams) where YYYY is the current edition year. Place the annotation immediately above the function body in the implementation section."

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

In `@units/Goccia.Lexer.pas` around lines 472 - 475, Add the required ECMAScript
spec annotation immediately above the implementation of procedure
TGocciaLexer.ScanTemplate: insert a comment in the format "// ES2026 §X.Y.Z
ScanTemplate()" (replace X.Y.Z with the correct spec section) directly above the
"procedure TGocciaLexer.ScanTemplate;" line in the implementation section so it
sits just above the function body, matching the repo guideline format.
units/Goccia.Compiler.Expressions.pas (1)

1713-1715: Use the shared property-name constant for freeze.

Line 1714 hardcodes a runtime property key even though this unit already depends on Goccia.Constants.PropertyNames. Please route this through the shared constant instead of introducing another string literal here.

As per coding guidelines, "Use runtime constants from Goccia.Constants.PropertyNames, Goccia.Constants.TypeNames, Goccia.Constants.ErrorNames, Goccia.Constants.ConstructorNames, and Goccia.Constants.SymbolNames instead of hardcoded string literals."

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

In `@units/Goccia.Compiler.Expressions.pas` around lines 1713 - 1715, Replace the
hardcoded 'freeze' literal passed to ACtx.Template.AddConstantString with the
shared property-name constant from Goccia.Constants.PropertyNames (e.g.,
PropertyNames.Freeze) so the code uses the centralized runtime constant; update
the call that sets FreezeIdx to use that constant instead of the string literal
and keep the surrounding checks (ObjectIdx/FreezeIdx bounds) unchanged.
🤖 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.Compiler.Expressions.pas`:
- Around line 1775-1803: The current code builds fresh cooked/raw arrays at
runtime with OP_NEW_ARRAY and sets .raw via OP_SET_PROP_CONST (within
EmitInstruction/EncodeABC and EmitObjectFreeze using TempReg/Arg0Reg and
ACtx.Template.AddConstantString), but tagged-template semantics require a single
frozen template object per call site that reuses identity; change this to emit a
compile-time template object or lookup via a GetTemplateObject-style mechanism
instead of creating arrays each execution, store the cooked array (Arg0Reg) as
the per-call-site constant/template object, attach the raw array as a
non-enumerable/internal slot (not with OP_SET_PROP_CONST) and ensure both arrays
are frozen (use EmitObjectFreeze semantics) and inserted into the
constant/template pool so the same object identity is returned on every call.
- Around line 1741-1769: The tagged-template callee path only special-cases
TGocciaMemberExpression, so it mis-handles super.foo`...` and private-name
calls; update the block that sets IsMethodCall / handles MemberExpr to mirror
CompileCall's callee-shape handling by also recognizing TGocciaSuperExpression
and the private-identifier node (e.g., TGocciaPrivateIdentifier or the project’s
private-name class), allocating ObjReg and BaseReg the same way, compiling the
appropriate callee parts (object/super target and property expression or
constant name) and emitting the same opcodes/emit-paths CompileCall uses for
computed vs constant properties so the receiver is passed the same way for
tagged templates as for ordinary calls.
- Around line 1742-1743: The code computes ArgCount := 1 +
AExpr.Expressions.Count and later casts it to UInt8 without checking bounds,
which can overflow for >254 substitutions; add a guard before the cast in the
tagged-template paths (the assignment at ArgCount := 1 + AExpr.Expressions.Count
and the similar block at 1813-1816) to validate ArgCount <= 255 and handle
violations by emitting a compilation error/exception or returning failure (same
behavior as CompileCall when rejecting oversized argument lists) instead of
performing the unchecked UInt8(ArgCount) cast.

In `@units/Goccia.Evaluator.pas`:
- Around line 2927-2945: GetTemplateObject currently rebuilds RawArray and
CookedArray on every call and uses AssignProperty for PROP_RAW which makes .raw
enumerable/writable/configurable; change TGocciaTaggedTemplateExpression to
cache the built template object in a FTemplateObject field so GetTemplateObject
returns the same frozen object on repeated calls, and replace the
AssignProperty(PROP_RAW, RawArray) call with DefineProperty using a
non-enumerable, non-writable, non-configurable descriptor (clear pfEnumerable,
pfWritable, pfConfigurable flags) before freezing CookedArray; apply the same
cache-and-DefineProperty fixes in the tagged-template bytecode generation path
so both interpreter GetTemplateObject and the compiler-emitted path produce
identical, memoized template objects.

In `@units/Goccia.Lexer.pas`:
- Around line 504-533: The lexer currently eagerly throws on malformed \u/\x
escapes inside ProcessEscapeSequence, which prevents representing
tagged-template raw segments; change ProcessEscapeSequence to not raise on
malformed escapes but instead return a boolean or status (e.g., ResultValid:
Boolean) and consume the same source range so RawSB/RawStart/FCurrent/FSource
still capture the raw text; in the template-segment handling (the backslash
branch that appends to SB/RawSB) track a per-segment flag (e.g.,
SegmentEscapeValid) set from ProcessEscapeSequence's result and only append to
SB the cooked characters when valid, otherwise leave cooked unset and ensure
RawSB contains the exact source; after finishing a template literal, if the
template is untagged then validate the segment flags and raise syntax errors for
invalid escapes (throwing as before), but if tagged, preserve cooked as
undefined and defer errors to the evaluator.

In `@units/Goccia.Parser.pas`:
- Around line 949-961: The code currently extracts ParsedExpr from ProgramNode
but then frees ProgramNode, leaving ParsedExpr pointing to freed memory; fix by
either parsing the interpolation as an expression directly (add/use a
ParseExpression method on TGocciaParser/ParseUnchecked) or explicitly transfer
ownership of the node out of ProgramNode before freeing it: after obtaining
ParsedExpr from TGocciaExpressionStatement(ProgramNode.Body[0]).Expression,
detach the statement/expression from ProgramNode (e.g. use
ProgramNode.Body.Extract(ProgramNode.Body[0]) or set ProgramNode.Body[0] := nil
/ remove the item so it is not freed) and only then call
Expressions.Add(ParsedExpr) and ProgramNode.Free so the AST node ownership is
correctly transferred.
- Around line 890-1017: The scanner must not treat synthetic leading backtick or
cooked escapes as real interpolation boundaries: before splitting, drop the
synthetic leading backtick from CookedFull/RawFull if present, and detect ${...}
boundaries based on the raw content (RawFull) or by ensuring the '${' is not
escaped (i.e. the previous character is not a backslash) when iterating the
loops that build CookedStrings/RawStrings and Expressions; update the while
loops that check (CookedFull[I] = '$') and (RawFull[I] = '$') to also verify the
preceding character isn't '\' (or use RawFull for the boundary test) so
sequences like \${x} are treated as literal text and the first segment does not
retain a synthetic '`' (affecting TGocciaTaggedTemplateExpression creation).

---

Nitpick comments:
In `@units/Goccia.Compiler.Expressions.pas`:
- Around line 1713-1715: Replace the hardcoded 'freeze' literal passed to
ACtx.Template.AddConstantString with the shared property-name constant from
Goccia.Constants.PropertyNames (e.g., PropertyNames.Freeze) so the code uses the
centralized runtime constant; update the call that sets FreezeIdx to use that
constant instead of the string literal and keep the surrounding checks
(ObjectIdx/FreezeIdx bounds) unchanged.

In `@units/Goccia.Lexer.pas`:
- Around line 472-475: Add the required ECMAScript spec annotation immediately
above the implementation of procedure TGocciaLexer.ScanTemplate: insert a
comment in the format "// ES2026 §X.Y.Z ScanTemplate()" (replace X.Y.Z with the
correct spec section) directly above the "procedure TGocciaLexer.ScanTemplate;"
line in the implementation section so it sits just above the function body,
matching the repo guideline format.
🪄 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: 82a2f000-6259-4c6e-9577-35310eb53c0a

📥 Commits

Reviewing files that changed from the base of the PR and between 340bb64 and 1e1f007.

📒 Files selected for processing (15)
  • benchmarks/strings.js
  • docs/built-ins.md
  • docs/bytecode-vm.md
  • docs/language-restrictions.md
  • tests/built-ins/String/raw.js
  • tests/language/expressions/string/tagged-templates.js
  • units/Goccia.AST.Expressions.pas
  • units/Goccia.Builtins.GlobalString.pas
  • units/Goccia.Compiler.Expressions.pas
  • units/Goccia.Compiler.pas
  • units/Goccia.Constants.PropertyNames.pas
  • units/Goccia.Evaluator.pas
  • units/Goccia.Lexer.pas
  • units/Goccia.Parser.pas
  • units/Goccia.VM.pas

Comment thread units/Goccia.Compiler.Expressions.pas Outdated
Comment thread units/Goccia.Compiler.Expressions.pas Outdated
Comment thread units/Goccia.Compiler.Expressions.pas Outdated
Comment thread units/Goccia.Evaluator.pas
Comment thread units/Goccia.Lexer.pas
Comment thread units/Goccia.Parser.pas
Comment thread units/Goccia.Parser.pas
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 11, 2026

Benchmark Results

364 benchmarks

Interpreted: 🟢 63 improved · 🔴 112 regressed · 🆕 8 new · 181 unchanged · avg -0.9%
Bytecode: 🟢 7 improved · 🔴 327 regressed · 🆕 8 new · 22 unchanged · avg -9.6%

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 11, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 4596 4596
Tests Passed 4555 ✅ 4596 ✅
Tests Skipped 41 0
Tests Test Duration 297.9ms 298.6ms
Tests Lex 81.7ms 59.6ms
Tests Parse 110.1ms 115.8ms
Tests Compile 67.8ms
Tests Execute 311.2ms 330.2ms
Tests Engine Total 503.0ms 573.4ms
Benchmarks Total 364 364
Benchmarks Duration 10.13min 8.43min

Measured on ubuntu-latest x64.

- Guard tagged template compiler against >254 substitutions overflowing UInt8
  argument count, consistent with CompileCall's existing guard
- Define .raw on the template object as non-enumerable/non-writable/non-configurable
  per ES2026 §13.2.8.3 step 8, replacing AssignProperty (which defaulted to
  enumerable) with DefineProperty([], ...) in the interpreter path
- Add EmitDefineNonEnumerableProperty helper in the compiler that calls
  Object.defineProperty({value: rawArray}) — omitting enumerable/writable/configurable
  defaults them all to false per spec — replacing OP_SET_PROP_CONST for the .raw
  attachment in the bytecode path
- Add test asserting .raw is non-enumerable, non-writable, non-configurable

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.

🧹 Nitpick comments (2)
units/Goccia.Compiler.Expressions.pas (2)

1701-1748: Consider extracting 'defineProperty' to a constant.

The string literal 'defineProperty' at line 1718 is hardcoded. For consistency with the project conventions, consider adding a constant (e.g., PROP_DEFINE_PROPERTY) to Goccia.Constants.PropertyNames and using it here.

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

In `@units/Goccia.Compiler.Expressions.pas` around lines 1701 - 1748, The
hardcoded string 'defineProperty' in EmitDefineNonEnumerableProperty should be
moved to a named constant to follow project conventions; add a constant (e.g.,
PROP_DEFINE_PROPERTY) to Goccia.Constants.PropertyNames and replace the inline
literal used to initialize DefPropIdx (the AddConstantString call) with that
constant, ensuring EmitDefineNonEnumerableProperty, DefPropIdx and any other
callers use the new constant name instead of the literal.

1750-1778: Consider extracting 'freeze' to a constant.

Similar to the above, the string literal 'freeze' at line 1763 could be extracted to a constant for consistency with the guideline to use runtime constants from Goccia.Constants.PropertyNames instead of hardcoded string literals.

As per coding guidelines: "Use runtime constants from Goccia.Constants.PropertyNames... instead of hardcoded string literals."

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

In `@units/Goccia.Compiler.Expressions.pas` around lines 1750 - 1778, Extract the
hardcoded 'freeze' string in EmitObjectFreeze and use the runtime constant from
Goccia.Constants.PropertyNames instead: replace
ACtx.Template.AddConstantString('freeze') with
ACtx.Template.AddConstantString(<PropertyNames.FreezeConstant>) (use the
appropriate identifier from Goccia.Constants.PropertyNames), and update the
FreezeIdx usage accordingly so the code references the constant symbol rather
than a literal; keep the existing ObjectIdx/FreezeIdx overflow check and
subsequent EmitInstruction calls intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@units/Goccia.Compiler.Expressions.pas`:
- Around line 1701-1748: The hardcoded string 'defineProperty' in
EmitDefineNonEnumerableProperty should be moved to a named constant to follow
project conventions; add a constant (e.g., PROP_DEFINE_PROPERTY) to
Goccia.Constants.PropertyNames and replace the inline literal used to initialize
DefPropIdx (the AddConstantString call) with that constant, ensuring
EmitDefineNonEnumerableProperty, DefPropIdx and any other callers use the new
constant name instead of the literal.
- Around line 1750-1778: Extract the hardcoded 'freeze' string in
EmitObjectFreeze and use the runtime constant from
Goccia.Constants.PropertyNames instead: replace
ACtx.Template.AddConstantString('freeze') with
ACtx.Template.AddConstantString(<PropertyNames.FreezeConstant>) (use the
appropriate identifier from Goccia.Constants.PropertyNames), and update the
FreezeIdx usage accordingly so the code references the constant symbol rather
than a literal; keep the existing ObjectIdx/FreezeIdx overflow check and
subsequent EmitInstruction calls intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d05a9831-17fc-499d-88fb-8269ed8335da

📥 Commits

Reviewing files that changed from the base of the PR and between 1e1f007 and a308d8d.

📒 Files selected for processing (3)
  • tests/language/expressions/string/tagged-templates.js
  • units/Goccia.Compiler.Expressions.pas
  • units/Goccia.Evaluator.pas
🚧 Files skipped from review as they are similar to previous changes (1)
  • units/Goccia.Evaluator.pas

…ants

Add PROP_FREEZE = 'freeze' to Goccia.Constants.PropertyNames and use the
existing PROP_DEFINE_PROPERTY constant (already present in the Proxy trap
section) in EmitDefineNonEnumerableProperty and EmitObjectFreeze instead of
inline string literals, per project convention.

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.

🧹 Nitpick comments (2)
units/Goccia.Compiler.Expressions.pas (2)

1795-1819: Consider extracting the shared callee/call lowering with CompileCall.

CompileTaggedTemplate now carries its own copy of the member-vs-plain callee setup and final OP_CALL / OP_CALL_METHOD emission. Pulling that into a small helper would reduce drift the next time call semantics change in one path but not the other.

Also applies to: 1860-1864

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

In `@units/Goccia.Compiler.Expressions.pas` around lines 1795 - 1819, The callee
setup and call emission logic duplicated in CompileTaggedTemplate (the
IsMethodCall branch handling TGocciaMemberExpression, AllocateRegister,
ACtx.CompileExpression, emitting OP_ARRAY_GET or OP_GET_PROP_CONST with
Template.AddConstantString, and the final OP_CALL / OP_CALL_METHOD emission)
should be extracted into a helper CompileCall; implement CompileCall to take the
expression/tag and return the resolved callee/base/obj registers and the
appropriate call opcode, reuse it from CompileTaggedTemplate and the other
location (lines ~1860-1864) to replace the duplicated code, and ensure existing
EmitInstruction and constant-pool overflow handling are preserved inside the
helper.

1701-1705: Use the repo’s spec-annotation format on these new tagged-template routines.

These comments reference the spec, but they do not use the required // ESYYYY §X.Y.Z SpecMethodName(specParams) form. Please normalize the annotations above EmitDefineNonEnumerableProperty, EmitObjectFreeze, and CompileTaggedTemplate so this path stays consistent with the rest of the spec-annotated compiler code.

As per coding guidelines, "When implementing ECMAScript-specified behavior, annotate each function or method with a comment referencing the relevant spec section using the format // ESYYYY §X.Y.Z SpecMethodName(specParams) ... Place the annotation immediately above the function body in the implementation section."

Also applies to: 1750-1753, 1780-1781

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

In `@units/Goccia.Compiler.Expressions.pas` around lines 1701 - 1705, Replace the
free-form spec comments above EmitDefineNonEnumerableProperty, EmitObjectFreeze,
and CompileTaggedTemplate (and the duplicate spots noted around the other two
comment blocks) with the repository's standardized spec-annotation line
immediately above each function body in the implementation section, using the
format "// ESYYYY §X.Y.Z SpecMethodName(specParams)"; e.g. for
EmitDefineNonEnumerableProperty use the ES2026 reference already mentioned (//
ES2026 §13.2.8.3 DefineProperty(AObjReg, propName, descriptor)) and create
analogous ES-prefixed annotations for EmitObjectFreeze and CompileTaggedTemplate
so each routine has a single-line spec annotation directly above its
implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@units/Goccia.Compiler.Expressions.pas`:
- Around line 1795-1819: The callee setup and call emission logic duplicated in
CompileTaggedTemplate (the IsMethodCall branch handling TGocciaMemberExpression,
AllocateRegister, ACtx.CompileExpression, emitting OP_ARRAY_GET or
OP_GET_PROP_CONST with Template.AddConstantString, and the final OP_CALL /
OP_CALL_METHOD emission) should be extracted into a helper CompileCall;
implement CompileCall to take the expression/tag and return the resolved
callee/base/obj registers and the appropriate call opcode, reuse it from
CompileTaggedTemplate and the other location (lines ~1860-1864) to replace the
duplicated code, and ensure existing EmitInstruction and constant-pool overflow
handling are preserved inside the helper.
- Around line 1701-1705: Replace the free-form spec comments above
EmitDefineNonEnumerableProperty, EmitObjectFreeze, and CompileTaggedTemplate
(and the duplicate spots noted around the other two comment blocks) with the
repository's standardized spec-annotation line immediately above each function
body in the implementation section, using the format "// ESYYYY §X.Y.Z
SpecMethodName(specParams)"; e.g. for EmitDefineNonEnumerableProperty use the
ES2026 reference already mentioned (// ES2026 §13.2.8.3 DefineProperty(AObjReg,
propName, descriptor)) and create analogous ES-prefixed annotations for
EmitObjectFreeze and CompileTaggedTemplate so each routine has a single-line
spec annotation directly above its implementation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e7a8338e-5b87-434c-9377-58f2c0d2661e

📥 Commits

Reviewing files that changed from the base of the PR and between a308d8d and 1ae9196.

📒 Files selected for processing (2)
  • units/Goccia.Compiler.Expressions.pas
  • units/Goccia.Constants.PropertyNames.pas
✅ Files skipped from review due to trivial changes (1)
  • units/Goccia.Constants.PropertyNames.pas

…te helpers

- Extract CompileTagCalleeRegisters from CompileTaggedTemplate to isolate the
  member-expression vs regular-expression callee shape detection and register
  allocation, mirroring CompileCall's non-super member branch
- Replace free-form comments on EmitDefineNonEnumerableProperty, EmitObjectFreeze,
  and CompileTaggedTemplate with standardized ES2026 §X.Y.Z spec annotations
  per project convention

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney merged commit 38a9fa8 into main Apr 11, 2026
9 checks passed
@frostney frostney deleted the t3code/tagged-templates-raw branch April 11, 2026 12:38
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