Skip to content

Add instruction counter / interrupt handler with configurable limit#349

Merged
frostney merged 8 commits intomainfrom
t3code/bytecode-interrupt-counter
Apr 19, 2026
Merged

Add instruction counter / interrupt handler with configurable limit#349
frostney merged 8 commits intomainfrom
t3code/bytecode-interrupt-counter

Conversation

@frostney
Copy link
Copy Markdown
Owner

Summary

  • Add --max-instructions=<N> CLI flag that caps the number of instructions a script may execute before aborting with a TGocciaInstructionLimitError
  • In bytecode mode the counter increments on every dispatched instruction (exact count); in interpreter mode it increments at function-call and loop-iteration checkpoints (approximate)
  • The counter uses thread-local storage (Goccia.InstructionLimit.pas) following the same pattern as Goccia.Timeout.pas, with zero overhead when the limit is not set

Test plan

  • All binaries build cleanly (loader, testrunner, benchmarkrunner, bundler, repl)
  • Full test suite passes in both interpreted and bytecode modes (same pre-existing FFI-only failures)
  • ./format.pas --check passes
  • Manual verification: infinite loop aborts with correct error and JSON output in both modes
  • CI tests added to pr.yml validating --max-instructions in both interpreted and bytecode modes (exit code, JSON error type, error message)

🤖 Generated with Claude Code

- Add `--max-instructions` CLI support and runtime enforcement
- Surface `InstructionLimitError` in JSON output and docs
- Cover interpreter, VM, and queue checkpoints
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 19, 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: 80ecda8d-68cd-4de7-8e90-1d7ed994333f

📥 Commits

Reviewing files that changed from the base of the PR and between f414ac1 and d247d12.

📒 Files selected for processing (1)
  • docs/bytecode-vm.md
✅ Files skipped from review due to trivial changes (1)
  • docs/bytecode-vm.md

📝 Walkthrough

Walkthrough

Adds a per-execution instruction-count limit: new --max-instructions CLI option, a thread-local Goccia.InstructionLimit unit (counter + exception), and instrumentation/checks across evaluator hot paths, the bytecode VM, microtask draining, runners, CLI options, CI assertions, JSON error mapping, and docs.

Changes

Cohort / File(s) Summary
Documentation & CI
AGENTS.md, docs/build-system.md, docs/bytecode-vm.md, .github/workflows/pr.yml
Document --max-instructions usage and bytecode example; CI adds non-fatal assertions that GocciaScriptLoader exits 1 and emits JSON { "ok": false, "type": "InstructionLimitError", "message": "Execution exceeded instruction limit of 500" } for interpreted and bytecode runs.
Instruction-Limit Unit
source/units/Goccia.InstructionLimit.pas
New unit providing TGocciaInstructionLimitError, thread-local GMaxInstructions/GInstructionCount, and API: StartInstructionLimit, ClearInstructionLimit, IncrementInstructionCounter, CheckInstructionLimit.
CLI Options
source/shared/CLI.Options.pas
Added TGocciaInt64Option and FMaxInstructions/MaxInstructions on TGocciaEngineOptions; parsing/validation, ctor/dtor wiring, and included in options array (size increased).
Runners / Apps
source/app/GocciaScriptLoader.dpr, source/app/GocciaBenchmarkRunner.dpr, source/app/GocciaTestRunner.dpr
Start StartInstructionLimit(...) immediately after StartExecutionTimeout(...) and call ClearInstructionLimit alongside ClearExecutionTimeout in finally/cleanup blocks for all execution paths.
Evaluator Instrumentation
source/units/Goccia.Evaluator.pas
Inserted IncrementInstructionCounter/CheckInstructionLimit at call sites, loop iterations, instantiation/tagged-template paths; EvaluateTry explicitly re-raises TGocciaInstructionLimitError.
VM & Runtime Execution
source/units/Goccia.VM.pas, source/units/Goccia.MicrotaskQueue.pas, source/units/Goccia.Values.Primitives.pas
Per-instruction increment/check in VM dispatch loop (check before decode, increment after IP advance); added CheckInstructionLimit in iterator/instantiate paths, microtask drain loop, and TGocciaValue.AfterConstruction.
Error Mapping
source/units/Goccia.ScriptLoader.JSON.pas
Map TGocciaInstructionLimitError to JSON error.type = 'InstructionLimitError'.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI/Options
    participant Runner as ScriptLoader/Runner
    participant Limit as InstructionLimit
    participant Evaluator as Evaluator/VM

    CLI->>Runner: --max-instructions = N
    Runner->>Limit: StartInstructionLimit(N)
    Note over Limit: Set GMaxInstructions = N\nGInstructionCount = 0

    rect rgba(100,150,200,0.5)
        Runner->>Evaluator: Execute script/module
        loop execution steps
            Evaluator->>Limit: IncrementInstructionCounter()
            Note over Limit: GInstructionCount++
            Evaluator->>Limit: CheckInstructionLimit()
            alt GInstructionCount >= GMaxInstructions
                Limit-->>Evaluator: Raise TGocciaInstructionLimitError
                Evaluator-->>Runner: Propagate error / abort
            end
        end
    end

    Runner->>Limit: ClearInstructionLimit()
    Note over Limit: Reset GMaxInstructions = 0\nGInstructionCount = 0
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately and concisely summarizes the main change: adding an instruction counter with a configurable limit feature.
Description check ✅ Passed The PR description comprehensively covers the change summary, implementation details, and includes a complete test plan with all checkboxes marked complete.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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

@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation new feature New feature or request labels Apr 19, 2026
…rupt-counter

# Conflicts:
#	AGENTS.md
#	source/shared/CLI.Options.pas
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@source/shared/CLI.Options.pas`:
- Around line 472-473: Update the help text for the FMaxInstructions option to
be mode-neutral: locate the TGocciaIntegerOption instance named FMaxInstructions
and change its description from "Maximum bytecode instructions before aborting"
to a neutral phrase such as "Maximum instructions before aborting" or "Maximum
instruction steps before aborting" so it correctly applies to both interpreted
and bytecode modes.

In `@source/units/Goccia.InstructionLimit.pas`:
- Around line 36-45: IncrementInstructionCounter currently increments
GInstructionCount even when no limit is set and CheckInstructionLimit uses >=
which aborts at the limit instead of when it's exceeded; to fix, make
IncrementInstructionCounter no-op (skip Inc(GInstructionCount)) when
GMaxInstructions <= 0 to avoid disabled-mode overhead, and change the check
inside CheckInstructionLimit to use > (i.e., raise TGocciaInstructionLimitError
only when GInstructionCount > GMaxInstructions) referencing the
IncrementInstructionCounter and CheckInstructionLimit procedures and the
GInstructionCount/GMaxInstructions globals and TGocciaInstructionLimitError for
locating the code.

In `@source/units/Goccia.MicrotaskQueue.pas`:
- Around line 100-102: TGocciaMicrotaskQueue.DrainQueue currently calls
IncrementInstructionCounter from a shared path used by both the interpreter and
bytecode executor, causing microtask dispatch to consume an extra synthetic
instruction and breaking --max-instructions accuracy; remove or gate the
IncrementInstructionCounter call from the shared DrainQueue path and instead
perform interpreter-only instruction bookkeeping inside the interpreter-specific
code path (i.e., move or wrap IncrementInstructionCounter so it is called only
when executing in the interpreter mode, not when DrainQueue is used by the
bytecode path—refer to TGocciaMicrotaskQueue.DrainQueue,
IncrementInstructionCounter, CheckExecutionTimeout, CheckInstructionLimit and
the bytecode execution flow in Goccia.Engine.pas/Goccia.Evaluator.pas to locate
the proper interpreter-only spot).

In `@source/units/Goccia.VM.pas`:
- Around line 1695-1696: The instruction-count check is done inconsistently: the
counter is incremented at opcode fetch but CheckInstructionLimit is called
inside some handlers (OP_CONSTRUCT, OP_CALL, OP_CALL_METHOD), causing off-by-one
behavior; move enforcement to the dispatch boundary so the limit is checked just
before dispatching the next opcode (where the counter is incremented) and remove
the mid-instruction CheckInstructionLimit calls from those handlers (or adjust
the counter/check contract so handlers cannot abort the already-counted opcode).
Update the code paths that call CheckInstructionLimit (references:
CheckExecutionTimeout, CheckInstructionLimit, OP_CONSTRUCT, OP_CALL,
OP_CALL_METHOD) so the hard limit is evaluated only at the single centralized
dispatch point.
🪄 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: b07bb807-8a38-4e12-beeb-23fd095de530

📥 Commits

Reviewing files that changed from the base of the PR and between 6ac691a and 695ea34.

📒 Files selected for processing (14)
  • .github/workflows/pr.yml
  • AGENTS.md
  • docs/build-system.md
  • docs/bytecode-vm.md
  • source/app/GocciaBenchmarkRunner.dpr
  • source/app/GocciaScriptLoader.dpr
  • source/app/GocciaTestRunner.dpr
  • source/shared/CLI.Options.pas
  • source/units/Goccia.Evaluator.pas
  • source/units/Goccia.InstructionLimit.pas
  • source/units/Goccia.MicrotaskQueue.pas
  • source/units/Goccia.ScriptLoader.JSON.pas
  • source/units/Goccia.VM.pas
  • source/units/Goccia.Values.Primitives.pas

Comment thread source/shared/CLI.Options.pas Outdated
Comment thread source/units/Goccia.InstructionLimit.pas
Comment thread source/units/Goccia.MicrotaskQueue.pas
Comment thread source/units/Goccia.VM.pas
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
source/shared/CLI.Options.pas (1)

131-145: ⚠️ Potential issue | 🟠 Major

Use an Int64-backed option type for --max-instructions.

FMaxInstructions is wired as TGocciaIntegerOption (32-bit), but the runtime limit API/counter uses Int64. This creates an avoidable range mismatch for large limits.

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

In `@source/shared/CLI.Options.pas` around lines 131 - 145, FMaxInstructions is
declared and exposed via the MaxInstructions property as TGocciaIntegerOption
(32-bit) but the runtime limit API expects Int64; change the field and property
to an Int64-backed option type (replace TGocciaIntegerOption with the Int64
variant, e.g., TGocciaInt64Option) for FMaxInstructions and the MaxInstructions
property, update any constructor initialization, destruction and Options()
registration code that creates or references FMaxInstructions to use the new
TGocciaInt64Option API, and search for usages of
FMaxInstructions/MaxInstructions elsewhere to ensure code that reads the option
now expects Int64 values.
♻️ Duplicate comments (1)
source/shared/CLI.Options.pas (1)

474-475: ⚠️ Potential issue | 🟡 Minor

Make the help text mode-neutral.

The description says “Maximum bytecode instructions…”, but this limit is enforced in interpreted mode too. Please use neutral wording.

Suggested wording
   FMaxInstructions := TGocciaIntegerOption.Create('max-instructions',
-    'Maximum bytecode instructions before aborting', 'Engine');
+    'Maximum instructions before aborting', 'Engine');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/shared/CLI.Options.pas` around lines 474 - 475, The help text for the
option created by FMaxInstructions
(TGocciaIntegerOption.Create('max-instructions', ...)) is currently specific to
“bytecode”; change the description string to neutral wording such as "Maximum
instructions before aborting" or "Maximum execution instructions before
aborting" so it applies to both interpreted and bytecode modes—update the second
argument passed to TGocciaIntegerOption.Create accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@source/shared/CLI.Options.pas`:
- Around line 131-145: FMaxInstructions is declared and exposed via the
MaxInstructions property as TGocciaIntegerOption (32-bit) but the runtime limit
API expects Int64; change the field and property to an Int64-backed option type
(replace TGocciaIntegerOption with the Int64 variant, e.g., TGocciaInt64Option)
for FMaxInstructions and the MaxInstructions property, update any constructor
initialization, destruction and Options() registration code that creates or
references FMaxInstructions to use the new TGocciaInt64Option API, and search
for usages of FMaxInstructions/MaxInstructions elsewhere to ensure code that
reads the option now expects Int64 values.

---

Duplicate comments:
In `@source/shared/CLI.Options.pas`:
- Around line 474-475: The help text for the option created by FMaxInstructions
(TGocciaIntegerOption.Create('max-instructions', ...)) is currently specific to
“bytecode”; change the description string to neutral wording such as "Maximum
instructions before aborting" or "Maximum execution instructions before
aborting" so it applies to both interpreted and bytecode modes—update the second
argument passed to TGocciaIntegerOption.Create accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce73c1ba-c15b-45b1-9597-59fd30933de8

📥 Commits

Reviewing files that changed from the base of the PR and between 695ea34 and 6a35ac1.

📒 Files selected for processing (6)
  • .github/workflows/pr.yml
  • AGENTS.md
  • source/app/GocciaBenchmarkRunner.dpr
  • source/app/GocciaScriptLoader.dpr
  • source/app/GocciaTestRunner.dpr
  • source/shared/CLI.Options.pas
✅ Files skipped from review due to trivial changes (3)
  • AGENTS.md
  • source/app/GocciaScriptLoader.dpr
  • source/app/GocciaBenchmarkRunner.dpr
🚧 Files skipped from review as they are similar to previous changes (2)
  • source/app/GocciaTestRunner.dpr
  • .github/workflows/pr.yml

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 19, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 5805 5805
Tests Passed 5764 ✅ 5805 ✅
Tests Skipped 41 0
Tests Workers 4 4
Tests Test Duration 1.41s 1.31s
Tests Lex (cumulative) 187.0ms 110.8ms
Tests Parse (cumulative) 248.6ms 243.5ms
Tests Compile (cumulative) 158.9ms
Tests Execute (cumulative) 1.55s 1.09s
Tests Engine Total (cumulative) 1.98s 1.61s
Tests Lex (avg/worker) 46.8ms 27.7ms
Tests Parse (avg/worker) 62.2ms 60.9ms
Tests Compile (avg/worker) 39.7ms
Tests Execute (avg/worker) 387.3ms 273.4ms
Tests Engine Total (avg/worker) 496.2ms 401.7ms
Benchmarks Total 386 386
Benchmarks Workers 4 4
Benchmarks Duration 3.17min 2.91min

Measured on ubuntu-latest x64.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 19, 2026

Benchmark Results

386 benchmarks

Interpreted: 🟢 340 improved · 🔴 14 regressed · 32 unchanged · avg +9.1%
Bytecode: 🟢 161 improved · 🔴 64 regressed · 161 unchanged · avg +2.1%

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

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

frostney and others added 2 commits April 19, 2026 02:36
- Make --max-instructions help text mode-neutral
- Guard IncrementInstructionCounter to skip threadvar access when disabled
- Remove synthetic increment from shared MicrotaskQueue.DrainQueue path
- Move CheckInstructionLimit to dispatch loop top for exact enforcement,
  remove redundant mid-instruction checks from backward-jump/call handlers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add TGocciaInt64Option to support values beyond the 32-bit Integer
range (~2.1B). The instruction limit runtime API already uses Int64;
this aligns the CLI parsing layer so users can specify limits above
2^31-1.

Also document that zero (the default) means unlimited.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai coderabbitai Bot added the internal Refactoring, CI, tooling, cleanup label Apr 19, 2026
The instruction limit and timeout are cross-cutting engine features
that work in both interpreter and bytecode modes. Move the primary
documentation to embedding.md under a new "Execution Limits" section
covering both mechanisms with Pascal API examples. The bytecode-vm.md
section now cross-references embedding.md.

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/embedding.md`:
- Line 642: Update the documentation sentence about disabling the instruction
counter to soften the "zero overhead" claim: replace the phrase that says "no
threadvar access, no comparisons, zero overhead" with wording that explains
disabling (GMaxInstructions <= 0) skips counter increments/writes but still
performs guard reads/checks (e.g., limit and counter are still read on the hot
path), and mention TGocciaInstructionLimitError remains raised when the limit is
reached; reference IncrementInstructionCounter, GMaxInstructions and the fact it
skips Inc to avoid threadvar writes.
🪄 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: 41f4c7bb-01a7-418f-96a3-d975c6bd582f

📥 Commits

Reviewing files that changed from the base of the PR and between f92569f and 8ddcb04.

📒 Files selected for processing (2)
  • docs/bytecode-vm.md
  • docs/embedding.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/bytecode-vm.md

Comment thread docs/embedding.md Outdated
The embedding doc should describe the Pascal API; CLI specifics belong
in build-system.md. Replace per-mechanism --flag lines with a single
cross-reference to the build system docs.

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
docs/embedding.md (1)

640-640: ⚠️ Potential issue | 🟡 Minor

Soften the “zero overhead” claim when disabled.
The current sentence overstates behavior. Disabling skips increment writes on the hot path, but guard checks still read/evaluate limit state, so “zero overhead” is inaccurate.

Based on learnings: IncrementInstructionCounter skips Inc when GMaxInstructions <= 0, but the limit-check path still exists.

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

In `@docs/embedding.md` at line 640, The sentence in docs/embedding.md overstates
behavior by claiming "zero overhead" when the instruction counter is disabled;
update the wording around TGocciaInstructionLimitError to state that setting
GMaxInstructions to zero disables increments (IncrementInstructionCounter skips
Inc) but does not eliminate the limit-check path — guard reads/evaluations still
occur, so describe it as "minimal" or "no incremental writes on the hot path"
instead of "zero overhead" and mention the remaining read/check cost.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@docs/embedding.md`:
- Line 640: The sentence in docs/embedding.md overstates behavior by claiming
"zero overhead" when the instruction counter is disabled; update the wording
around TGocciaInstructionLimitError to state that setting GMaxInstructions to
zero disables increments (IncrementInstructionCounter skips Inc) but does not
eliminate the limit-check path — guard reads/evaluations still occur, so
describe it as "minimal" or "no incremental writes on the hot path" instead of
"zero overhead" and mention the remaining read/check cost.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab7a2006-1f1d-42cc-9fa3-f5808dab7c14

📥 Commits

Reviewing files that changed from the base of the PR and between f92569f and 970c61b.

📒 Files selected for processing (2)
  • docs/bytecode-vm.md
  • docs/embedding.md
✅ Files skipped from review due to trivial changes (1)
  • docs/bytecode-vm.md

frostney and others added 2 commits April 19, 2026 03:08
When disabled, IncrementInstructionCounter and CheckInstructionLimit
still read the GMaxInstructions threadvar to short-circuit. Describe
the actual cost: guard read only, no increments or comparisons.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Describe the dispatch-loop mechanism without referencing the CLI flag;
the CLI is a separate layer. Cross-reference embedding.md for the API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney merged commit b683b16 into main Apr 19, 2026
10 checks passed
@frostney frostney deleted the t3code/bytecode-interrupt-counter branch April 19, 2026 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation internal Refactoring, CI, tooling, cleanup new feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant