Skip to content

[browser][coreCLR] Loading WebCIL 0.1#124268

Open
pavelsavara wants to merge 4 commits intodotnet:mainfrom
pavelsavara:loading_webcil1
Open

[browser][coreCLR] Loading WebCIL 0.1#124268
pavelsavara wants to merge 4 commits intodotnet:mainfrom
pavelsavara:loading_webcil1

Conversation

@pavelsavara
Copy link
Member

@pavelsavara pavelsavara commented Feb 11, 2026

Enable WebCIL support for CoreCLR on Browser/WASM

Fixes #120248

WebCIL format v0.1 with 16-byte section alignment

Bumps WebCIL version from 0.0 to 0.1. The WebcilConverter now emits section data at 16-byte-aligned offsets, ensuring RVA static fields backing ReadOnlySpan<T> over types up to Vector128<T> retain their natural alignment.

CoreCLR PEDecoder: native WebCIL parsing

New src/coreclr/inc/webcil.h defines WebcilHeader and WebcilSectionHeader C structs with static_assert size checks. PEDecoder gains:

  • FLAG_WEBCIL flag; HasWebcilHeaders() validates magic, version, section count/bounds/ordering and synthesizes IMAGE_SECTION_HEADER[] from WebCIL sections so RvaToSection()/RvaToOffset() work uniformly.
  • HasHeaders() / CheckHeaders() as unified entry points that dispatch to WebCIL or NT paths.
  • WebCIL-aware HasDirectoryEntry(), GetDirectoryEntryData() (handles COMHEADER and DEBUG entries via WebcilHeader fields with explicit range validation against section data).
  • CheckCorHeader() and CheckILOnly() WebCIL branches (WebCIL images are always IL-only by definition).
  • GetPEKindAndMachine() reports peILonly / IMAGE_FILE_MACHINE_I386 for WebCIL.
  • GetNumberOfRvaAndSizes() moved from public to private API; GetNumberOfSections() / FindFirstSection() delegate to synthesized headers for WebCIL.
  • Preconditions across the file generalized from CheckNTHeaders() to CheckHeaders() / HasHeaders().

PEImage / PEAssembly integration

PEImage exposes HasHeaders() forwarding to PEDecoder::HasHeaders(). PEAssembly uses HasHeaders() instead of HasNTHeaders() for metadata access.

Browser host loader: WebCIL module instantiation

  • New instantiateWebCILModule() in host assets:
    • instantiates the .wasm wrapper as a WebAssembly module
    • calls getWebcilSize/getWebcilPayload exports to extract the raw WebCIL
    • copies the payload into 16-byte aligned memory, registers it under the .dll virtual path.
  • New getWasmMemory / getWasmTable
  • Enabling WebCIL by default for CoreCLR-on-WASM via WasmEnableWebcil.

DAC support gap

All WebCIL code paths in PEDecoder are gated behind #ifdef TARGET_BROWSER, which is mutually exclusive with DACCESS_COMPILE.
Should we drop #ifdef TARGET_BROWSER ? Or build target specific DAC binaries ?
Follow up in #124467

(func $getWebcilPayload (;1;) (export "getWebcilPayload") (param $d (;0;) i32) (param $n (;1;) i32)
    local.get $d
    i32.const 0
    local.get $n
    memory.init 1
)

@pavelsavara pavelsavara added this to the 11.0.0 milestone Feb 11, 2026
@pavelsavara pavelsavara self-assigned this Feb 11, 2026
@pavelsavara pavelsavara added the arch-wasm WebAssembly architecture label Feb 11, 2026
Copilot AI review requested due to automatic review settings February 11, 2026 12:37
@pavelsavara pavelsavara added area-Host os-browser Browser variant of arch-wasm labels Feb 11, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @agocke, @jeffschwMSFT, @elinor-fung
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

Copilot AI left a comment

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 adds support for loading WebCIL version 1.0 assemblies in CoreCLR on browser/WASM targets. WebCIL is an alternative container format for ECMA-335 assemblies that strips PE headers and packages assemblies as WebAssembly modules with a .wasm extension, helping avoid issues with firewalls/antivirus software that block .dll files.

Changes:

  • Added WebCILImageLayout C++ class that extends PEImageLayout to handle WebCIL format, parsing WebCIL headers and mapping RVAs to file offsets
  • Implemented instantiateWebCILModule in TypeScript that instantiates WebCIL .wasm modules and extracts assembly payloads into aligned memory
  • Enabled WebCIL support for CoreCLR by removing WasmEnableWebcil=false restrictions and updating test configurations

Reviewed changes

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

Show a summary per file
File Description
src/native/libs/Common/JavaScript/types/public-api.ts Added "webcil1" asset behavior type
src/native/libs/Common/JavaScript/types/exchange.ts Added instantiateWebCILModule to BrowserHost exports
src/native/libs/Common/JavaScript/cross-module/index.ts Updated export table to include instantiateWebCILModule
src/native/corehost/browserhost/loader/dotnet.d.ts Added "webcil1" type definition
src/native/corehost/browserhost/loader/assets.ts Added WebCIL detection and loading logic, mapping .wasm to .dll paths
src/native/corehost/browserhost/host/index.ts Exported instantiateWebCILModule function
src/native/corehost/browserhost/host/host.ts Updated assembly path mapping to replace .wasm with .dll
src/native/corehost/browserhost/host/assets.ts Implemented instantiateWebCILModule to extract WebCIL payload and register assemblies
src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs Removed CoreCLR restriction for WebCIL in tests
src/mono/browser/build/WasmApp.InTree.props Removed WasmEnableWebcil=false for CoreCLR, updated TODO comment
src/coreclr/vm/webcildecoder.cpp New file implementing WebCILImageLayout class for parsing and validating WebCIL format
src/coreclr/vm/peimagelayout.h Added WebCIL header structures and WebCILImageLayout class declaration
src/coreclr/vm/peimagelayout.cpp Added WebCIL format detection in LoadFlat
src/coreclr/vm/peassembly.cpp Excluded 32-bit NT headers check for TARGET_BROWSER, added braces for consistency
src/coreclr/vm/coreassemblyspec.cpp Added braces around single-statement if bodies
src/coreclr/vm/CMakeLists.txt Added webcildecoder.cpp to browser build
src/coreclr/inc/pedecoder.h Made specific PEDecoder methods virtual for browser target to enable WebCILImageLayout overrides
eng/testing/tests.browser.targets Removed WasmEnableWebcil=false for CoreCLR, updated TODO comment

@davidwrighton
Copy link
Member

Please have @elinor-fung look at this

Copilot AI review requested due to automatic review settings February 11, 2026 20:39
Copy link
Contributor

Copilot AI left a comment

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

Copilot AI review requested due to automatic review settings February 11, 2026 21:06
Copy link
Contributor

Copilot AI left a comment

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 18 out of 19 changed files in this pull request and generated 4 comments.

Copy link
Contributor

Copilot AI left a comment

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 23 out of 24 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings February 12, 2026 21:57
Copy link
Contributor

Copilot AI left a comment

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

@pavelsavara pavelsavara removed the NO-REVIEW Experimental/testing PR, do NOT review it label Feb 16, 2026
@pavelsavara
Copy link
Member Author

The solution in this PR now works and the change looks better than the previous attempt with inheritance from PEDecoder.
@jkotas @adamperlin now it makes sense to provide feedback, thank you.

The open question is DAC support, which I don't fully understand yet.
I prefer that we merge this PR without solving it, to unblock R2R work.
I created #124467 for DAC+WebCIL follow up work.

cc @AaronRobinsonMSFT @steveisok

@steveisok
Copy link
Member

steveisok commented Feb 16, 2026

cc @AaronRobinsonMSFT @steveisok

/cc @dotnet/dotnet-diag

// in HasWebcilHeaders(), so RvaToSection()/RvaToOffset() work uniformly.
static constexpr uint16_t WEBCIL_MAX_SECTIONS = 8;
uint16_t m_webcilSectionCount = 0;
IMAGE_SECTION_HEADER m_webcilSectionHeaders[WEBCIL_MAX_SECTIONS];
Copy link
Member

Choose a reason for hiding this comment

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

This is 320 bytes. It is not prohibitive, but it is not free either.

Would it be possible to say that the WebCIL has exactly one section to make things simpler? (Shrink all sections into one during the conversion to WebCIL.)

mutableThis->m_webcilSectionCount = nSections;
for (uint16_t i = 0; i < nSections; i++)
{
memset(&mutableThis->m_webcilSectionHeaders[i], 0, sizeof(IMAGE_SECTION_HEADER));
Copy link
Member

Choose a reason for hiding this comment

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

Instead of initializing each section one at a time, we should just do the lot of them prior to the loop.

I think the WASM world is single threaded right now so there is no race, but this has an inherent race condition with the initialization happening and the flag being set below. Basically, the first thread comes through and sets the flag and another comes in and reinitializes all of the sections while the first thread has already returned. I don't think we need to change anything here, just an observation.

previousOffsetEnd = (UINT32)endInFile.Value();
}

PEDecoder* mutableThis = const_cast<PEDecoder *>(this);
Copy link
Member

Choose a reason for hiding this comment

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

Remove the const from the function. const_cast is rarely needed.

<NestedBuildProperty Include="WasmTestForwardConsole" />
</ItemGroup>

<Target Name="CleanSampleBinObj" BeforeTargets="BuildSampleInTree">
Copy link
Member

Choose a reason for hiding this comment

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

We should be using the MSBuild Clean item group instead of creating one off clean targets.

Copy link
Member Author

Choose a reason for hiding this comment

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

@maraf would it work here ?

if (HasWebcilHeaders())
{
// WebCIL images are always IL-only by definition.
const_cast<PEDecoder *>(this)->m_flags |= FLAG_IL_ONLY_CHECKED;
Copy link
Member

Choose a reason for hiding this comment

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

Change the const if this is needed please.

RETURN (TADDR)NULL;
}

// RvaToSection guarantees rva >= sectionBase, so the subtraction
Copy link
Member

Choose a reason for hiding this comment

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

An assert here is appropriate.

@pavelsavara pavelsavara changed the title [browser][coreCLR] Loading WebCIL 1.1 [browser][coreCLR] Loading WebCIL 0.1 Feb 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] support loading WebCIL

7 participants