Skip to content

[wasm] Split CoreCLR thunks by target OS (browser vs wasi)#129549

Open
lewing wants to merge 4 commits into
dotnet:mainfrom
lewing:wasm-thunk-split-per-target
Open

[wasm] Split CoreCLR thunks by target OS (browser vs wasi)#129549
lewing wants to merge 4 commits into
dotnet:mainfrom
lewing:wasm-thunk-split-per-target

Conversation

@lewing

@lewing lewing commented Jun 17, 2026

Copy link
Copy Markdown
Member

Browser and WASI CoreLib expose different sets of P/Invokes and UCO callbacks:

  • WASI CoreLib pulls in the Unix Interop.Libraries.cs path, so it references Sys (sockets, fcntl, host entry, etc.) symbols that browser CoreLib does not.
  • Browser CoreLib references JS-interop pinvokes/callbacks (SystemJS_, SystemInteropJS_, JavaScriptExports.*) that WASI does not.

A single generated callhelpers-{pinvoke,reverse,interp-to-managed}.cpp cannot be correct for both. Split the checked-in baseline copies into src/coreclr/vm/wasm/{browser,wasi}/ and pick the appropriate subdir in vm/CMakeLists.txt based on CLR_CMAKE_TARGET_WASI.

Also parameterize the WasmAppBuilder.CoreCLR generator with a TargetOS property (default "browser" to preserve existing behavior). The generator now filters DllImport and UnmanagedCallersOnly methods by the target's [SupportedOSPlatform] / [UnsupportedOSPlatform] attributes so a future regen against a wasi build naturally drops browser-only entries and vice-versa. BrowserWasmApp.CoreCLR.targets explicitly passes TargetOS="browser".

Browser and WASI CoreLib expose different sets of P/Invokes and UCO
callbacks:

  * WASI CoreLib pulls in the Unix Interop.Libraries.cs path, so it
    references Sys (sockets, fcntl, host entry, etc.) symbols that
    browser CoreLib does not.
  * Browser CoreLib references JS-interop pinvokes/callbacks
    (SystemJS_*, SystemInteropJS_*, JavaScriptExports.*) that WASI
    does not.

A single generated callhelpers-{pinvoke,reverse,interp-to-managed}.cpp
cannot be correct for both. Split the checked-in baseline copies into
src/coreclr/vm/wasm/{browser,wasi}/ and pick the appropriate subdir
in vm/CMakeLists.txt based on CLR_CMAKE_TARGET_WASI.

Also parameterize the WasmAppBuilder.CoreCLR generator with a TargetOS
property (default "browser" to preserve existing behavior). The
generator now filters DllImport and UnmanagedCallersOnly methods by
the target's [SupportedOSPlatform] / [UnsupportedOSPlatform] attributes
so a future regen against a wasi build naturally drops browser-only
entries and vice-versa. BrowserWasmApp.CoreCLR.targets explicitly
passes TargetOS="browser".
Copilot AI review requested due to automatic review settings June 17, 2026 23:51
@lewing lewing requested review from akoeplinger and maraf as code owners June 17, 2026 23:51
@lewing lewing requested a review from radekdoulik June 17, 2026 23:52
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
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 separates WebAssembly CoreCLR “callhelpers” thunk sources for browser vs WASI so the runtime can compile against the correct P/Invoke + reverse-P/Invoke surface for each target, and wires the VM build to pick the appropriate thunk set based on CLR_CMAKE_TARGET_WASI. It also extends the WasmAppBuilder CoreCLR table generator pipeline with a TargetOS input intended to filter platform-specific entries.

Changes:

  • Split checked-in WASM thunk baselines into src/coreclr/vm/wasm/{browser,wasi}/ and select the subdir from src/coreclr/vm/CMakeLists.txt.
  • Add a TargetOS MSBuild task property and propagate it into the CoreCLR P/Invoke collection pipeline.
  • Update browser CoreCLR app build targets to pass TargetOS="browser" explicitly.

Reviewed changes

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

Show a summary per file
File Description
src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs Passes targetOS through to the collector used when scanning assemblies.
src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs Adds TargetOS-aware filtering logic for platform attributes (type-level).
src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs Introduces a TargetOS property and forwards it into the generator pipeline.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targets Sets TargetOS="browser" when invoking ManagedToNativeGenerator.
src/coreclr/vm/wasm/wasi/callhelpers-pinvoke.cpp WASI-specific checked-in baseline P/Invoke override table.
src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp WASI-specific checked-in baseline interp-to-managed thunk table.
src/coreclr/vm/wasm/browser/callhelpers-reverse.cpp Browser reverse-thunk baseline updated (includes a manual addition).
src/coreclr/vm/wasm/browser/callhelpers-pinvoke.cpp Browser-specific checked-in baseline P/Invoke override table.
src/coreclr/vm/wasm/browser/callhelpers-interp-to-managed.cpp Browser-specific checked-in baseline interp-to-managed thunk table.
src/coreclr/vm/CMakeLists.txt Selects browser vs WASI thunk sources via WASM_THUNK_SUBDIR.
Comments suppressed due to low confidence (2)

src/coreclr/vm/wasm/browser/callhelpers-reverse.cpp:1189

  • This manual reverse-thunk addition references System.Threading.WasiFinalizerScheduler.ScheduleFinalization, but there is no such managed type/method anywhere in this repo. At runtime LookupUnmanagedCallersOnlyMethodByName throws if the type can’t be found (TypeName::GetTypeFromAsmQualifiedName(..., TRUE)), so this would hard-fail. Unless the managed implementation is added in this PR, these manual entries need to be removed (and ideally generated instead of hand-maintained).
    src/coreclr/vm/wasm/browser/callhelpers-reverse.cpp:1282
  • g_ReverseThunks also contains a manual entry for WasiFinalizerScheduler.ScheduleFinalization. If the managed type/method isn’t added, this mapping should be removed as it can trigger the same hard failure when resolved.

Comment thread src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs
Comment on lines 231 to 235
foreach (CustomAttributeData cattr in CustomAttributeData.GetCustomAttributes(type))
{
try
{
if (cattr.AttributeType.FullName == "System.Runtime.Versioning.UnsupportedOSPlatformAttribute" &&

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.

Addressed in e05eefdIsUnsupportedOnPlatform now walks method-level, then up through declaring types, then falls back to the assembly. Attribute evaluation is factored into a shared helper (EvaluatePlatformAttributes returning Supported/Unsupported/Unknown) so each scope can short-circuit cleanly, and assembly results are cached separately from the type cache. Assemblies like System.Runtime.InteropServices.JavaScript that carry [assembly: SupportedOSPlatform("browser")] are now correctly excluded from a TargetOS="wasi" regen.

Note

AI-generated content by GitHub Copilot CLI.

lewing and others added 2 commits June 17, 2026 19:04
The 'MANUAL ADDITION' block in src/coreclr/vm/wasm/browser/callhelpers-reverse.cpp
that wired up Call_/MD_WasiFinalizerScheduler_ScheduleFinalization was a
leftover from when browser and WASI shared a single checked-in copy of
the generated thunks. It is not produced (and not needed) by a fresh
browser-targeted regen because:

  * WasiFinalizerScheduler.cs lives inside an
    <ItemGroup Condition="'$(TargetsWasi)' == 'true'"> in
    System.Private.CoreLib.Shared.projitems, so it is only compiled
    into the WASI CoreLib.
  * Browser CoreCLR uses the JS-host-provided
    SystemJS_ScheduleFinalization import (setTimeout(callback, 0));
    no managed callback registration is involved on browser.
  * Browser CoreLib does not contain a [UnmanagedCallersOnly]
    WasiFinalizerScheduler.ScheduleFinalization method, so the
    reverse thunk has no managed target on browser.

After the thunk split (1d75035) the WASI side now regenerates this
entry naturally (visible in wasi/callhelpers-reverse.cpp with no
'MANUAL' marker). Remove the dead block + map entry from the browser
copy. Verified browser and WASI corerun both still build.
…rm attrs

Two review fixes for the CoreCLR WasmAppBuilder generator changes:

* ManagedToNativeGenerator now validates and normalizes the TargetOS
  property. Empty/whitespace and unknown values fail the task with an
  actionable error instead of silently producing empty filtered tables;
  the value is lower-cased so casing differences in the MSBuild input
  don't cause every IsSupportedOSPlatform check to miss.

* PInvokeCollector.IsUnsupportedOnPlatform now considers method-level
  and assembly-level [SupportedOSPlatform] / [UnsupportedOSPlatform]
  attributes in addition to the type's own attributes (walking up
  through declaring types first, then falling back to the assembly).
  Assemblies like System.Runtime.InteropServices.JavaScript that carry
  [assembly: SupportedOSPlatform("browser")] are now correctly excluded
  from a TargetOS="wasi" regen and vice versa. Assembly-level results
  are cached separately from the type cache.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 18, 2026 00:26
@lewing

lewing commented Jun 18, 2026

Copy link
Copy Markdown
Member Author

@copilot review

Pushed e05eefd in response to this review:

  • ManagedToNativeGenerator.cs:42 (TargetOS validation) — addressed: empty/whitespace and unknown values now fail the task with an actionable error; value is normalized to lowercase.
  • PInvokeCollector.cs:235 (assembly-level filtering) — addressed: IsUnsupportedOnPlatform now walks method → declaring types → assembly via a shared EvaluatePlatformAttributes helper, with a separate cache for assembly-level results.

The two suppressed/low-confidence comments about the WasiFinalizerScheduler MANUAL ADDITION in browser/callhelpers-reverse.cpp (lines 1189 and 1282 on commit 46c7403) were valid and are already removed in commit a63d5d99f97 of this same PR.

Note

AI-generated content by GitHub Copilot CLI.

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 7 out of 11 changed files in this pull request and generated no new comments.

Comment thread src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs Outdated
Comment thread src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs Outdated
Per Marek's review feedback. With the TargetOS validation now in
ManagedToNativeGenerator.Execute(), the default "browser" on the
PInvokeCollector and PInvokeTableGenerator constructors is dead weight
that would also hide future misuse. Make it a required parameter
everywhere; the only existing call site
(ManagedToNativeGenerator.ExecuteInternal) already passes TargetOS
explicitly so no behaviour changes.

PInvokeTableGenerator's isLibraryMode optional parameter was reordered
to come before the now-required targetOS (C# disallows a required
parameter after an optional one). Reverting to required-required
order matches the only caller and keeps the API symmetric with
PInvokeCollector.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@lewing lewing enabled auto-merge (squash) June 18, 2026 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants