Skip to content

[wasm] Emit producers and build_id custom sections (native, webcil, R2R) - #130768

Open
pavelsavara with Copilot wants to merge 29 commits into
mainfrom
copilot/research-implementation-direction
Open

pavelsavara with Copilot wants to merge 29 commits into
mainfrom
copilot/research-implementation-direction

Conversation

Copilot AI commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Emits the WebAssembly producers
and build_id custom sections
from the .NET toolchain.

The application-facing Browser behavior is enabled for .NET 12 and later. Older target frameworks
retain their existing WebAssembly SDK behavior.

Metadata ownership

Artifact producers build_id
Mono/CoreCLR dotnet.native.wasm Runtime-pack dotnet-producers.s, merged by wasm-ld when available Generated by wasm-ld
Regular Webcil Emitted by WebcilWasmWrapper SHA-256 of the Webcil payload
R2R Webcil Emitted through WasmObjectWriter SHA-256 of the generated module
NativeAOT relocatable Wasm object Emitted through WasmObjectWriter None; the final linker owns the executable ID

Each final Wasm file owns its identity. Runtime-pack files keep their original IDs, while native
relinks and newly generated Webcil files receive IDs from the component that creates them.

Emscripten and Binaryen preserve the native linker ID through post-link transformations. When
Binaryen generates a source map, it records the same value as debugId, keeping the transformed
module associated with its debug information.

Native runtime producers

Current Mono and CoreCLR Browser runtime packs contain flavor-specific
runtimes/browser-wasm/native/dotnet-producers.s files. Native relinks pass the source to
Emscripten, wasm-ld merges it with compiler-provided metadata, and
-sEMIT_PRODUCERS_SECTION=1 preserves the merged section.

.NET contributes:

  • processed-by=<Mono|CoreCLR>
  • sdk=.NET

$(WasmEmitProducersSection)=false disables this native runtime contribution.

The source is optional when a newer WebAssembly SDK resolves an older runtime pack that predates
it. Native relinking still succeeds and retains the linker-generated build ID, but the final module
has no producers section. Runtime-repository builds continue to generate an equivalent source
before linking when the runtime pack is not available yet.

Managed Wasm producers

The compiler writer hierarchy emits:

  • R2R Webcil: processed-by=WebCIL, sdk=.NET
  • NativeAOT objects: processed-by=ILCompiler, sdk=.NET

NativeAOT producer metadata is emitted after the required linking section and is excluded from
linking symbols and relocation bookkeeping.

Regular Webcil emits:

  • processed-by=WebCIL
  • sdk=.NET

Webcil deliberately omits language: a managed assembly may originate from C#, F#, Visual Basic,
generated IL, or multiple languages. Native compiler inputs continue to contribute their own
language metadata.

Validation

  • Browser/CoreCLR Debug clr+libs+host build: passed with 0 warnings and 0 errors.
  • Browser/Mono Debug mono+libs build: passed with 0 warnings and 0 errors.
  • WebAssembly Pack and Runtime WebAssembly SDK builds for CoreCLR and Mono: passed.
  • CoreCLR missing-producer-source initialization probe: passed.
  • Mono missing-producer-source workload regression: failed against the old target as expected,
    then passed with the fix (1 passed, 0 failed, 0 skipped).
  • Mono producer enabled/disabled workload theory: 2 passed, 0 failed, 0 skipped.
  • CoreCLR no-workload metadata suite: 4 passed.
  • Mono no-workload metadata suite: 4 passed.
  • Mono workload native metadata suite: 4 passed, including WasmRunWasmOpt=true.
  • Direct CoreCLR browserhost build with WasmRunWasmOpt=true: passed.
  • WASI Checked NativeAOT product build and exact CI test-tree build: passed.
  • NativeAOT ILCompiler.Compiler and R2R ILCompiler.ReadyToRun builds: passed.
  • CI wasi-wasm linux Checked NativeAOT: passed.
  • CI dotnet-linker-tests: passed.
  • Changed MSBuild XML parsing and git diff --check: passed.

Design notes: docs/design/mono/wasm-custom-sections.md.

Resolves #96334
Resolves #91049

Note

This PR description was updated with the assistance of GitHub Copilot.

Copilot AI requested review from Copilot and removed request for Copilot July 15, 2026 10:43
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 4 pipeline(s).
11 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 review requested due to automatic review settings July 15, 2026 20:35
@pavelsavara
pavelsavara temporarily deployed to copilot-pat-pool July 15, 2026 20:35 — with GitHub Actions Inactive
@pavelsavara
pavelsavara temporarily deployed to copilot-pat-pool July 15, 2026 20:36 — with GitHub Actions Inactive

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 prototypes emitting WebAssembly tool-conventions custom sections (producers, build_id) and surfacing a buildId value through the browser-wasm JavaScript API, wiring it through the Mono/CoreCLR relink pipelines and stamping WebCIL/R2R wasm outputs.

Changes:

  • Add a reusable managed WasmCustomSectionWriter and an MSBuild task to generate a linkable wasm object contributing .NET entries to the producers section during relink.
  • Plumb WasmNativeBuildId through build targets/tasks and expose runtimeBuildInfo.buildId in the JS public API surface.
  • Add WBT coverage for relink/webcil metadata sections and a design doc describing the approach.

Reviewed changes

Copilot reviewed 38 out of 42 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/tasks/WasmAppBuilder/WebcilConverter.cs Exposes build-id/version passthrough to Webcil converter.
src/tasks/WasmAppBuilder/WasmEmitProducersObject.cs New task writing producers wasm object for linker merge.
src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilWasmWrapper.cs Appends producers/build_id to wrapped WebCIL wasm.
src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs Wires metadata options into wrapper output.
src/tasks/Microsoft.NET.WebAssembly.Webcil/Microsoft.NET.WebAssembly.Webcil.csproj Links shared custom-section writer into task assembly.
src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ConvertDllsToWebCil.cs Passes build-id/product version into WebCIL conversion.
src/native/rollup.config.defines.js Adds buildId rollup constant from env.
src/native/libs/System.Native.Browser/native/index.ts Overrides runtimeBuildInfo.buildId from relinked native module.
src/native/libs/System.Native.Browser/libSystem.Native.Browser.footer.js Exposes WASM_BUILD_ID via $DOTNET during emcc link.
src/native/libs/Common/JavaScript/types/public-api.ts Extends public RuntimeAPI typing with buildId.
src/native/libs/Common/JavaScript/types/ems-ambient.ts Adds buildId to emscripten ambient DOTNET shape.
src/native/libs/Common/JavaScript/loader/index.ts Seeds runtimeBuildInfo.buildId from rollup constant.
src/native/libs/Common/JavaScript/loader/dotnet.d.ts Updates generated public typings for buildId.
src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/WasmMetadataSectionsTests.cs New tests validating producers/build_id emission.
src/mono/wasm/build/WasmApp.Common.targets Forces native relink when WasmNativeBuildId is set.
src/mono/sample/wasm/Directory.Build.targets Propagates WasmNativeBuildId through nested builds.
src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj Sample configuration updates (currently problematic).
src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in Treats WasmNativeBuildId as relink-triggering.
src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets Passes build-id/version into ConvertDllsToWebCIL task.
src/mono/browser/runtime/types/internal.ts Adds buildId to emscriptenBuildOptions typing.
src/mono/browser/runtime/types/index.ts Extends runtime API typing with buildId.
src/mono/browser/runtime/rollup.config.js Adds buildId constant in mono runtime rollup config.
src/mono/browser/runtime/loader/globals.ts Formatting-only changes.
src/mono/browser/runtime/loader/assets.ts Formatting-only changes.
src/mono/browser/runtime/globals.ts Copies buildId from relinked module into runtimeBuildInfo.
src/mono/browser/runtime/exports.ts Seeds runtimeBuildInfo.buildId from rollup constant.
src/mono/browser/runtime/es6/dotnet.es6.lib.js Plumbs WASM_BUILD_ID into emcc-evaluated options blob.
src/mono/browser/runtime/dotnet.d.ts Updates generated public typings for buildId.
src/mono/browser/build/BrowserWasmApp.targets Mono relink: emits producers object + build-id linker/env wiring.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targets CoreCLR relink: emits producers object + build-id linker/env wiring.
src/mono/browser/browser.proj Treats WasmNativeBuildId as runtime-pack defaultable property.
src/coreclr/tools/Common/Wasm/WasmCustomSectionWriter.cs New encoder/merger for producers/build_id custom sections.
src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Stamps producers/build_id into R2R webcil wasm output.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj Links shared custom-section writer into ILC tool.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs Plumbs wasm build-id option through compilation pipeline.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs Carries wasm build-id into object emission.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs Passes wasm build-id through to WasmObjectWriter.
src/coreclr/tools/aot/crossgen2/Properties/Resources.resx Adds help text for new crossgen2 option.
src/coreclr/tools/aot/crossgen2/Program.cs Wires new option into ReadyToRun builder.
src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs Adds --wasm-native-build-id option.
src/coreclr/hosts/corerun/wasm/libCorerun.extpost.js Adds buildId field to corerun runtimeBuildInfo.
docs/design/mono/wasm-custom-sections.md Design doc describing custom section strategy and properties.

@pavelsavara pavelsavara changed the title [wasm] Emit producers and build_id custom sections (prototype) [wasm] Emit producers and build_id custom sections (native, webcil, R2R) Jul 15, 2026
Resolve Browser WASM custom-section conflicts with the current WebCIL writer and app-relink infrastructure.

Co-authored-by: Copilot <[email protected]>
pavelsavara and others added 3 commits October 23, 2026 16:50
Resolve ReadyToRun WebCIL conflicts while preserving build IDs, debug information, and symbol maps.

Co-authored-by: Copilot <[email protected]>
Enable Emscripten's producers-section setting for Mono and CoreCLR links so the metadata merged by wasm-ld survives post-link processing. Cover both enabled and disabled emission.

Co-authored-by: Copilot <[email protected]>
Use endian-safe WASM parsing, escape generated build IDs, fail invalid Webcil IDs early, retain task exception details, and restore the Browser runtime's linted formatting.

Co-authored-by: Copilot <[email protected]>
pavelsavara and others added 2 commits November 6, 2026 12:24
Apply metadata behavior to .NET 12 and later, and keep repository-only
producer object generation out of shipped workload targets. Reuse the
build-stamped runtime module for non-relinked publish output.

Co-authored-by: Copilot <[email protected]>
Ship flavor-specific assembly source in browser runtime packs and let
Emscripten assemble it during native relinking. Remove the managed
relocatable WebAssembly object writer.

Co-authored-by: Copilot <[email protected]>
Remove unused producer parsing and merge paths, centralize build ID
validation, and preserve raw input until prefix-aware parsing. Add
coverage for valid normalization and malformed IDs.

Co-authored-by: Copilot <[email protected]>
Remove the incorrect C# producer claim from regular and R2R Webcil
modules, and simplify custom-section emission to direct producer and
build-ID APIs.

Co-authored-by: Copilot <[email protected]>
pavelsavara and others added 4 commits November 10, 2026 13:24
Stamp the user-provided ID after final Webcil staging so regular and R2R
modules share the build-wide value without crossgen-specific plumbing.
Keep content hashes as the unset fallback, remove duplicate runtime
transport, and preserve incremental R2R outputs.

Co-authored-by: Copilot <[email protected]>
…sm-custom-sections

# Conflicts:
#	src/native/libs/Common/JavaScript/loader/run.ts
Make each emitted Wasm file own its build ID instead of applying one
user-supplied ID across a deployment. Native links use wasm-ld IDs and
regenerate them after wasm-opt, while regular and R2R Webcil retain their
writer-generated content hashes.

Co-authored-by: Copilot <[email protected]>
@pavelsavara
pavelsavara marked this pull request as draft November 10, 2026 18:32
pavelsavara and others added 4 commits November 11, 2026 17:49
Preserve wasm-ld build IDs through Binaryen so transformed modules and
their source maps retain the same identity. Emit producers and Webcil
build IDs through the existing Wasm writer implementations instead of
maintaining a separate section parser and post-optimization stamping task.

Co-authored-by: Copilot <[email protected]>
Emit producers as plain metadata after the mandatory linking section in
relocatable NativeAOT objects. Keep it out of linking symbols and relocation
bookkeeping so wasm-ld accepts the object while R2R Webcil continues to use
the shared producer payload writer.

Co-authored-by: Copilot <[email protected]>
@pavelsavara

Copy link
Copy Markdown
Member

Thanks for the detailed review. I reworked the implementation around the ownership model you
suggested:

  • Removed the public build-wide ID configuration and application-time restamping. Runtime-pack
    modules keep their IDs, and each newly generated Wasm file receives an ID from its producer.
  • Removed post-wasm-opt build-ID regeneration. The wasm-ld ID is preserved through
    Emscripten/Binaryen and continues to match Binaryen's source-map debugId.
  • Deleted WasmCustomSectionWriter, ProducerValue, and WasmRegenerateBuildId.
  • Regular Webcil emits its producers and payload-hash build_id directly from
    WebcilWasmWrapper.
  • Moved compiler producer encoding into WasmObjectWriter, shared by R2R Webcil and NativeAOT
    Wasm objects.
  • Kept build_id in WebCilObjectWriter only. NativeAOT relocatable objects have no build ID;
    the final linker owns it.
  • NativeAOT emits producers as plain metadata after the required linking section and excludes
    it from linking symbols and relocations.
  • Webcil producer metadata is language-neutral: processed-by=WebCIL and sdk=.NET.

Validation includes Browser Mono/CoreCLR builds, regular and R2R Webcil metadata tests, explicit
wasm-opt coverage, the exact WASI NativeAOT CI product/test commands, and the repaired
wasi-wasm linux Checked NativeAOT CI job. The linker pipeline also passes.

Note

This response was prepared with the assistance of GitHub Copilot.

pavelsavara and others added 2 commits November 13, 2026 15:06
Document the final per-artifact ownership model for producers and build
IDs, including native linker behavior, managed writer responsibilities,
and the NativeAOT relocatable section-order invariant.

Co-authored-by: Copilot <[email protected]>
Treat dotnet-producers.s as an optional runtime-pack contribution so a
newer WebAssembly SDK can relink against a pack that predates the source.

Co-authored-by: Copilot <[email protected]>
@pavelsavara
pavelsavara marked this pull request as ready for review November 13, 2026 18:07

This branch was previously deployed

1 inactive (outdated) deployment
copilot-pat-pool — 457c3749 Deployed Jul 15, 2026 by pavelsavara via pat_pool #15245
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-Build-mono os-browser Browser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Emit Producers section when compiling to wasm Blazor - WebAssembly build_id section

5 participants