Skip to content

[wasi] Stand up CoreCLR-WASI library-test leg (per-app corerun relink)#130745

Open
lewing wants to merge 22 commits into
dotnet:mainfrom
lewing:lewing-wasi-coreclr-library-tests
Open

[wasi] Stand up CoreCLR-WASI library-test leg (per-app corerun relink)#130745
lewing wants to merge 22 commits into
dotnet:mainfrom
lewing:lewing-wasi-coreclr-library-tests

Conversation

@lewing

@lewing lewing commented Jul 15, 2026

Copy link
Copy Markdown
Member

Draft. Stands up a CoreCLR-WASI library-test leg (smoke scope: System.Runtime.Tests), addressing part of #130129.

Builds on the CoreCLR-WASI wasihost corehost (#130816, merged), which ships libWasiHost.a in the runtime pack. This PR generates each test's own reverse P/Invoke thunks and links them into that host per-app.

What this does

Adds a per-app native link of the shipping wasihost corehost (libWasiHost.a) so a test's own [UnmanagedCallersOnly] reverse P/Invoke thunks are covered — mirroring the browser-CoreCLR relink. The baked callhelpers table (libcoreclr_gen_static.a) only covers framework top-level UCO callbacks; library/test callbacks (e.g. a nested WindowsUILanguageHelper.EnumUiLanguagesCallback) are unknown to it and trap at first use without the per-app link.

  • Host: consumes libWasiHost.a from the wasihost corehost ([wasi] Add CoreCLR-WASI corehost (wasihost) #130816) — the leg does not manufacture its own host.
  • Per-app link (src/mono/wasi/build/WasiApp.CoreCLR.targets): ManagedToNativeGenerator (TargetOS=wasi) → compile the generated callhelpers with the wasi-sdk clang → link libWasiHost.a from the runtime-pack static archives + the app callhelper .o (replacing libcoreclr_gen_static.a) via wasm-component-ld. The wasi:http import that System.Net.* pulls in is declared with -Wl,--component-type (WasiHttpWorld_component_type.wit, as Mono does); wasmtime is given -S http by the test targets.
  • Generator (ManagedToNativeGenerator.cs / PInvokeTableGenerator.cs): a WarnOnUnresolvedPInvokeModules flag downgrades WASM0066 to a message for untrimmed library-test closures (whose foreign-platform P/Invokes are unresolved on wasm and never called), so they don't fail the build under warn-as-error.
  • Test/CI wiring: tests.wasi.targets, sendtohelix-wasi.targets, tests.proj smoke set, and a wasi-wasm-coreclr-library-tests CI template (non-gating, rolling).

The leg runs with full ICU globalization (non-invariant): the wasihost corehost preloads icudt.dat from CORE_ROOT.

Validation

Locally (macOS arm64, wasi-sdk + wasmtime): the baseline (clr+libs+host+packs -os wasi -c Release) builds green and stages libWasiHost.a from the wasihost corehost into the runtime pack. The System.Runtime.Tests bundle links the host per-app and discovers + runs the full suite:

Discovered: managed/System.Runtime.Tests.dll (found 9966 of 9966 test cases)
Starting:   managed/System.Runtime.Tests.dll

Managed exception dispatch through the interpreter EH + reverse UCO thunks works with no precode assert. A System.Tests.VersionTests subset ran 251/251 passing (WASM EXIT 0).

Relationship to other work

Tracked follow-ups (not in this PR)

Note

This pull request was authored with GitHub Copilot.

Copilot AI review requested due to automatic review settings July 15, 2026 01:15
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 6 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @BrzVlad, @janvorli
See info in area-owners.md if you want to be subscribed.

Copilot AI 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.

Pull request overview

This PR wires up an initial CoreCLR-on-WASI library tests lane (smoke scope: System.Runtime.Tests) by adding a per-app relink of the corerun host so app/test [UnmanagedCallersOnly] reverse-thunk callhelpers are generated and linked into the host, and by hooking that into Helix + CI.

Changes:

  • Fix reverse P/Invoke thunk key generation for nested [UnmanagedCallersOnly] callbacks so runtime lookup keys match.
  • Add a CoreCLR-specific WASI app-builder target set that generates callhelper sources and relinks corerun per app using wasi-sdk + wasm-component-ld.
  • Add smoke test selection + Helix/CI plumbing for a non-gating CoreCLR-WASI library-tests leg.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs Align nested-type namespace handling for reverse-thunk key generation.
src/mono/wasi/build/WasiApp.InTree.targets Select CoreCLR vs Mono WASI app-builder targets based on RuntimeFlavor.
src/mono/wasi/build/WasiApp.InTree.props Configure WASI in-tree defaults for RuntimeFlavor (e.g., invariant globalization for CoreCLR bring-up).
src/mono/wasi/build/WasiApp.CoreCLR.targets New: CoreCLR-WASI app-builder that copies framework bits and performs per-app corerun relink with generated callhelpers.
src/libraries/tests.proj Add CoreCLR-WASI smoke project set (initially System.Runtime.Tests) and keep Mono-WASI smoke set intact.
src/libraries/sendtohelix-wasi.targets Distinguish CoreCLR work items on the shared WASI queue and adjust payload staging for CoreCLR vs Mono.
src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props Add libWasiHost.a to the platform manifest so it ships in the runtime pack.
src/coreclr/hosts/corerun/CMakeLists.txt Build/install a WASI host static archive (libWasiHost.a) for relink scenarios.
eng/testing/tests.wasi.targets Teach WASI test runner args/env for CoreCLR (corerun, CORE_ROOT, EH proposal flag).
eng/pipelines/runtime.yml Add a rolling/non-gating CoreCLR-WASI library-tests smoke leg template invocation.
eng/pipelines/common/templates/wasi-wasm-coreclr-library-tests.yml New: pipeline template for CoreCLR-WASI Helix library tests (smoke-only bring-up leg).

Comment thread src/mono/wasi/build/WasiApp.InTree.targets
Comment thread src/libraries/sendtohelix-wasi.targets
Comment thread eng/pipelines/common/templates/wasi-wasm-coreclr-library-tests.yml Outdated
Comment thread src/mono/wasi/build/WasiApp.InTree.props Outdated
Copilot AI review requested due to automatic review settings July 15, 2026 01:24

Copilot AI 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.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment thread src/mono/wasi/build/WasiApp.CoreCLR.targets Outdated
Comment thread src/mono/wasi/build/WasiApp.CoreCLR.targets Outdated
Comment thread src/mono/wasi/build/WasiApp.CoreCLR.targets Outdated
Comment thread src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs
Copilot AI review requested due to automatic review settings July 15, 2026 01:40

Copilot AI 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.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread src/mono/wasi/build/WasiApp.CoreCLR.targets Outdated
Copilot AI review requested due to automatic review settings July 15, 2026 02:44

Copilot AI 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.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Comment thread src/mono/wasi/build/WasiApp.CoreCLR.targets Outdated
Copilot AI review requested due to automatic review settings July 15, 2026 03:05

Copilot AI 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.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 15, 2026 04:33

Copilot AI 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.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Comment thread src/mono/wasi/build/WasiApp.CoreCLR.targets Outdated
lewing and others added 2 commits July 16, 2026 21:59
…ime.Tests

With ICU working the leg's only failures are 3 genuine wasm-interpreter behavior
differences (CI: Tests run 72926, Passed 72812, Failed 3, Skipped 111):

- RuntimeFeatureTests.DynamicCode_Jit: the interpreter doesn't JIT-compile, so
  IsDynamicCodeCompiled is false. Extend the existing browser-CoreCLR ActiveIssue
  (dotnet#123011) from IsBrowser to IsWasm so it also covers wasi.
- ExceptionTests.ThrowStatementDoesNotResetExceptionStackLine{Same,Other}Method:
  the interpreter reports different rethrow stack-line info. These are
  [ConditionalFact(HasAssemblyFiles)] - browser skips (no assembly files) but wasi
  has real .dll's so they run and fail. ActiveIssue for IsWasi+IsCoreCLR (dotnet#130796).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ea71f7e7-5477-4e58-bf1a-ca27d4b23d74
…library-test leg

Adapt the CoreCLR-WASI library-test leg to build off the wasihost corehost
PR (dotnet#130816). Both PRs produced libWasiHost.a in the runtime pack native dir;
dotnet#130816 supplies it from a proper, statically-linked corehost
(src/native/corehost/wasihost), so this leg no longer needs to manufacture its
own host from corerun.

- corerun/CMakeLists.txt: drop the WasiHost-Static target (libWasiHost.a now
  comes from the wasihost corehost).
- corerun.cpp: revert the wasi ICU preload + weak GlobalizationNative_LoadICUData
  decl; wasihost.cpp loads icudt.dat from CORE_ROOT.
- Directory.Build.props: drop the duplicate libWasiHost.a platform-manifest entry
  (dotnet#130816 adds it in the wasi-specific section).
- WasiApp.CoreCLR.targets: the per-app link already links the pack's
  libWasiHost.a; remove the dead WasiCoreCLRRelinkCoreRun opt-out and the
  _WasiCopyPrebuiltCoreRun fallback (there is no prebuilt corerun executable in
  the wasi CoreCLR runtime pack), and update comments to describe linking the
  shipping wasihost archive.
- Refresh corerun/relink wording in the WASI app-builder and test/CI wiring
  comments to reflect the wasihost host.

The per-app native link (ManagedToNativeGenerator -> compile callhelpers ->
link libWasiHost.a + runtime-pack static libs + app callhelper .o via
wasm-component-ld) is unchanged and matches the link dotnet#130816 validated.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f00a53c8-f7ba-4417-8ea6-30d0a1507a81
Copilot AI review requested due to automatic review settings July 17, 2026 03:08
@lewing
lewing force-pushed the lewing-wasi-coreclr-library-tests branch from 8e32d3b to c3e9eb0 Compare July 17, 2026 03:08
@lewing
lewing marked this pull request as ready for review July 17, 2026 03:10
@lewing
lewing requested review from akoeplinger and maraf as code owners July 17, 2026 03:10
@lewing
lewing requested a review from radekdoulik July 17, 2026 03:10
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
10 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI 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.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs Outdated
Comment thread eng/testing/tests.wasi.targets
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comment thread src/libraries/tests.proj
Comment on lines +579 to +583
<!-- wasi smoke tests CoreCLR. Start minimal (single library) for the bring-up leg;
expand as gaps close. See https://github.com/dotnet/runtime/issues/130129. -->
<ItemGroup Condition="'$(TargetOS)' == 'wasi' and '$(RunAOTCompilation)' != 'true' and '$(RuntimeFlavor)' == 'CoreCLR'">
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Runtime.Tests\System.Runtime.Tests.csproj" />
</ItemGroup>
Comment thread src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs
@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
  "version": 5,
  "last_dispatched_commit": "400271c150b54d691b57f581553b13f185419ffc",
  "last_dispatched_base_ref": "main",
  "last_dispatched_base_sha": "f079ec9d15385ccc314129e62249d0838daced6b",
  "last_reviewed_commit": "67c7ec50329e720407ce2342d799f113525ebf3f",
  "last_reviewed_base_ref": "main",
  "last_reviewed_base_sha": "f079ec9d15385ccc314129e62249d0838daced6b",
  "last_recorded_worker_run_id": "29687155833",
  "review_attempt_commit": "400271c150b54d691b57f581553b13f185419ffc",
  "review_attempt_base_ref": "main",
  "review_attempt_count": 1,
  "max_review_attempts": 5,
  "review_history_format": "holistic-review-disclosure-v1",
  "review_history": [
    {
      "commit": "67c7ec50329e720407ce2342d799f113525ebf3f",
      "review_id": 4730771238
    }
  ]
}

@github-actions github-actions 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.

Holistic Review

Motivation: Justified. The PR stands up a CoreCLR-WASI library-test leg (smoke scope: System.Runtime.Tests) toward #130129, mirroring the existing browser-CoreCLR relink pattern. The core problem is real: the baked libcoreclr_gen_static.a only covers framework top-level [UnmanagedCallersOnly] callbacks, so app/test reverse P/Invoke thunks (e.g. nested UCO callbacks) trap at first use without a per-app link.

Approach: Reasonable and consistent with the codebase. A new WasiApp.CoreCLR.targets performs a per-app ManagedToNativeGenerator → wasi-sdk clang compile → wasm-component-ld link of libWasiHost.a, closely paralleling BrowserWasmApp.CoreCLR.targets. The RuntimeFlavor-conditioned splits in the shared Mono WASI targets/props and the new non-gating rolling CI leg are the established way to fork Mono vs CoreCLR wiring. The generator change is a small, backward-compatible opt-in flag.

Summary: ⚠️ Needs Human Review. No blocking correctness defects found in the changed code, and the C#/test changes are low-risk. However, this is a draft with a large, hand-authored native link line (library set/order, EH flags, memory sizes, component-type WIT) validated only locally on macOS arm64; a human with WASI toolchain expertise should confirm the link recipe and that the new rolling CI leg goes green on Helix before this is considered done. Key items to focus on below.


Detailed Findings

✅ Generator flag — backward-compatible and correctly scoped

WarnOnUnresolvedPInvokeModules defaults to true, so existing browser/Mono callers are unaffected; only the new WASI library-test leg opts out (WasiApp.CoreCLR.targets line 170). Downgrading WASM0066 to a low-importance message for untrimmed cross-platform closures (whose foreign P/Invokes are genuinely unreachable on wasm) is a sensible way to avoid failing under warn-as-error, and the ignoredModules.Add(...) guard dedups the message per module. One behavioral nuance worth noting (not a bug): in warn mode WASM0066 is emitted per-method, while in message mode it is deduped per-module — intended, but asymmetric.

✅ Test disabling — correct and minimal

The two [ActiveIssue(...IsWasi, ...IsCoreCLR)] annotations in ExceptionTests.cs reference a tracked issue (#130796) and a valid PlatformDetection.IsWasi predicate, scoping the skip to exactly the CoreCLR-WASI leg. This is the right mechanism rather than deleting/rewriting the tests.

⚠️ Native link recipe — broad, hand-maintained, locally-validated only

WasiApp.CoreCLR.targets encodes a large explicit static-lib set with order-sensitive resolution (duplicated libminipal.a, mid-list -lstdc++), a full VM -D define set that must stay in lockstep with the runtime callhelper compile to avoid ABI/EH/interp thunk skew, fixed memory/stack sizes, and -wasm-use-legacy-eh=false. The comments acknowledge this mirrors the corerun CMake link line, but there is no build-time guard that keeps the define set or lib list in sync with the runtime's own link — future drift would surface only as runtime traps, not build errors. A reviewer familiar with the wasihost link should confirm the recipe and consider whether any of it can be sourced from the pack rather than duplicated (the PR already tracks header relocation via #128362).

⚠️ Verification is local-only; CI leg is new and non-gating

Validation is a single local macOS arm64 run (9966 cases discovered, a 251-case subset passing). The full suite pass/fail on the actual Helix wasi_wasm queue is unproven in-PR, and the leg is deliberately smoke-only, rolling, and alwaysRun-on-rolling (non-PR-gating). That is appropriate for a bring-up leg, but means regressions here won't block PRs — human sign-off should include confirming the rolling leg is green after merge.

💡 Cross-cutting parity note

The generator comment and WasiApp.CoreCLR.targets (lines 150-151) note that BrowserWasmApp.CoreCLR.targets should set the same WarnOnUnresolvedPInvokeModules=false flag when its library-test leg runs untrimmed closures. Consider filing/linking a follow-up so the browser sibling doesn't silently diverge (fail under warn-as-error) when it reaches the same scope.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 149 AIC · ⌖ 10.4 AIC · ⊞ 10K

Comment thread src/mono/wasi/build/WasiApp.CoreCLR.targets Outdated
…der targets

WasiApp.CoreCLR.targets hardcoded WasmMainAssemblyFileName=WasmTestRunner.dll,
which is a test-runner default in a general app-builder targets file — wrong for
a normal (non-test) app. The test path already sets it in
eng/testing/tests.wasi.targets, and the browser sibling
(BrowserWasmApp.CoreCLR.targets) does not set it either. Remove the default here
and let test-specific files supply it. Addresses PR review (radekdoulik).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f00a53c8-f7ba-4417-8ea6-30d0a1507a81
Copilot AI review requested due to automatic review settings July 20, 2026 19:40

Copilot AI 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.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread eng/pipelines/runtime.yml
Comment on lines +171 to +176
- template: /eng/pipelines/common/templates/wasi-wasm-coreclr-library-tests.yml
parameters:
platforms:
- wasi_wasm
shouldRunSmokeOnly: true
alwaysRun: ${{ variables.isRollingBuild }}

@github-actions github-actions 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.

Holistic Review

Motivation: This PR stands up a non-gating CoreCLR-WASI library-test leg (smoke scope: System.Runtime.Tests), addressing part of #130129. It links the shipping wasihost corehost (libWasiHost.a, from merged #130816) per-app so each test's own reverse P/Invoke thunks are covered, and adds generator, test, and CI wiring. The single new commit since the prior review (400271c1) removes a hardcoded WasmMainAssemblyFileName=WasmTestRunner.dll default from the general-purpose WasiApp.CoreCLR.targets.

Approach: The incremental change deletes one conditional property assignment from src/mono/wasi/build/WasiApp.CoreCLR.targets. A test-runner default (WasmTestRunner.dll) does not belong in a general app-builder targets file; it is wrong for a normal non-test app. The test path continues to supply the value via eng/testing/tests.wasi.targets (line 9, Condition="'$(WasmMainAssemblyFileName)' == ''"), and the browser sibling BrowserWasmApp.CoreCLR.targets likewise does not set it. Both the removed line and the test-targets line were conditional defaults, so import ordering does not change the effective value for the test leg.

Summary: The incremental change is a clean, correctly-scoped cleanup that removes a test-specific default from a shared targets file while preserving the value for the test path. No functional regression for the library-test leg is expected, and it brings the WASI targets in line with the browser sibling. No new actionable findings. Verdict: LGTM for the incremental change.

Assessment History

  • review 4730771238 reviewed commit 67c7ec50329e720407ce2342d799f113525ebf3f. Its verdict and the current verdict are both LGTM; the assessment is unchanged. The only new commit (400271c1) removes a misplaced test-runner default from the app-builder targets, which does not alter the PR's motivation, approach, or risk profile.

Detailed Findings

No actionable findings in the incremental change. The removal is verified safe: eng/testing/tests.wasi.targets still defines WasmMainAssemblyFileName conditionally for the test path, and the browser CoreCLR sibling target follows the same convention of not defaulting it in the shared app-builder targets.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 49.5 AIC · ⌖ 10.4 AIC · ⊞ 10K

InterpToNativeOutputPath="$(_WasiInterpToNativeTablePath)"
CacheFilePath="$(_WasiM2NCachePath)"
TargetOS="wasi"
WarnOnUnresolvedPInvokeModules="false"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be false only for library test projects?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

it should probably be false by default since pinvoke problems are runtime failures

@radekdoulik radekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Besides the WarnOnUnresolvedPInvokeModules question it LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-CodeGen-Interpreter-coreclr os-wasi Related to WASI variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants