Skip to content

Change wasm-tests CI to run Node harness instead of Pascal harness#61

Merged
frostney merged 1 commit into
mainfrom
codex/wasm-ci-no-fpc
Mar 10, 2026
Merged

Change wasm-tests CI to run Node harness instead of Pascal harness#61
frostney merged 1 commit into
mainfrom
codex/wasm-ci-no-fpc

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Mar 10, 2026

Summary by CodeRabbit

  • Tests

    • Migrated WASM integration test harness from Pascal to Node.js, improving compatibility and maintainability across platforms.
    • Removed OS-specific installation steps from CI/CD pipelines.
    • Updated all continuous integration workflows to use the new test runner.
  • Documentation

    • Updated test execution documentation and WASM backend guides to reflect new test runner commands.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

This pull request replaces the Pascal-based WASM integration test harness with a Node.js ES module implementation. The changes include removing FPC installation steps from CI workflows, updating test invocations to use the new Node.js runner, removing the old Pascal script, adding the new Node.js module, and updating documentation references.

Changes

Cohort / File(s) Summary
CI Workflows
.github/workflows/ci.yml, .github/workflows/pr.yml
Removed OS-specific FPC installation steps and updated WASM test invocation from Pascal script (run-wasm-tests.pas) to Node.js module (node ./tests-wasm/run-wasm-tests.mjs).
Documentation
AGENTS.md, docs/wasm-backend.md
Updated WASM test harness file references and invocation commands from run-wasm-tests.pas to run-wasm-tests.mjs with node execution syntax.
Test Harness Implementation
tests-wasm/run-wasm-tests.mjs
New Node.js ES module that orchestrates WASM tests by resolving ScriptLoader binary, iterating test fixtures, compiling to WASM, executing via host script, parsing expected output, and reporting results with colored formatting and aggregated counts.
Test Harness Removal
tests-wasm/run-wasm-tests.pas
Deleted the original Pascal-based test harness script that performed similar WASM test orchestration.

Sequence Diagram(s)

sequenceDiagram
    participant Runner as Test Runner
    participant ScriptLoader as ScriptLoader Binary
    participant TempDir as Temp Directory
    participant Fixture as Test Fixture
    participant Host as Host Script
    participant Node as Node.js Runtime
    
    Runner->>Runner: Resolve ScriptLoader & Host paths
    Runner->>Runner: Create temp working directory
    loop For each fixture
        Runner->>Fixture: Read fixture file
        alt Skip directive detected
            Runner->>Runner: Mark as SKIPPED
        else Fixture valid
            Runner->>ScriptLoader: Invoke --emit=wasm<br/>(fixture → temp wasm)
            alt Compilation succeeds
                ScriptLoader-->>TempDir: WASM file created
                Runner->>Host: Execute node ./host<br/>(with WASM file)
                Host->>Node: Run in Node.js runtime
                alt Execution succeeds
                    Node-->>Host: stdout output
                    Runner->>Fixture: Parse // Expected: lines
                    Runner->>Runner: Compare actual vs expected
                    alt Output matches
                        Runner->>Runner: Mark as PASS
                    else Output mismatch
                        Runner->>Runner: Mark as FAIL
                    end
                else Execution fails
                    Runner->>Runner: Mark as FAIL<br/>(node error/exit code)
                end
            else Compilation fails
                Runner->>Runner: Mark as FAIL<br/>(compile error)
            end
        end
    end
    Runner->>TempDir: Clean up
    Runner->>Runner: Output final summary<br/>(passed/failed/skipped counts)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 A wand of Node replaces Pascal's grace,
WASM tests now run at a nimbler pace,
FPC steps removed, the CI flows clean,
JavaScript harness—the fastest we've seen! ✨
Hoppy refactoring, no bugs in between! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: replacing the Pascal-based WASM test harness with a Node.js-based harness in CI, which aligns with the substantial code modifications across CI configs and test files.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/wasm-ci-no-fpc

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@frostney frostney changed the title Add 6-week roadmap documents Change wasm-tests CI to run Node harness instead of Pascal harness Mar 10, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Benchmark Results

254 benchmarks

Interpreted: 🟢 2 improved · 🔴 1 regressed · 251 unchanged · avg +0.3%
Bytecode: 🟢 7 improved · 🔴 10 regressed · 237 unchanged · avg -0.3%

arraybuffer.js — Interp: 14 unch. · avg -1.1% · Bytecode: 14 unch. · avg -0.9%
Benchmark Interpreted Δ Bytecode Δ
create ArrayBuffer(0) 423,795 → 420,124 -0.9% 136,986 → 135,582 -1.0%
create ArrayBuffer(64) 424,937 → 412,727 -2.9% 138,431 → 139,022 +0.4%
create ArrayBuffer(1024) 320,072 → 317,039 -0.9% 126,021 → 124,835 -0.9%
create ArrayBuffer(8192) 132,364 → 133,106 +0.6% 81,864 → 81,874 +0.0%
slice full buffer (64 bytes) 512,603 → 506,004 -1.3% 367,545 → 353,006 -4.0%
slice half buffer (512 of 1024 bytes) 431,856 → 423,856 -1.9% 322,284 → 319,484 -0.9%
slice with negative indices 439,031 → 432,010 -1.6% 345,036 → 338,341 -1.9%
slice empty range 481,590 → 483,411 +0.4% 347,257 → 347,610 +0.1%
byteLength access 1,546,955 → 1,559,080 +0.8% 981,769 → 977,574 -0.4%
Symbol.toStringTag access 1,105,365 → 1,093,576 -1.1% 506,024 → 510,834 +1.0%
ArrayBuffer.isView 701,595 → 701,599 +0.0% 442,389 → 437,674 -1.1%
clone ArrayBuffer(64) 383,800 → 377,872 -1.5% 317,622 → 309,828 -2.5%
clone ArrayBuffer(1024) 288,954 → 283,320 -1.9% 249,319 → 244,874 -1.8%
clone ArrayBuffer inside object 260,093 → 252,024 -3.1% 152,966 → 153,721 +0.5%
arrays.js — Interp: 🟢 1, 18 unch. · avg +1.9% · Bytecode: 🟢 1, 🔴 2, 16 unch. · avg -1.5%
Benchmark Interpreted Δ Bytecode Δ
Array.from length 100 12,566 → 13,619 🟢 +8.4% 11,492 → 12,109 +5.4%
Array.from 10 elements 210,875 → 224,605 +6.5% 154,255 → 157,383 +2.0%
Array.of 10 elements 295,726 → 295,122 -0.2% 209,957 → 214,504 +2.2%
spread into new array 329,159 → 336,275 +2.2% 526,648 → 562,680 +6.8%
map over 50 elements 25,593 → 27,244 +6.5% 20,116 → 20,642 +2.6%
filter over 50 elements 22,218 → 23,453 +5.6% 19,667 → 15,081 🔴 -23.3%
reduce sum 50 elements 26,110 → 26,515 +1.5% 17,670 → 17,483 -1.1%
forEach over 50 elements 22,177 → 22,458 +1.3% 21,887 → 20,765 -5.1%
find in 50 elements 34,598 → 35,907 +3.8% 25,044 → 25,590 +2.2%
sort 20 elements 12,046 → 12,088 +0.3% 2,827 → 2,891 +2.3%
flat nested array 117,497 → 117,416 -0.1% 277,761 → 270,800 -2.5%
flatMap 73,318 → 72,648 -0.9% 186,127 → 203,626 🟢 +9.4%
map inside map (5x5) 21,166 → 21,170 +0.0% 67,175 → 67,378 +0.3%
filter inside map (5x10) 15,673 → 15,779 +0.7% 12,769 → 12,549 -1.7%
reduce inside map (5x10) 19,268 → 19,068 -1.0% 12,496 → 12,684 +1.5%
forEach inside forEach (5x10) 16,287 → 16,288 +0.0% 14,139 → 13,958 -1.3%
find inside some (10x10) 13,861 → 13,991 +0.9% 9,934 → 9,498 -4.4%
map+filter chain nested (5x20) 5,342 → 5,405 +1.2% 4,149 → 3,886 -6.3%
reduce flatten (10x5) 41,705 → 41,253 -1.1% 5,554 → 4,601 🔴 -17.2%
async-await.js — Interp: 6 unch. · avg +0.3% · Bytecode: 6 unch. · avg +1.5%
Benchmark Interpreted Δ Bytecode Δ
single await 372,830 → 367,783 -1.4% 260,664 → 272,341 +4.5%
multiple awaits 167,202 → 165,545 -1.0% 112,371 → 117,214 +4.3%
await non-Promise value 824,168 → 835,286 +1.3% 951,530 → 950,981 -0.1%
await with try/catch 370,273 → 366,018 -1.1% 266,158 → 266,901 +0.3%
await Promise.all 50,817 → 51,708 +1.8% 39,825 → 40,022 +0.5%
nested async function call 184,950 → 189,387 +2.4% 205,545 → 204,870 -0.3%
classes.js — Interp: 31 unch. · avg +0.4% · Bytecode: 31 unch. · avg +0.6%
Benchmark Interpreted Δ Bytecode Δ
simple class new 115,105 → 113,987 -1.0% 323,703 → 339,313 +4.8%
class with defaults 91,505 → 90,751 -0.8% 230,517 → 239,074 +3.7%
50 instances via Array.from 5,580 → 5,515 -1.2% 6,106 → 6,112 +0.1%
instance method call 57,725 → 58,274 +1.0% 152,310 → 150,374 -1.3%
static method call 89,317 → 89,731 +0.5% 354,606 → 353,786 -0.2%
single-level inheritance 45,042 → 45,840 +1.8% 145,895 → 150,854 +3.4%
two-level inheritance 38,417 → 38,377 -0.1% 119,397 → 123,624 +3.5%
private field access 55,164 → 56,638 +2.7% 159,485 → 167,136 +4.8%
private methods 61,272 → 61,827 +0.9% 200,901 → 209,342 +4.2%
getter/setter access 64,245 → 64,577 +0.5% 164,952 → 168,095 +1.9%
class decorator (identity) 81,384 → 80,921 -0.6% 52,021 → 52,010 -0.0%
class decorator (wrapping) 47,288 → 47,395 +0.2% 36,506 → 36,155 -1.0%
identity method decorator 57,546 → 58,229 +1.2% 43,100 → 42,210 -2.1%
wrapping method decorator 48,448 → 48,283 -0.3% 38,893 → 38,989 +0.2%
stacked method decorators (x3) 34,125 → 34,465 +1.0% 27,573 → 27,505 -0.2%
identity field decorator 66,422 → 66,653 +0.3% 45,330 → 44,997 -0.7%
field initializer decorator 56,311 → 56,534 +0.4% 40,660 → 39,947 -1.8%
getter decorator (identity) 56,578 → 54,073 -4.4% 40,474 → 39,971 -1.2%
setter decorator (identity) 47,158 → 47,691 +1.1% 34,952 → 34,527 -1.2%
static method decorator 60,976 → 61,014 +0.1% 62,538 → 62,295 -0.4%
static field decorator 71,488 → 72,235 +1.0% 65,899 → 65,969 +0.1%
private method decorator 47,369 → 47,120 -0.5% 36,305 → 36,668 +1.0%
private field decorator 51,973 → 52,717 +1.4% 38,189 → 38,194 +0.0%
plain auto-accessor (no decorator) 89,808 → 90,285 +0.5% 52,396 → 52,274 -0.2%
auto-accessor with decorator 52,261 → 52,568 +0.6% 36,768 → 36,259 -1.4%
decorator writing metadata 44,035 → 44,323 +0.7% 41,153 → 41,119 -0.1%
static getter read 104,006 → 105,137 +1.1% 380,286 → 378,806 -0.4%
static getter/setter pair 76,282 → 77,649 +1.8% 204,306 → 204,089 -0.1%
inherited static getter 59,379 → 59,828 +0.8% 256,839 → 259,590 +1.1%
inherited static setter 63,236 → 63,923 +1.1% 202,669 → 203,777 +0.5%
inherited static getter with this binding 52,926 → 53,706 +1.5% 149,823 → 150,350 +0.4%
closures.js — Interp: 🔴 1, 10 unch. · avg -1.6% · Bytecode: 11 unch. · avg +0.0%
Benchmark Interpreted Δ Bytecode Δ
closure over single variable 156,234 → 146,297 -6.4% 586,697 → 594,035 +1.3%
closure over multiple variables 135,831 → 124,533 🔴 -8.3% 392,226 → 389,811 -0.6%
nested closures 128,662 → 129,394 +0.6% 542,763 → 553,942 +2.1%
function as argument 97,439 → 97,947 +0.5% 488,079 → 492,450 +0.9%
function returning function 123,433 → 122,425 -0.8% 577,984 → 577,341 -0.1%
compose two functions 73,079 → 73,682 +0.8% 347,592 → 349,702 +0.6%
fn.call 158,868 → 157,388 -0.9% 128,433 → 126,417 -1.6%
fn.apply 118,652 → 116,701 -1.6% 86,903 → 88,074 +1.3%
fn.bind 142,007 → 139,725 -1.6% 139,334 → 134,871 -3.2%
recursive sum to 50 11,897 → 11,957 +0.5% 38,407 → 38,540 +0.3%
recursive tree traversal 19,922 → 19,873 -0.2% 58,325 → 57,775 -0.9%
collections.js — Interp: 12 unch. · avg +0.4% · Bytecode: 12 unch. · avg -0.5%
Benchmark Interpreted Δ Bytecode Δ
add 50 elements 6,817 → 7,061 +3.6% 5,507 → 5,491 -0.3%
has lookup (50 elements) 83,952 → 84,992 +1.2% 81,040 → 80,808 -0.3%
delete elements 44,857 → 44,414 -1.0% 35,344 → 35,208 -0.4%
forEach iteration 16,814 → 16,534 -1.7% 14,969 → 14,944 -0.2%
spread to array 36,420 → 38,210 +4.9% 127,329 → 121,922 -4.2%
deduplicate array 43,051 → 43,347 +0.7% 44,683 → 44,538 -0.3%
set 50 entries 5,062 → 5,039 -0.5% 5,322 → 5,165 -3.0%
get lookup (50 entries) 77,689 → 75,400 -2.9% 84,409 → 84,504 +0.1%
has check 117,654 → 117,772 +0.1% 134,438 → 134,177 -0.2%
delete entries 41,557 → 41,270 -0.7% 32,196 → 32,340 +0.4%
forEach iteration 16,322 → 16,398 +0.5% 15,136 → 15,114 -0.1%
keys/values/entries 9,572 → 9,572 -0.0% 18,914 → 19,282 +1.9%
destructuring.js — Interp: 22 unch. · avg +0.4% · Bytecode: 🔴 2, 20 unch. · avg -2.0%
Benchmark Interpreted Δ Bytecode Δ
simple array destructuring 444,379 → 446,246 +0.4% 630,286 → 627,583 -0.4%
with rest element 299,350 → 295,257 -1.4% 486,364 → 478,657 -1.6%
with defaults 439,027 → 441,945 +0.7% 702,181 → 644,782 🔴 -8.2%
skip elements 449,426 → 454,203 +1.1% 721,366 → 689,052 -4.5%
nested array destructuring 191,325 → 193,898 +1.3% 376,384 → 364,725 -3.1%
swap variables 543,283 → 548,322 +0.9% 974,158 → 959,599 -1.5%
simple object destructuring 300,094 → 302,111 +0.7% 512,240 → 523,081 +2.1%
with defaults 351,739 → 357,499 +1.6% 318,828 → 314,215 -1.4%
with renaming 321,752 → 318,862 -0.9% 571,698 → 572,021 +0.1%
nested object destructuring 150,619 → 152,070 +1.0% 247,383 → 248,353 +0.4%
rest properties 188,201 → 189,334 +0.6% 239,754 → 236,502 -1.4%
object parameter 94,663 → 93,039 -1.7% 187,148 → 183,432 -2.0%
array parameter 128,877 → 129,134 +0.2% 317,662 → 312,860 -1.5%
mixed destructuring in map 35,381 → 35,414 +0.1% 33,443 → 32,243 -3.6%
forEach with array destructuring 69,850 → 71,111 +1.8% 136,397 → 134,573 -1.3%
map with array destructuring 71,889 → 72,197 +0.4% 165,045 → 163,199 -1.1%
filter with array destructuring 73,648 → 74,134 +0.7% 196,222 → 189,137 -3.6%
reduce with array destructuring 80,652 → 81,116 +0.6% 183,949 → 180,438 -1.9%
map with object destructuring 78,780 → 78,345 -0.6% 69,160 → 67,816 -1.9%
map with nested destructuring 64,493 → 64,063 -0.7% 54,283 → 57,469 +5.9%
map with rest in destructuring 40,276 → 40,880 +1.5% 44,603 → 41,585 -6.8%
map with defaults in destructuring 59,493 → 59,449 -0.1% 36,943 → 34,208 🔴 -7.4%
fibonacci.js — Interp: 8 unch. · avg -0.2% · Bytecode: 🟢 2, 6 unch. · avg +1.2%
Benchmark Interpreted Δ Bytecode Δ
recursive fib(15) 360 → 364 +1.1% 1,124 → 1,084 -3.6%
recursive fib(20) 30 → 30 +1.6% 98 → 101 +3.8%
recursive fib(15) typed 332 → 333 +0.3% 1,426 → 1,360 -4.6%
recursive fib(20) typed 29 → 30 +0.8% 129 → 129 +0.1%
iterative fib(20) via reduce 12,603 → 12,671 +0.5% 8,320 → 8,030 -3.5%
iterator fib(20) 9,802 → 9,622 -1.8% 14,104 → 15,153 🟢 +7.4%
iterator fib(20) via Iterator.from + take 15,008 → 14,715 -2.0% 15,872 → 17,406 🟢 +9.7%
iterator fib(20) last value via reduce 11,566 → 11,295 -2.3% 12,359 → 12,427 +0.6%
for-of.js — Interp: 7 unch. · avg +0.4% · Bytecode: 🟢 1, 6 unch. · avg +1.5%
Benchmark Interpreted Δ Bytecode Δ
for...of with 10-element array 53,111 → 53,138 +0.1% 156,914 → 149,349 -4.8%
for...of with 100-element array 6,024 → 6,048 +0.4% 21,349 → 21,397 +0.2%
for...of with string (10 chars) 37,733 → 37,375 -0.9% 111,748 → 123,306 🟢 +10.3%
for...of with Set (10 elements) 51,948 → 51,888 -0.1% 156,183 → 159,889 +2.4%
for...of with Map entries (10 entries) 33,449 → 33,670 +0.7% 55,254 → 56,356 +2.0%
for...of with destructuring 44,417 → 44,813 +0.9% 86,408 → 86,892 +0.6%
for-await-of with sync array 49,384 → 50,398 +2.1% 131,140 → 131,296 +0.1%
iterators.js — Interp: 20 unch. · avg +0.2% · Bytecode: 🔴 1, 19 unch. · avg +0.3%
Benchmark Interpreted Δ Bytecode Δ
Iterator.from({next}).toArray() — 20 elements 15,644 → 15,503 -0.9% 18,238 → 15,552 🔴 -14.7%
Iterator.from({next}).toArray() — 50 elements 6,812 → 6,712 -1.5% 7,596 → 7,324 -3.6%
spread pre-wrapped iterator — 20 elements 12,284 → 12,124 -1.3% 15,351 → 16,119 +5.0%
Iterator.from({next}).forEach — 50 elements 4,712 → 4,664 -1.0% 4,907 → 5,221 +6.4%
Iterator.from({next}).reduce — 50 elements 4,792 → 4,730 -1.3% 4,926 → 4,904 -0.4%
wrap array iterator 182,724 → 181,115 -0.9% 116,179 → 119,918 +3.2%
wrap plain {next()} object 10,668 → 10,690 +0.2% 11,778 → 11,838 +0.5%
map + toArray (50 elements) 4,720 → 4,819 +2.1% 5,044 → 5,127 +1.6%
filter + toArray (50 elements) 4,628 → 4,705 +1.7% 5,176 → 5,219 +0.8%
take(10) + toArray (50 element source) 27,920 → 28,167 +0.9% 28,104 → 28,826 +2.6%
drop(40) + toArray (50 element source) 6,608 → 6,680 +1.1% 7,335 → 7,359 +0.3%
chained map + filter + take (100 element source) 8,569 → 8,699 +1.5% 9,211 → 8,907 -3.3%
some + every (50 elements) 2,717 → 2,711 -0.2% 2,978 → 2,966 -0.4%
find (50 elements) 5,883 → 5,952 +1.2% 6,508 → 6,564 +0.9%
array.values().map().filter().toArray() 9,296 → 9,426 +1.4% 9,207 → 9,181 -0.3%
array.values().take(5).toArray() 222,940 → 223,234 +0.1% 141,141 → 149,393 +5.8%
array.values().drop(45).toArray() 205,053 → 204,920 -0.1% 137,160 → 137,908 +0.5%
map.entries() chained helpers 11,247 → 11,311 +0.6% 4,801 → 4,890 +1.8%
set.values() chained helpers 19,300 → 19,382 +0.4% 19,529 → 19,267 -1.3%
string iterator map + toArray 14,670 → 14,593 -0.5% 20,255 → 20,364 +0.5%
json.js — Interp: 20 unch. · avg +0.5% · Bytecode: 🟢 1, 🔴 1, 18 unch. · avg -0.6%
Benchmark Interpreted Δ Bytecode Δ
parse simple object 189,996 → 191,368 +0.7% 155,630 → 153,807 -1.2%
parse nested object 114,537 → 114,938 +0.3% 109,402 → 107,781 -1.5%
parse array of objects 60,730 → 60,913 +0.3% 60,292 → 60,628 +0.6%
parse large flat object 51,362 → 51,819 +0.9% 49,114 → 49,467 +0.7%
parse mixed types 74,277 → 75,269 +1.3% 70,029 → 71,235 +1.7%
stringify simple object 151,274 → 151,330 +0.0% 131,336 → 129,516 -1.4%
stringify nested object 81,444 → 82,650 +1.5% 73,421 → 72,782 -0.9%
stringify array of objects 38,586 → 38,694 +0.3% 35,278 → 34,644 -1.8%
stringify mixed types 69,966 → 69,730 -0.3% 62,617 → 62,809 +0.3%
reviver doubles numbers 46,665 → 46,711 +0.1% 40,559 → 45,688 🟢 +12.6%
reviver filters properties 38,946 → 39,232 +0.7% 46,571 → 45,012 -3.3%
reviver on nested object 53,013 → 53,590 +1.1% 53,178 → 45,825 🔴 -13.8%
reviver on array 29,719 → 30,245 +1.8% 28,413 → 28,881 +1.6%
replacer function doubles numbers 46,165 → 46,433 +0.6% 47,584 → 47,392 -0.4%
replacer function excludes properties 59,721 → 59,743 +0.0% 58,174 → 57,523 -1.1%
array replacer (allowlist) 107,798 → 107,815 +0.0% 88,969 → 89,754 +0.9%
stringify with 2-space indent 79,273 → 80,122 +1.1% 67,589 → 66,327 -1.9%
stringify with tab indent 79,824 → 80,424 +0.8% 67,953 → 66,965 -1.5%
parse then stringify 48,196 → 47,871 -0.7% 44,541 → 44,356 -0.4%
stringify then parse 28,599 → 28,614 +0.1% 26,734 → 26,629 -0.4%
jsx.jsx — Interp: 21 unch. · avg +0.5% · Bytecode: 🟢 1, 🔴 1, 19 unch. · avg +0.1%
Benchmark Interpreted Δ Bytecode Δ
simple element 239,055 → 252,853 +5.8% 670,692 → 677,429 +1.0%
self-closing element 236,764 → 234,695 -0.9% 723,121 → 686,651 -5.0%
element with string attribute 189,389 → 191,131 +0.9% 508,807 → 417,409 🔴 -18.0%
element with multiple attributes 158,991 → 159,590 +0.4% 365,441 → 363,959 -0.4%
element with expression attribute 170,671 → 172,592 +1.1% 408,612 → 432,256 +5.8%
text child 218,796 → 221,196 +1.1% 557,655 → 570,651 +2.3%
expression child 213,100 → 215,711 +1.2% 582,928 → 592,797 +1.7%
mixed text and expression 202,671 → 202,093 -0.3% 523,346 → 538,056 +2.8%
nested elements (3 levels) 80,067 → 80,565 +0.6% 224,203 → 243,323 🟢 +8.5%
sibling children 59,704 → 59,616 -0.1% 178,666 → 173,052 -3.1%
component element 154,043 → 152,059 -1.3% 420,686 → 426,051 +1.3%
component with children 94,214 → 93,397 -0.9% 265,157 → 259,650 -2.1%
dotted component 129,459 → 129,869 +0.3% 306,075 → 312,172 +2.0%
empty fragment 222,854 → 223,683 +0.4% 649,109 → 638,521 -1.6%
fragment with children 59,385 → 58,959 -0.7% 175,364 → 176,917 +0.9%
spread attributes 110,944 → 111,757 +0.7% 108,992 → 110,704 +1.6%
spread with overrides 96,647 → 97,938 +1.3% 82,944 → 83,746 +1.0%
shorthand props 164,251 → 163,032 -0.7% 401,872 → 405,281 +0.8%
nav bar structure 27,497 → 27,811 +1.1% 77,786 → 78,637 +1.1%
card component tree 32,516 → 32,628 +0.3% 85,311 → 85,841 +0.6%
10 list items via Array.from 14,936 → 14,817 -0.8% 23,483 → 23,886 +1.7%
numbers.js — Interp: 11 unch. · avg -1.0% · Bytecode: 11 unch. · avg -0.4%
Benchmark Interpreted Δ Bytecode Δ
integer arithmetic 633,893 → 636,594 +0.4% 1,499,366 → 1,493,020 -0.4%
floating point arithmetic 609,827 → 609,605 -0.0% 1,599,208 → 1,582,970 -1.0%
number coercion 185,254 → 178,053 -3.9% 129,483 → 129,977 +0.4%
toFixed 105,391 → 103,906 -1.4% 203,957 → 205,514 +0.8%
toString 167,649 → 165,131 -1.5% 658,832 → 661,335 +0.4%
valueOf 241,320 → 243,405 +0.9% 920,567 → 925,268 +0.5%
toPrecision 152,648 → 152,103 -0.4% 400,699 → 392,973 -1.9%
Number.isNaN 282,839 → 282,395 -0.2% 165,913 → 166,591 +0.4%
Number.isFinite 278,708 → 275,802 -1.0% 160,585 → 159,540 -0.7%
Number.isInteger 273,114 → 269,614 -1.3% 175,217 → 172,555 -1.5%
Number.parseInt and parseFloat 238,954 → 231,511 -3.1% 150,579 → 148,538 -1.4%
objects.js — Interp: 7 unch. · avg +3.3% · Bytecode: 🔴 1, 6 unch. · avg -0.4%
Benchmark Interpreted Δ Bytecode Δ
create simple object 495,907 → 522,512 +5.4% 859,362 → 868,368 +1.0%
create nested object 231,941 → 239,224 +3.1% 371,687 → 374,700 +0.8%
create 50 objects via Array.from 9,447 → 9,854 +4.3% 8,354 → 8,171 -2.2%
property read 628,804 → 636,162 +1.2% 644,289 → 644,482 +0.0%
Object.keys 292,473 → 300,585 +2.8% 222,120 → 227,977 +2.6%
Object.entries 106,471 → 112,896 +6.0% 74,037 → 68,175 🔴 -7.9%
spread operator 196,590 → 197,472 +0.4% 200,567 → 206,085 +2.8%
promises.js — Interp: 🟢 1, 11 unch. · avg +1.4% · Bytecode: 🟢 1, 🔴 2, 9 unch. · avg -1.0%
Benchmark Interpreted Δ Bytecode Δ
Promise.resolve(value) 578,744 → 579,430 +0.1% 364,342 → 371,934 +2.1%
new Promise(resolve => resolve(value)) 197,515 → 201,294 +1.9% 187,620 → 165,323 🔴 -11.9%
Promise.reject(reason) 575,230 → 564,891 -1.8% 347,651 → 331,563 -4.6%
resolve + then (1 handler) 176,762 → 182,760 +3.4% 147,977 → 152,958 +3.4%
resolve + then chain (3 deep) 66,265 → 73,121 🟢 +10.3% 66,184 → 64,902 -1.9%
resolve + then chain (10 deep) 23,723 → 24,298 +2.4% 23,728 → 23,045 -2.9%
reject + catch + then 108,175 → 107,017 -1.1% 95,630 → 91,525 -4.3%
resolve + finally + then 90,815 → 90,552 -0.3% 75,209 → 80,427 +6.9%
Promise.all (5 resolved) 35,082 → 35,140 +0.2% 27,776 → 25,592 🔴 -7.9%
Promise.race (5 resolved) 36,838 → 37,333 +1.3% 27,442 → 26,501 -3.4%
Promise.allSettled (5 mixed) 29,861 → 30,155 +1.0% 22,345 → 24,175 🟢 +8.2%
Promise.any (5 mixed) 34,842 → 34,589 -0.7% 26,609 → 27,723 +4.2%
strings.js — Interp: 11 unch. · avg -1.1% · Bytecode: 11 unch. · avg +1.1%
Benchmark Interpreted Δ Bytecode Δ
string concatenation 492,689 → 484,029 -1.8% 375,563 → 397,806 +5.9%
template literal 414,297 → 415,309 +0.2% 603,015 → 621,760 +3.1%
string repeat 429,230 → 415,385 -3.2% 938,568 → 910,534 -3.0%
split and join 143,470 → 145,133 +1.2% 261,294 → 267,425 +2.3%
indexOf and includes 170,373 → 168,028 -1.4% 523,217 → 534,119 +2.1%
toUpperCase and toLowerCase 269,686 → 269,100 -0.2% 686,455 → 672,803 -2.0%
slice and substring 168,051 → 165,154 -1.7% 599,345 → 605,912 +1.1%
trim operations 199,839 → 201,344 +0.8% 710,683 → 706,364 -0.6%
replace and replaceAll 222,500 → 215,984 -2.9% 599,678 → 602,051 +0.4%
startsWith and endsWith 140,385 → 138,672 -1.2% 466,741 → 481,617 +3.2%
padStart and padEnd 209,187 → 205,697 -1.7% 540,350 → 540,234 -0.0%
typed-arrays.js — Interp: 22 unch. · avg -0.1% · Bytecode: 22 unch. · avg -0.5%
Benchmark Interpreted Δ Bytecode Δ
new Int32Array(0) 347,439 → 345,805 -0.5% 123,876 → 123,612 -0.2%
new Int32Array(100) 318,795 → 318,740 -0.0% 119,745 → 118,284 -1.2%
new Int32Array(1000) 157,585 → 159,260 +1.1% 89,600 → 87,765 -2.0%
new Float64Array(100) 276,375 → 265,879 -3.8% 113,268 → 115,031 +1.6%
Int32Array.from([...]) 185,151 → 183,662 -0.8% 62,183 → 62,648 +0.7%
Int32Array.of(1, 2, 3, 4, 5) 326,079 → 324,860 -0.4% 248,315 → 239,227 -3.7%
sequential write 100 elements 3,966 → 3,960 -0.1% 12,322 → 12,368 +0.4%
sequential read 100 elements 4,140 → 4,098 -1.0% 9,825 → 9,725 -1.0%
Float64Array write 100 elements 3,630 → 3,663 +0.9% 11,805 → 11,605 -1.7%
fill(42) 44,806 → 44,998 +0.4% 43,422 → 43,314 -0.2%
slice() 213,113 → 213,596 +0.2% 188,388 → 183,283 -2.7%
map(x => x * 2) 8,597 → 8,666 +0.8% 7,005 → 6,986 -0.3%
filter(x => x > 50) 8,722 → 8,682 -0.5% 7,423 → 7,346 -1.0%
reduce (sum) 8,373 → 8,305 -0.8% 6,319 → 6,269 -0.8%
sort() 168,872 → 175,728 +4.1% 148,693 → 153,863 +3.5%
indexOf() 440,188 → 440,575 +0.1% 340,434 → 340,632 +0.1%
reverse() 332,158 → 334,516 +0.7% 261,541 → 262,265 +0.3%
create view over existing buffer 419,692 → 416,933 -0.7% 131,912 → 131,888 -0.0%
subarray() 471,072 → 458,958 -2.6% 341,881 → 336,473 -1.6%
set() from array 575,448 → 575,888 +0.1% 242,255 → 240,313 -0.8%
for-of loop 5,650 → 5,680 +0.5% 18,152 → 17,787 -2.0%
spread into array 20,626 → 20,702 +0.4% 61,250 → 62,179 +1.5%

Measured on ubuntu-latest x64. Changes within ±7% are considered insignificant.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests-wasm/run-wasm-tests.mjs (1)

52-75: Consider caching file content to avoid double reads.

Both parseExpectedLines and isSkipped call readFileSync on the same fixture file. In runFixture, if the file isn't skipped, parseExpectedLines reads it again. For a small test suite this is fine, but you could optimize by reading once and passing the content to both functions.

♻️ Optional: Single-read approach
+function readFixtureSource(fileName) {
+  return readFileSync(fileName, "utf8");
+}
+
-function parseExpectedLines(fileName) {
+function parseExpectedLines(source) {
   const expectedPrefix = "// Expected: ";
-  const source = readFileSync(fileName, "utf8");
   return source
     .split(/\r?\n/)
     .filter((line) => line.startsWith(expectedPrefix))
     .map((line) => line.slice(expectedPrefix.length));
 }

-function isSkipped(fileName) {
-  const source = readFileSync(fileName, "utf8");
+function isSkipped(source) {
   for (const rawLine of source.split(/\r?\n/)) {

Then in runFixture:

const source = readFixtureSource(fixtureFile);
if (isSkipped(source)) { ... }
// later:
const expected = parseExpectedLines(source);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests-wasm/run-wasm-tests.mjs` around lines 52 - 75, Both parseExpectedLines
and isSkipped independently call readFileSync causing duplicate reads; change
the API to accept the file content string instead of reading inside those
functions. Update parseExpectedLines(source) and isSkipped(source) to take a
source string (remove internal readFileSync usage), add a helper like
readFixtureSource in runFixture to read the file once, and pass that source to
isSkipped and parseExpectedLines. Ensure all call sites that previously passed
fileName are updated to pass the cached source string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests-wasm/run-wasm-tests.mjs`:
- Around line 52-75: Both parseExpectedLines and isSkipped independently call
readFileSync causing duplicate reads; change the API to accept the file content
string instead of reading inside those functions. Update
parseExpectedLines(source) and isSkipped(source) to take a source string (remove
internal readFileSync usage), add a helper like readFixtureSource in runFixture
to read the file once, and pass that source to isSkipped and parseExpectedLines.
Ensure all call sites that previously passed fileName are updated to pass the
cached source string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8d855643-0108-4bc6-997b-802ff932808a

📥 Commits

Reviewing files that changed from the base of the PR and between 95a3bf4 and fae9c08.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .github/workflows/pr.yml
  • AGENTS.md
  • docs/wasm-backend.md
  • tests-wasm/run-wasm-tests.mjs
  • tests-wasm/run-wasm-tests.pas
💤 Files with no reviewable changes (1)
  • tests-wasm/run-wasm-tests.pas

@frostney frostney merged commit c34c258 into main Mar 10, 2026
7 checks passed
@frostney frostney deleted the codex/wasm-ci-no-fpc branch March 10, 2026 22:25
@frostney frostney added the internal Refactoring, CI, tooling, cleanup label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal Refactoring, CI, tooling, cleanup

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant