Skip to content

wasm: switch threaded WASI runner to Wasmer - #2725

Merged
cpunion merged 6 commits into
xgo-dev:mainfrom
zhouguangyuan0718:codex/wasi-wasmer-runner-20261003
Oct 4, 2026
Merged

cpunion merged 6 commits into
xgo-dev:mainfrom
zhouguangyuan0718:codex/wasi-wasmer-runner-20261003

Conversation

@zhouguangyuan0718

@zhouguangyuan0718 zhouguangyuan0718 commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Stock WAMR's classic interpreter cannot execute fixed-width SIMD, while LLGo's threaded WASI programs also require shared memory and SjLj exception handling. Switch W32 execution to the unmodified Wasmer 7.5.0 CLI and emit standard Wasm EH directly from LLVM. This is an alternative to maintaining the interpreter patch in #2723.

  • Pin official Wasmer archives and SHA-256 digests; replace WAMR installation/cache integration and remove its three existing patches.
  • Leave backend selection to Wasmer throughout public run/test, GOROOT, standard-library, build-cache, debugging and CI adapters. Its pinned Windows archive selects V8; supported Unix builds prefer Cranelift for these modules. Windows drive-letter paths still receive explicit POSIX guest mappings.
  • Select -wasm-use-legacy-eh=false for compilation and LTO linking. Adapt pthread_exit to wasix_32v1.thread_exit; wasi-libc continues to provide thread startup and TLS.
  • Prevent repeated explicit GC from starving pending allocations: publish collector roots and wait for another allocator lock acquisition after releasing the mutex. Ordinary allocation keeps the pthread mutex fast path.
  • Preserve directory/environment forwarding and separate guest flags with --. Synchronize the inherited wasi.json template with the public runner, and apply Windows directory mapping to the independent GOROOT runner for both Go and LLGo artifacts.
  • Keep Wasmer's module cache enabled. Test runners set host RUST_LOG=off to prevent engine tracing from contaminating guest-output assertions; ordinary runs retain the caller's logging settings. Guest output is never filtered.
  • Add a spawned-thread SIMD/standard-EH regression with v128 calls and exception payloads, exercise WASI SIMD at O0/O2 in CI, and re-enable cross-package recovery in the WASI build-cache fixture. Document the Preview 1 + WASI threads + WASIX thread-exit contract.

Validation of the review fixes on macOS arm64, Go 1.27.0, LLVM/LLD 22.1.8 and official Wasmer 7.5.0, without an explicit backend:

  • The inherited-target regression fails on the previous template and passes after synchronization. A separate real-Wasmer probe confirms that an inherited target can now pass -test.v through the runner; previously Wasmer rejected it as a host option.
  • Focused build/crosscompile/target/GOROOT tests and the complete standard-library-driver unit suite passed. GOROOT tests cover both Go and LLGo commands, Windows drive-letter paths with spaces, POSIX guest directories, guest-argument separation, enabled caching and engine-log suppression.
  • The complete dev/test_wasm_wasi_threads.py acceptance driver passed, including cold/warm cache reuse and guest stdout/stderr/exit status, GC/nogc exceptions, startup, threaded GC, arena boundaries, filesystems, finalizers, reflection/GC races, select stress, standard-library packages and the GOROOT sentinel.
  • test/simd/... passed at O0 and O2. A separate W32-WASI GOROOT helloworld.go comparison passed with both Go and LLGo artifacts.
  • Windows amd64 GOROOT test compilation, shell/Python syntax, workflow YAML parsing and diff checks passed. Windows execution of the updated branch remains a CI check.

Earlier validation includes W32 Go/C++ DWARF and execution at O0/O2 with embedded/external debug artifacts, cold/warm build-cache fixtures, Linux GC allocator-handoff stress, and Windows MSVC/MinGW build-cache execution. All 98 checks on the previous head f8663a224 completed without failures; CI for the updated branch is pending.

Scope notes: this is not a full standard-library compatibility audit. Wasmer 7.5.0 publishes no macOS Intel CLI archive, so that host requires a source-built CLI. The original Thin/Full LTO flag-only runs did not exercise LTO because WASI omitted -flto; #2726 fixes that separately and verifies genuine LTO artifacts. The cumulative Goexit resource-exhaustion report in #2727 also reproduces on unchanged main and remains a separate issue.

@codecov

codecov Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: Migrate WASI runner from WAMR/iwasm to Wasmer

A clean, well-tested migration. Flag strings are consistent across the many call sites (crosscompile.go, wasi.json, dev/*.sh, dev/*.py, test/goroot/*.go, test/buildcache/test.sh, llgo.yml), the host contract tests were updated to match the new Wasmer argv (volume mapping, --env whitelist, -- separator, Windows :/work naming), and no dangling iwasm/build_iwasm.sh references remain in code. dev/install_wasmer.sh pins per-platform SHA-256 digests, verifies before chmod/exec, and fails closed on an unsupported platform.

The notes below are mostly non-blocking; the two worth a reviewer decision are the --disable-cache performance tradeoff and the dropped --max-threads=128.

Behavioral changes worth confirming (not inline)

  • recover now runs under wasip1. This PR deletes test/buildcache/recover_wasip1.go (which stubbed verifyRecoverCache to a no-op because iwasm lacked the setjmp/longjmp imports) and relaxes recover.go / dep1/recover.go to //go:build llgo, so cross-package defer/recover now executes under wasip1 on every WASM cache build. This is the single highest-risk behavioral change and only correct if Wasmer's standard-EH path fully supports LLGo's defer/recover lowering. Worth explicitly confirming the buildcache WASM run was observed to pass (not skipped for a missing wasmer).

Stale WAMR comments outside the diff (migration missed these)

These files were not touched by the PR but now carry comments that contradict the Wasmer runner. Consider a follow-up sweep:

  • dev/wasmstdlib/full.go:138,166-167,171,174-175,179 — timeout justifications cite "WAMR classic Release" / "interpreter run" and WAMR-era second counts (e.g. 217s, 50/75s TLS). Under --cranelift Wasmer is a compiler, not an interpreter, so these attributions and figures are stale.
  • test/std/crypto/x509/x509_test.go:254, test/std/os/os_test.go:1632, test/std/os/go125_symbols_test.go:27, test/std/os/exec/exec_wasm_test.go:75 — rationale/behavior still attributed to "WAMR". The guarded code paths now run under Wasmer; reword or re-verify that Wasmer exhibits the same WASI preview1 rights / /dev/null behavior.

Minor

  • dev/install_wasmer.sh:45-50 — if neither sha256sum nor shasum is present, the comparison still runs and reports a misleading "checksum mismatch" rather than "no SHA-256 tool available". Low impact.
  • internal/build/run.go wasiHostDirectories ignores the passed tempDir on non-Windows (hardcodes /tmp), so a custom TMPDIR maps the guest to host /tmp. Matches prior behavior; the tempDir parameter is only honored on Windows — minor API inconsistency.

Comment thread internal/crosscompile/crosscompile.go Outdated
// before execution and also grants Go's default /tmp directory.
// The 64-client select stress needs more than 64 concurrent pthreads.
WASIThreadedEmulator = `iwasm --max-threads=128 --stack-size=1048576 --heap-size=0 --dir=. --dir=/tmp "{}"`
WASIThreadedEmulator = `wasmer run --cranelift --disable-cache --enable-exceptions --enable-simd --stack-size=1048576 --volume=. --volume=/tmp "{}"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

--disable-cache + --cranelift is likely the worst-case pairing for these short-lived, repeatedly-run test binaries. --disable-cache forces a full Cranelift (optimizing, slow-to-compile) recompile on every invocation, so the compile cost is paid in full while the faster execution is never amortized. This bites wherever the same module runs more than once: dev/test_wasm_wasi_threads.py runs test/go 3x and the deferred-goexit module 10x; test/buildcache/test.sh runs buildcache.wasm ~6x. If disabling the cache is intentional (clean state per run), a one-line rationale comment here would help, since this template is duplicated verbatim across ~8 call sites and the decision is otherwise hard to revisit. Otherwise consider singlepass and/or dropping --disable-cache for the repeated-run paths.

Comment thread internal/crosscompile/crosscompile.go Outdated
// before execution and also grants Go's default /tmp directory.
// The 64-client select stress needs more than 64 concurrent pthreads.
WASIThreadedEmulator = `iwasm --max-threads=128 --stack-size=1048576 --heap-size=0 --dir=. --dir=/tmp "{}"`
WASIThreadedEmulator = `wasmer run --cranelift --disable-cache --enable-exceptions --enable-simd --stack-size=1048576 --volume=. --volume=/tmp "{}"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The old WAMR template carried --max-threads=128 with the rationale "The 64-client select stress needs more than 64 concurrent pthreads." The new Wasmer template drops any thread-count flag, and dev/test_wasm_wasi_threads.py still runs TestConcurrentSelectProposeReplyStress. This now relies on Wasmer 7.5.0's default thread ceiling being >= what that stress needs (>64). Please confirm the default is sufficient, or re-add an explicit cap for parity with the previous guarantee — otherwise that test could newly deadlock/fail.

# The unoptimized testing framework exceeds Wasmtime's locals limit.
"$RUNNER_TEMP/llgo-bin/llgo" test -O2 -target wasi -emulator \
-v -count=1 -timeout=2m ./test/simd/...
for opt in 0 2; do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This now runs the full ./test/simd/... emulator suite twice (-O0 and -O2) where it previously ran once, roughly doubling this step's Wasmer time; combined with --disable-cache (recompile per module run) the cost compounds. The step has no dedicated timeout and inherits the job budget — confirm it still fits. If -O0 coverage was the goal, intentional; just flagging the wall-clock impact.

@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

LLGo baseline benchmarks

54af04d2a338 | workflow run | long-term charts

Program measurements

Platform Workload File size vs base Text size vs base Build vs base Run vs base
Linux cprintf 8568 B 0 B / +0.0% 387 B 0 B / +0.0% 961.622 ms +1.976 ms / +0.2% (worse) 1.240 ms +3.168 us / +0.3% (worse)
Linux cprintf-lto 8408 B 0 B / +0.0% 368 B 0 B / +0.0% 945.822 ms -38.69 ms / -3.9% (better) 1.241 ms -34.18 us / -2.7% (better)
Linux fmtprintf 4880944 B -8 B / -0.0001639% (better) 501619 B 0 B / +0.0% 7.418 s -400.6 ms / -5.1% (better) 3.174 ms +12.23 us / +0.4% (worse)
Linux fmtprintf-lto 3600808 B 0 B / +0.0% 438538 B 0 B / +0.0% 16.267 s -765.8 ms / -4.5% (better) 2.967 ms -113.1 us / -3.7% (better)
Linux println 674952 B 0 B / +0.0% 16855 B 0 B / +0.0% 974.116 ms -39.43 ms / -3.9% (better) 1.595 ms +945 ns / +0.1% (worse)
Linux println-lto 190024 B 0 B / +0.0% 14273 B 0 B / +0.0% 1.310 s -20.5 ms / -1.5% (better) 1.625 ms +30.31 us / +1.9% (worse)
macOS cprintf 50736 B 0 B / +0.0% 4409 B 0 B / +0.0% 847.418 ms -53.02 ms / -5.9% (better) 3.184 ms +536.8 us / +20.3% (worse)
macOS cprintf-lto 50496 B 0 B / +0.0% 161 B 0 B / +0.0% 934.266 ms +670.8 us / +0.1% (worse) 2.387 ms +190.8 us / +8.7% (worse)
macOS fmtprintf 1773456 B 0 B / +0.0% 877780 B 0 B / +0.0% 4.477 s -1.703 s / -27.6% (better) 7.703 ms -2.088 ms / -21.3% (better)
macOS fmtprintf-lto 1360928 B 0 B / +0.0% 762428 B 0 B / +0.0% 12.633 s +3.168 s / +33.5% (worse) 4.601 ms -410.4 us / -8.2% (better)
macOS println 99344 B 0 B / +0.0% 24216 B 0 B / +0.0% 860.335 ms +8.617 ms / +1.0% (worse) 4.089 ms +1.014 ms / +33.0% (worse)
macOS println-lto 83664 B 0 B / +0.0% 21457 B 0 B / +0.0% 1.036 s +41.48 ms / +4.2% (worse) 3.203 ms -37.88 us / -1.2% (better)
Windows MinGW cprintf 651264 B 0 B / +0.0% 4550 B 0 B / +0.0% 1.805 s +64.82 ms / +3.7% (worse) 3.613 ms +131.7 us / +3.8% (worse)
Windows MinGW cprintf-lto 43520 B 0 B / +0.0% 4486 B 0 B / +0.0% 1.795 s +74.07 ms / +4.3% (worse) 3.546 ms +77.9 us / +2.2% (worse)
Windows MinGW fmtprintf 5432832 B 0 B / +0.0% 600310 B 0 B / +0.0% 7.441 s -34.77 ms / -0.5% (better) 9.254 ms +1.117 ms / +13.7% (worse)
Windows MinGW fmtprintf-lto 4127232 B 0 B / +0.0% 546582 B 0 B / +0.0% 15.025 s +56.19 ms / +0.4% (worse) 8.222 ms -122.2 us / -1.5% (better)
Windows MinGW println 706560 B 0 B / +0.0% 25190 B 0 B / +0.0% 1.744 s +42.28 ms / +2.5% (worse) 6.494 ms -1.834 ms / -22.0% (better)
Windows MinGW println-lto 208896 B 0 B / +0.0% 22054 B 0 B / +0.0% 2.013 s +616.2 us / +0.03062% (worse) 6.528 ms -19.6 us / -0.3% (better)
Windows MinGW 386 cprintf 601600 B 0 B / +0.0% 5326 B 0 B / +0.0% 1.341 s +13.61 ms / +1.0% (worse) 3.954 ms -79.1 us / -2.0% (better)
Windows MinGW 386 cprintf-lto 103424 B 0 B / +0.0% 5094 B 0 B / +0.0% 1.393 s +30.8 ms / +2.3% (worse) 3.869 ms +30.5 us / +0.8% (worse)
Windows MinGW 386 fmtprintf 4745216 B 0 B / +0.0% 472478 B 0 B / +0.0% 5.959 s -9.733 ms / -0.2% (better) 8.070 ms +313 us / +4.0% (worse)
Windows MinGW 386 fmtprintf-lto 4148736 B 0 B / +0.0% 451114 B 0 B / +0.0% 11.941 s +301.4 ms / +2.6% (worse) 8.101 ms -118.2 us / -1.4% (better)
Windows MinGW 386 println 653312 B 0 B / +0.0% 21490 B 0 B / +0.0% 1.366 s +25.16 ms / +1.9% (worse) 6.996 ms +125.2 us / +1.8% (worse)
Windows MinGW 386 println-lto 258560 B 0 B / +0.0% 19306 B 0 B / +0.0% 1.575 s -1.623 ms / -0.1% (better) 7.321 ms +305.8 us / +4.4% (worse)
Windows MinGW ARM64 cprintf 661504 B 0 B / +0.0% 4408 B 0 B / +0.0% 1.968 s -801.6 us / -0.04071% (better) 6.599 ms -294 us / -4.3% (better)
Windows MinGW ARM64 cprintf-lto 43520 B 0 B / +0.0% 4340 B 0 B / +0.0% 2.031 s +27.72 ms / +1.4% (worse) 7.033 ms +42.5 us / +0.6% (worse)
Windows MinGW ARM64 fmtprintf 5343744 B 0 B / +0.0% 510876 B 0 B / +0.0% 7.603 s +235.4 ms / +3.2% (worse) 13.554 ms +532.3 us / +4.1% (worse)
Windows MinGW ARM64 fmtprintf-lto 4302336 B 0 B / +0.0% 477264 B 0 B / +0.0% 14.058 s -465.8 ms / -3.2% (better) 13.797 ms -997.2 us / -6.7% (better)
Windows MinGW ARM64 println 714240 B 0 B / +0.0% 23884 B 0 B / +0.0% 1.964 s -8.539 ms / -0.4% (better) 11.610 ms -290.6 us / -2.4% (better)
Windows MinGW ARM64 println-lto 215552 B 0 B / +0.0% 21232 B 0 B / +0.0% 2.235 s +1.499 ms / +0.1% (worse) 11.585 ms +374 us / +3.3% (worse)
Windows MSVC cprintf 893952 B 0 B / +0.0% 65798 B 0 B / +0.0% 1.868 s +295.1 ms / +18.8% (worse) 3.436 ms +96.8 us / +2.9% (worse)
Windows MSVC cprintf-lto 289792 B 0 B / +0.0% 65734 B 0 B / +0.0% 1.652 s -26.07 ms / -1.6% (better) 3.460 ms +15.9 us / +0.5% (worse)
Windows MSVC fmtprintf 5732864 B 0 B / +0.0% 695862 B 0 B / +0.0% 7.224 s +172.9 ms / +2.5% (worse) 9.701 ms +811.3 us / +9.1% (worse)
Windows MSVC fmtprintf-lto 4449792 B 0 B / +0.0% 646134 B 0 B / +0.0% 13.674 s +116.4 ms / +0.9% (worse) 8.598 ms +17.9 us / +0.2% (worse)
Windows MSVC println 1017344 B 0 B / +0.0% 120854 B 0 B / +0.0% 1.617 s +33.2 ms / +2.1% (worse) 7.545 ms +206.4 us / +2.8% (worse)
Windows MSVC println-lto 528384 B 0 B / +0.0% 118390 B 0 B / +0.0% 1.921 s +93.11 ms / +5.1% (worse) 7.189 ms +123.1 us / +1.7% (worse)
Windows MSVC 386 cprintf 513536 B 0 B / +0.0% 3931 B 0 B / +0.0% 1.240 s +4.891 ms / +0.4% (worse) 4.335 ms -378.1 us / -8.0% (better)
Windows MSVC 386 cprintf-lto 44032 B 0 B / +0.0% 3853 B 0 B / +0.0% 1.349 s +46.6 ms / +3.6% (worse) 4.378 ms -740.8 us / -14.5% (better)
Windows MSVC 386 fmtprintf 4479488 B 0 B / +0.0% 455868 B 0 B / +0.0% 5.647 s -279.9 ms / -4.7% (better) 9.541 ms -1.204 ms / -11.2% (better)
Windows MSVC 386 fmtprintf-lto 3899392 B 0 B / +0.0% 426651 B 0 B / +0.0% 10.615 s -1.083 s / -9.3% (better) 8.763 ms -2.465 ms / -22.0% (better)
Windows MSVC 386 println 567296 B 0 B / +0.0% 20340 B 0 B / +0.0% 1.241 s -216.1 ms / -14.8% (better) 8.337 ms +128.7 us / +1.6% (worse)
Windows MSVC 386 println-lto 199168 B 0 B / +0.0% 18501 B 0 B / +0.0% 1.442 s -66.49 ms / -4.4% (better) 8.482 ms +749.9 us / +9.7% (worse)
Windows MSVC ARM64 cprintf 662528 B 0 B / +0.0% 4192 B 0 B / +0.0% 1.573 s -20.27 ms / -1.3% (better) 6.625 ms -80.6 us / -1.2% (better)
Windows MSVC ARM64 cprintf-lto 47616 B 0 B / +0.0% 4084 B 0 B / +0.0% 1.557 s -37.16 ms / -2.3% (better) 6.718 ms -463.7 us / -6.5% (better)
Windows MSVC ARM64 fmtprintf 5339648 B 0 B / +0.0% 510808 B 0 B / +0.0% 6.470 s -155.4 ms / -2.3% (better) 13.915 ms +849.4 us / +6.5% (worse)
Windows MSVC ARM64 fmtprintf-lto 4309504 B 0 B / +0.0% 477924 B 0 B / +0.0% 12.551 s -208.1 ms / -1.6% (better) 13.343 ms -799.3 us / -5.7% (better)
Windows MSVC ARM64 println 715264 B 0 B / +0.0% 23908 B 0 B / +0.0% 1.565 s -24.83 ms / -1.6% (better) 11.858 ms +132.2 us / +1.1% (worse)
Windows MSVC ARM64 println-lto 220672 B 0 B / +0.0% 21380 B 0 B / +0.0% 1.784 s +194.7 us / +0.01092% (worse) 11.247 ms -930.4 us / -7.6% (better)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 14.560 ns/op +0.14 ns/op / +1.0% (worse)
Linux BenchmarkMergeCompilerFlags 199.300 ns/op +5.4 ns/op / +2.8% (worse)
Linux BenchmarkMergeLinkerFlags 131.200 ns/op +2.9 ns/op / +2.3% (worse)
Linux BenchmarkChannelBuffered 55.060 ns/op -0.2 ns/op / -0.4% (better)
Linux BenchmarkChannelHandoff 13686 ns/op +471 ns/op / +3.6% (worse)
Linux BenchmarkDefer 46.570 ns/op -0.76 ns/op / -1.6% (better)
Linux BenchmarkDirectCall 1.176 ns/op +0.009 ns/op / +0.8% (worse)
Linux BenchmarkGlobalRead 1.165 ns/op -0.001 ns/op / -0.1% (better)
Linux BenchmarkGlobalWrite 7.824 ns/op +0.05 ns/op / +0.6% (worse)
Linux BenchmarkGoroutine 24328 ns/op -218 ns/op / -0.9% (better)
Linux BenchmarkInterfaceCall 5.841 ns/op -0.044 ns/op / -0.7% (better)
Linux BenchmarkRuntimeGetG 3.025 ns/op +0.006 ns/op / +0.2% (worse)
macOS BenchmarkLookupPCRandom 18.260 ns/op +3.45 ns/op / +23.3% (worse)
macOS BenchmarkMergeCompilerFlags 175.200 ns/op +71.9 ns/op / +69.6% (worse)
macOS BenchmarkMergeLinkerFlags 104.300 ns/op +33.57 ns/op / +47.5% (worse)
macOS BenchmarkChannelBuffered 26.260 ns/op +0.73 ns/op / +2.9% (worse)
macOS BenchmarkChannelHandoff 5754 ns/op -1801 ns/op / -23.8% (better)
macOS BenchmarkDefer 40.910 ns/op +7.97 ns/op / +24.2% (worse)
macOS BenchmarkDirectCall 1.216 ns/op +0.163 ns/op / +15.5% (worse)
macOS BenchmarkGlobalRead 1.201 ns/op +0.133 ns/op / +12.5% (worse)
macOS BenchmarkGlobalWrite 1.330 ns/op +0.275 ns/op / +26.1% (worse)
macOS BenchmarkGoroutine 62100 ns/op +22992 ns/op / +58.8% (worse)
macOS BenchmarkInterfaceCall 5.139 ns/op +1.168 ns/op / +29.4% (worse)
macOS BenchmarkRuntimeGetG 2.337 ns/op +0.095 ns/op / +4.2% (worse)
Windows MinGW BenchmarkLookupPCRandom 13.220 ns/op -0.01 ns/op / -0.1% (better)
Windows MinGW BenchmarkMergeCompilerFlags 615.400 ns/op -18.8 ns/op / -3.0% (better)
Windows MinGW BenchmarkMergeLinkerFlags 549.400 ns/op +4.6 ns/op / +0.8% (worse)
Windows MinGW BenchmarkChannelBuffered 30.410 ns/op +0.13 ns/op / +0.4% (worse)
Windows MinGW BenchmarkChannelHandoff 964.700 ns/op +19.7 ns/op / +2.1% (worse)
Windows MinGW BenchmarkDefer 56.410 ns/op -1.45 ns/op / -2.5% (better)
Windows MinGW BenchmarkDirectCall 1.548 ns/op -0.002 ns/op / -0.1% (better)
Windows MinGW BenchmarkGlobalRead 1.550 ns/op +0.001 ns/op / +0.1% (worse)
Windows MinGW BenchmarkGlobalWrite 2.470 ns/op -0.006 ns/op / -0.2% (better)
Windows MinGW BenchmarkGoroutine 91375 ns/op -627 ns/op / -0.7% (better)
Windows MinGW BenchmarkInterfaceCall 8.376 ns/op -0.006 ns/op / -0.1% (better)
Windows MinGW BenchmarkRuntimeGetG 2.478 ns/op -0.003 ns/op / -0.1% (better)
Windows MinGW 386 BenchmarkLookupPCRandom 21.550 ns/op 0 ns/op / +0.0%
Windows MinGW 386 BenchmarkMergeCompilerFlags 557.300 ns/op +0.8 ns/op / +0.1% (worse)
Windows MinGW 386 BenchmarkMergeLinkerFlags 516.200 ns/op -1.9 ns/op / -0.4% (better)
Windows MinGW 386 BenchmarkChannelBuffered 33.870 ns/op -0.02 ns/op / -0.1% (better)
Windows MinGW 386 BenchmarkChannelHandoff 699.400 ns/op +17.8 ns/op / +2.6% (worse)
Windows MinGW 386 BenchmarkDefer 36.250 ns/op +0.27 ns/op / +0.8% (worse)
Windows MinGW 386 BenchmarkDirectCall 1.357 ns/op -0.001 ns/op / -0.1% (better)
Windows MinGW 386 BenchmarkGlobalRead 1.356 ns/op -0.001 ns/op / -0.1% (better)
Windows MinGW 386 BenchmarkGlobalWrite 6.979 ns/op 0 ns/op / +0.0%
Windows MinGW 386 BenchmarkGoroutine 72439 ns/op -996 ns/op / -1.4% (better)
Windows MinGW 386 BenchmarkInterfaceCall 7.356 ns/op -0.012 ns/op / -0.2% (better)
Windows MinGW 386 BenchmarkRuntimeGetG 1.631 ns/op +0.001 ns/op / +0.1% (worse)
Windows MinGW ARM64 BenchmarkLookupPCRandom 12.120 ns/op +0.02 ns/op / +0.2% (worse)
Windows MinGW ARM64 BenchmarkMergeCompilerFlags 581.300 ns/op -3.9 ns/op / -0.7% (better)
Windows MinGW ARM64 BenchmarkMergeLinkerFlags 551.600 ns/op +0.8 ns/op / +0.1% (worse)
Windows MinGW ARM64 BenchmarkChannelBuffered 37.500 ns/op -0.1 ns/op / -0.3% (better)
Windows MinGW ARM64 BenchmarkChannelHandoff 3088 ns/op +273 ns/op / +9.7% (worse)
Windows MinGW ARM64 BenchmarkDefer 56.740 ns/op +2.01 ns/op / +3.7% (worse)
Windows MinGW ARM64 BenchmarkDirectCall 0.663 ns/op -0.0004 ns/op / -0.1% (better)
Windows MinGW ARM64 BenchmarkGlobalRead 0.663 ns/op -0.0007 ns/op / -0.1% (better)
Windows MinGW ARM64 BenchmarkGlobalWrite 0.737 ns/op +0.0002 ns/op / +0.02713% (worse)
Windows MinGW ARM64 BenchmarkGoroutine 67146 ns/op +1949 ns/op / +3.0% (worse)
Windows MinGW ARM64 BenchmarkInterfaceCall 4.141 ns/op -0.005 ns/op / -0.1% (better)
Windows MinGW ARM64 BenchmarkRuntimeGetG 1.808 ns/op +0.038 ns/op / +2.1% (worse)
Windows MSVC BenchmarkLookupPCRandom 13.210 ns/op +0.1 ns/op / +0.8% (worse)
Windows MSVC BenchmarkMergeCompilerFlags 641.500 ns/op +32.7 ns/op / +5.4% (worse)
Windows MSVC BenchmarkMergeLinkerFlags 585.100 ns/op +42.1 ns/op / +7.8% (worse)
Windows MSVC BenchmarkChannelBuffered 29.970 ns/op +0.12 ns/op / +0.4% (worse)
Windows MSVC BenchmarkChannelHandoff 1154 ns/op +127 ns/op / +12.4% (worse)
Windows MSVC BenchmarkDefer 62.850 ns/op +7.6 ns/op / +13.8% (worse)
Windows MSVC BenchmarkDirectCall 1.557 ns/op +0.01 ns/op / +0.6% (worse)
Windows MSVC BenchmarkGlobalRead 1.552 ns/op +0.006 ns/op / +0.4% (worse)
Windows MSVC BenchmarkGlobalWrite 2.473 ns/op +0.004 ns/op / +0.2% (worse)
Windows MSVC BenchmarkGoroutine 89686 ns/op +850 ns/op / +1.0% (worse)
Windows MSVC BenchmarkInterfaceCall 9.117 ns/op +0.1 ns/op / +1.1% (worse)
Windows MSVC BenchmarkRuntimeGetG 2.513 ns/op +0.035 ns/op / +1.4% (worse)
Windows MSVC 386 BenchmarkLookupPCRandom 21.570 ns/op -0.07 ns/op / -0.3% (better)
Windows MSVC 386 BenchmarkMergeCompilerFlags 605 ns/op +13.4 ns/op / +2.3% (worse)
Windows MSVC 386 BenchmarkMergeLinkerFlags 545 ns/op -9.8 ns/op / -1.8% (better)
Windows MSVC 386 BenchmarkChannelBuffered 33.930 ns/op +0.02 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkChannelHandoff 715.400 ns/op -10.4 ns/op / -1.4% (better)
Windows MSVC 386 BenchmarkDefer 40.730 ns/op +1.46 ns/op / +3.7% (worse)
Windows MSVC 386 BenchmarkDirectCall 1.357 ns/op -0.001 ns/op / -0.1% (better)
Windows MSVC 386 BenchmarkGlobalRead 1.356 ns/op -0.001 ns/op / -0.1% (better)
Windows MSVC 386 BenchmarkGlobalWrite 6.977 ns/op -0.007 ns/op / -0.1% (better)
Windows MSVC 386 BenchmarkGoroutine 81748 ns/op +3569 ns/op / +4.6% (worse)
Windows MSVC 386 BenchmarkInterfaceCall 7.331 ns/op -0.012 ns/op / -0.2% (better)
Windows MSVC 386 BenchmarkRuntimeGetG 1.629 ns/op -0.001 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkLookupPCRandom 12.150 ns/op +0.05 ns/op / +0.4% (worse)
Windows MSVC ARM64 BenchmarkMergeCompilerFlags 573.600 ns/op +8.8 ns/op / +1.6% (worse)
Windows MSVC ARM64 BenchmarkMergeLinkerFlags 531.500 ns/op -1.4 ns/op / -0.3% (better)
Windows MSVC ARM64 BenchmarkChannelBuffered 38.540 ns/op -0.03 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkChannelHandoff 1835 ns/op -145 ns/op / -7.3% (better)
Windows MSVC ARM64 BenchmarkDefer 60.570 ns/op -0.92 ns/op / -1.5% (better)
Windows MSVC ARM64 BenchmarkDirectCall 0.663 ns/op -0.0001 ns/op / -0.01507% (better)
Windows MSVC ARM64 BenchmarkGlobalRead 0.663 ns/op -0.0009 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkGlobalWrite 3.794 ns/op -0.015 ns/op / -0.4% (better)
Windows MSVC ARM64 BenchmarkGoroutine 63183 ns/op +8740 ns/op / +16.1% (worse)
Windows MSVC ARM64 BenchmarkInterfaceCall 4.148 ns/op +0.003 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkRuntimeGetG 1.808 ns/op 0 ns/op / +0.0%
Timer runtime benchmarks
Platform Operation and runtime ns/op vs base
Linux AfterFuncZeroDelivery/Go 913.400 ns/op +5.2 ns/op / +0.6% (worse)
Linux AfterFuncZeroDelivery/LLGo 38013 ns/op -8842 ns/op / -18.9% (better)
Linux CreateStop/Go 289.100 ns/op -6 ns/op / -2.0% (better)
Linux CreateStop/LLGo 1889 ns/op +129 ns/op / +7.3% (worse)
Linux RearmStopped/Go 114.900 ns/op -1.2 ns/op / -1.0% (better)
Linux RearmStopped/LLGo 1131 ns/op -317 ns/op / -21.9% (better)
Linux ResetActive/Go 67.480 ns/op -1.23 ns/op / -1.8% (better)
Linux ResetActive/LLGo 898.500 ns/op +177.4 ns/op / +24.6% (worse)
Linux ResetHeap1024/Go 67.240 ns/op +0.12 ns/op / +0.2% (worse)
Linux ResetHeap1024/LLGo 173.400 ns/op -2.3 ns/op / -1.3% (better)
macOS AfterFuncZeroDelivery/Go 588.500 ns/op +163.5 ns/op / +38.5% (worse)
macOS AfterFuncZeroDelivery/LLGo 85779 ns/op +15712 ns/op / +22.4% (worse)
macOS CreateStop/Go 211.900 ns/op +68 ns/op / +47.3% (worse)
macOS CreateStop/LLGo 664.400 ns/op +251.1 ns/op / +60.8% (worse)
macOS RearmStopped/Go 80.060 ns/op +22.9 ns/op / +40.1% (worse)
macOS RearmStopped/LLGo 460.200 ns/op +111 ns/op / +31.8% (worse)
macOS ResetActive/Go 56.940 ns/op +8.59 ns/op / +17.8% (worse)
macOS ResetActive/LLGo 148.200 ns/op -17.2 ns/op / -10.4% (better)
macOS ResetHeap1024/Go 59.820 ns/op +17.16 ns/op / +40.2% (worse)
macOS ResetHeap1024/LLGo 93.980 ns/op +5.47 ns/op / +6.2% (worse)
Windows MinGW AfterFuncZeroDelivery/Go 556.100 ns/op -13.2 ns/op / -2.3% (better)
Windows MinGW AfterFuncZeroDelivery/LLGo 183122 ns/op -2573 ns/op / -1.4% (better)
Windows MinGW CreateStop/Go 112.500 ns/op -8 ns/op / -6.6% (better)
Windows MinGW CreateStop/LLGo 451.800 ns/op +45.7 ns/op / +11.3% (worse)
Windows MinGW RearmStopped/Go 31.630 ns/op -1.4 ns/op / -4.2% (better)
Windows MinGW RearmStopped/LLGo 273.700 ns/op +6.4 ns/op / +2.4% (worse)
Windows MinGW ResetActive/Go 20.050 ns/op -0.63 ns/op / -3.0% (better)
Windows MinGW ResetActive/LLGo 176.100 ns/op +29.8 ns/op / +20.4% (worse)
Windows MinGW ResetHeap1024/Go 20.520 ns/op -0.46 ns/op / -2.2% (better)
Windows MinGW ResetHeap1024/LLGo 127.700 ns/op +2.2 ns/op / +1.8% (worse)
Windows MinGW 386 AfterFuncZeroDelivery/Go 772.600 ns/op +9.9 ns/op / +1.3% (worse)
Windows MinGW 386 AfterFuncZeroDelivery/LLGo 128825 ns/op -3366 ns/op / -2.5% (better)
Windows MinGW 386 CreateStop/Go 166.200 ns/op -2.2 ns/op / -1.3% (better)
Windows MinGW 386 CreateStop/LLGo 410.500 ns/op +20.7 ns/op / +5.3% (worse)
Windows MinGW 386 RearmStopped/Go 56.570 ns/op -0.09 ns/op / -0.2% (better)
Windows MinGW 386 RearmStopped/LLGo 279.300 ns/op -1.9 ns/op / -0.7% (better)
Windows MinGW 386 ResetActive/Go 32.530 ns/op -0.05 ns/op / -0.2% (better)
Windows MinGW 386 ResetActive/LLGo 897.800 ns/op +666.2 ns/op / +287.7% (worse)
Windows MinGW 386 ResetHeap1024/Go 32.830 ns/op -0.03 ns/op / -0.1% (better)
Windows MinGW 386 ResetHeap1024/LLGo 152.900 ns/op +2.9 ns/op / +1.9% (worse)
Windows MinGW ARM64 AfterFuncZeroDelivery/Go 658.800 ns/op -3.7 ns/op / -0.6% (better)
Windows MinGW ARM64 AfterFuncZeroDelivery/LLGo 151004 ns/op -1007 ns/op / -0.7% (better)
Windows MinGW ARM64 CreateStop/Go 215.700 ns/op +5.2 ns/op / +2.5% (worse)
Windows MinGW ARM64 CreateStop/LLGo 363.800 ns/op -5.9 ns/op / -1.6% (better)
Windows MinGW ARM64 RearmStopped/Go 70.580 ns/op +0.04 ns/op / +0.1% (worse)
Windows MinGW ARM64 RearmStopped/LLGo 250.500 ns/op +0.5 ns/op / +0.2% (worse)
Windows MinGW ARM64 ResetActive/Go 31.100 ns/op +0.05 ns/op / +0.2% (worse)
Windows MinGW ARM64 ResetActive/LLGo 116 ns/op -4.2 ns/op / -3.5% (better)
Windows MinGW ARM64 ResetHeap1024/Go 31.080 ns/op -0.02 ns/op / -0.1% (better)
Windows MinGW ARM64 ResetHeap1024/LLGo 125.100 ns/op +0.3 ns/op / +0.2% (worse)
Windows MSVC AfterFuncZeroDelivery/Go 562 ns/op +2.9 ns/op / +0.5% (worse)
Windows MSVC AfterFuncZeroDelivery/LLGo 179212 ns/op +561 ns/op / +0.3% (worse)
Windows MSVC CreateStop/Go 117 ns/op +1.3 ns/op / +1.1% (worse)
Windows MSVC CreateStop/LLGo 403.100 ns/op -30 ns/op / -6.9% (better)
Windows MSVC RearmStopped/Go 31.480 ns/op -0.24 ns/op / -0.8% (better)
Windows MSVC RearmStopped/LLGo 251.800 ns/op +3.8 ns/op / +1.5% (worse)
Windows MSVC ResetActive/Go 20.120 ns/op +0.1 ns/op / +0.5% (worse)
Windows MSVC ResetActive/LLGo 145.800 ns/op +3 ns/op / +2.1% (worse)
Windows MSVC ResetHeap1024/Go 20.490 ns/op +0.01 ns/op / +0.04883% (worse)
Windows MSVC ResetHeap1024/LLGo 124.600 ns/op +0.2 ns/op / +0.2% (worse)
Windows MSVC 386 AfterFuncZeroDelivery/Go 763.900 ns/op -17.5 ns/op / -2.2% (better)
Windows MSVC 386 AfterFuncZeroDelivery/LLGo 148210 ns/op +73 ns/op / +0.04928% (worse)
Windows MSVC 386 CreateStop/Go 167.500 ns/op -4.8 ns/op / -2.8% (better)
Windows MSVC 386 CreateStop/LLGo 367.900 ns/op -18.5 ns/op / -4.8% (better)
Windows MSVC 386 RearmStopped/Go 57.070 ns/op +0.31 ns/op / +0.5% (worse)
Windows MSVC 386 RearmStopped/LLGo 268.800 ns/op +7.2 ns/op / +2.8% (worse)
Windows MSVC 386 ResetActive/Go 32.580 ns/op -0.06 ns/op / -0.2% (better)
Windows MSVC 386 ResetActive/LLGo 885.200 ns/op +5.6 ns/op / +0.6% (worse)
Windows MSVC 386 ResetHeap1024/Go 32.860 ns/op -0.03 ns/op / -0.1% (better)
Windows MSVC 386 ResetHeap1024/LLGo 142.200 ns/op -0.1 ns/op / -0.1% (better)
Windows MSVC ARM64 AfterFuncZeroDelivery/Go 665.400 ns/op -0.2 ns/op / -0.03005% (better)
Windows MSVC ARM64 AfterFuncZeroDelivery/LLGo 164535 ns/op -1530 ns/op / -0.9% (better)
Windows MSVC ARM64 CreateStop/Go 197.900 ns/op +0.1 ns/op / +0.1% (worse)
Windows MSVC ARM64 CreateStop/LLGo 430 ns/op +0.1 ns/op / +0.02326% (worse)
Windows MSVC ARM64 RearmStopped/Go 70.550 ns/op +0.02 ns/op / +0.02836% (worse)
Windows MSVC ARM64 RearmStopped/LLGo 275.900 ns/op +4 ns/op / +1.5% (worse)
Windows MSVC ARM64 ResetActive/Go 30.990 ns/op -0.1 ns/op / -0.3% (better)
Windows MSVC ARM64 ResetActive/LLGo 144 ns/op +1.7 ns/op / +1.2% (worse)
Windows MSVC ARM64 ResetHeap1024/Go 31.080 ns/op -0.08 ns/op / -0.3% (better)
Windows MSVC ARM64 ResetHeap1024/LLGo 136.800 ns/op +0.5 ns/op / +0.4% (worse)

Compared with 783ec4fd3d57 measured in the same runner job.

@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

LLGo WebAssembly build benchmarks

afcaf6f372f2 | workflow run | long-term charts

WebAssembly output sizes
Example, profile and compiler Wasm module vs base Generated JS glue vs base
cprintf/j32-emscripten/LLGo 154193 B 0 B / +0.0% 88742 B 0 B / +0.0%
cprintf/j32-goos-js/LLGo 152295 B 0 B / +0.0% 73165 B 0 B / +0.0%
cprintf/j64-emscripten-memory64/LLGo 141248 B 0 B / +0.0% 92630 B 0 B / +0.0%
cprintf/w32-goos-wasip1/LLGo 153508 B +660 B / +0.4% (worse) 0 B 0 B / 0.0%
cprintf/w32-wasi/LLGo 154198 B +638 B / +0.4% (worse) 0 B 0 B / 0.0%
fmtprintf/j32-emscripten/LLGo 3213612 B +51 B / +0.001587% (worse) 132442 B 0 B / +0.0%
fmtprintf/j32-goos-js/Go 2526852 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/j32-goos-js/LLGo 3192706 B +46 B / +0.001441% (worse) 101635 B 0 B / +0.0%
fmtprintf/j64-emscripten-memory64/LLGo 2950218 B +50 B / +0.001695% (worse) 139285 B 0 B / +0.0%
fmtprintf/w32-goos-wasip1/Go 2500019 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/w32-goos-wasip1/LLGo 2349336 B +1857 B / +0.1% (worse) 0 B 0 B / 0.0%
fmtprintf/w32-wasi/LLGo 2345976 B +1835 B / +0.1% (worse) 0 B 0 B / 0.0%
j32-emscripten/LLGo 153428 B 0 B / +0.0% 88742 B 0 B / +0.0%
j32-goos-js/Go 1895533 B 0 B / +0.0% 0 B 0 B / 0.0%
j32-goos-js/LLGo 151768 B 0 B / +0.0% 73165 B 0 B / +0.0%
j64-emscripten-memory64/LLGo 140582 B 0 B / +0.0% 92630 B 0 B / +0.0%
reflectcall/j32-emscripten/LLGo 1543965 B +67 B / +0.00434% (worse) 105908 B 0 B / +0.0%
reflectcall/j32-goos-js/Go 2191221 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/j32-goos-js/LLGo 1546420 B +49 B / +0.003169% (worse) 90331 B 0 B / +0.0%
reflectcall/j64-emscripten-memory64/LLGo 1428634 B +64 B / +0.00448% (worse) 111641 B 0 B / +0.0%
reflectcall/w32-goos-wasip1/Go 2205707 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/w32-goos-wasip1/LLGo 1277776 B +955 B / +0.1% (worse) 0 B 0 B / 0.0%
reflectcall/w32-wasi/LLGo 1275362 B +933 B / +0.1% (worse) 0 B 0 B / 0.0%
w32-goos-wasip1/Go 1909947 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-goos-wasip1/LLGo 153155 B +660 B / +0.4% (worse) 0 B 0 B / 0.0%
w32-wasi/LLGo 153845 B +638 B / +0.4% (worse) 0 B 0 B / 0.0%
LLGo WebAssembly build measurements
Example and profile Build vs base
j32-emscripten 6.581 s +326.2 ms / +5.2% (worse)
j32-goos-js 6.459 s +238.1 ms / +3.8% (worse)
j64-emscripten-memory64 5.965 s +577.6 ms / +10.7% (worse)
reflectcall/w32-wasi 24.816 s +784.3 ms / +3.3% (worse)
w32-goos-wasip1 4.407 s +109.6 ms / +2.5% (worse)
w32-wasi 4.765 s +716.3 ms / +17.7% (worse)

Compared with 5f1f13897af7 measured in the same runner job.

@cpunion cpunion left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed f8663a224. The migration direction looks reasonable, but I found two P2 gaps in runner configuration, detailed inline: inherited WASI targets bypass the host-contract adaptation, and the independent GOROOT runner still selects Cranelift on Windows.

Validation: the focused build/crosscompile/target/wasmstdlib/GOROOT unit tests passed, including the existing GC mutex-reacquisition regression. The latest 98 checks had no failed or unfinished entries. I verified the inherited-target argument construction on this PR and reproduced the CLI argument rejection with locally installed Wasmer 7.3.0; I also checked the relevant 7.5.0 CLI parsing and Windows build configuration in upstream sources. I did not rerun the full pinned Wasmer 7.5.0 matrix or execute the Windows GOROOT path locally.

Separate existing issue: #2727 records cumulative thread-resource exhaustion after repeated runtime.Goexit(). It reproduces on unchanged main with WAMR as well as this PR with local Wasmer 7.3.0, so it is not attributed to this PR. Both configurations failed in 3/3 repeated runs after completed 225 and before completed 250, while normal-return controls completed all 400 goroutines.

Comment thread targets/wasi.json Outdated
"wasm-profile": "w32",
"wasm-provider": "wasi",
"emulator": "iwasm --max-threads=128 --stack-size=1048576 --heap-size=0 --dir=. --dir=/tmp \"{}\""
"emulator": "wasmer run --cranelift --disable-cache --enable-exceptions --enable-simd --stack-size=1048576 --volume=. --volume=/tmp \"{}\""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Keep the inherited runner template in sync with WASIThreadedEmulator

This JSON template still includes --disable-cache, while crosscompile.WASIThreadedEmulator no longer does. runEmuCmdTo applies the host-contract adaptation only when the entire template equals that constant. The built-in wasi and wasip1 names hide the mismatch because UseWithGOARMAndToolchain explicitly replaces their emulator, but a downstream target inheriting this file does not get that replacement:

{
  "inherits": ["wasi"]
}

I verified that such a target retains --volume=. and gets no guest PWD/PATH, no -- argument separator, and no Windows V8/volume adaptation. Passing a guest flag such as -test.v then fails at the Wasmer CLI instead of running the program:

error: unexpected argument '-t' found

Please synchronize this template with the constant and add a regression exercising an inherited target through the runner, not only the two built-in target names.

Comment thread test/goroot/wasm_profile_test.go Outdated
args := []string{"--max-threads=128", "--stack-size=1048576", "--heap-size=0", "--dir=" + dir, "--dir=/tmp", artifact}
return "iwasm", append(args, programArgs...), gorootRuntimeEnv(env), nil
if p.runner == "wasmer" {
args := []string{"run", "--cranelift", "--disable-cache", "--enable-exceptions", "--enable-simd", "--stack-size=1048576", "--volume=" + dir, "--volume=/tmp", artifact, "--"}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Apply the Windows runner contract to GOROOT execution too

This independent execution path always selects --cranelift, but the official Windows Wasmer 7.5.0 archive installed by this PR only supplies V8. Unlike the public run/test path, gorootArtifactCommand does not go through runEmuCmdTo, so Windows -wasm-profile=W32-WASI fails before either the Go baseline or LLGo artifact can run. The current unit tests assert this same hard-coded command on every host, so they do not detect the missing adaptation.

Please apply the same Windows backend selection (--v8) and explicit host-to-guest volume mappings used by the public runner, and make the regression expectations platform-aware.

@cpunion
cpunion merged commit 463897d into xgo-dev:main Oct 4, 2026
98 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants