Skip to content

[RyuJIT Wasm] WasmObjectWriter Webcil Envelope Support#125468

Open
adamperlin wants to merge 33 commits intodotnet:mainfrom
adamperlin:adamperlin/wasm-object-writer-webcil
Open

[RyuJIT Wasm] WasmObjectWriter Webcil Envelope Support#125468
adamperlin wants to merge 33 commits intodotnet:mainfrom
adamperlin:adamperlin/wasm-object-writer-webcil

Conversation

@adamperlin
Copy link
Contributor

@adamperlin adamperlin commented Mar 12, 2026

This PR implements WebCIL envelope support for the WasmObjectWriter. It builds up the data segment and assigns RVAs/Raw data addresses to each Webcil section as a first pass. As a second pass, it emits the proper headers and sections, and and also implements relocation resolution for IMAGE_BASE* type relocs that may appear in Webcil data sections using the pre-assigned section addresses.

The WebcilDataSegment is emitted as two Wasm data segments according to the Webcil spec like so:

  (data "\0f\00\00\00") ;; data segment 0: payload size as a 4 byte LE uint32, 
                        ;; may have extra padding so that the next segment is properly aligned
  (data "payload\cc")  ;; data segment 1: webcil payload (start is 4 byte aligned)
      | webcil header
      __________________________
      | section header (1)
      | ...
      | section header (n)
      ___________________________
      | section 1 (align 16-byte)
      ___________________________
      | ...
      ___________________________
      | section n (align 16-byte)
      ___________________________

The PR also adds a simple validator program which uses Microsoft.NET.Webcil.Validator. I am fine if we don't want to include this or want this refactored, I just included it in case it would be useful to have as I used it for testing purposes.

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

Adds initial WebCIL “envelope” emission support to the CoreCLR AOT Wasm object writer so the runtime can locate PE/CLI header data and debug directory data inside a WebAssembly binary.

Changes:

  • Introduces WebcilHeader / WebcilSectionHeader encoders and wires Webcil.cs into ILCompiler projects.
  • Extends WasmObjectWriter to build a flat WebCIL segment, resolve PE-style relocations into it, and emit it as passive Wasm data segments (with DataCount + exported helpers/globals).
  • Adjusts dependency tracking so Wasm methods get explicit signature nodes, and updates some Wasm-specific section placement logic.

Reviewed changes

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

Show a summary per file
File Description
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj Adds Webcil.cs to the ReadyToRun tool build.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs Adds a Wasm32-only dependency on WasmTypeNode for explicit signatures.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj Adds Webcil.cs to the compiler tool build.
src/coreclr/tools/Common/Compiler/ObjectWriter/Webcil.cs New: encodes WebCIL header + section headers.
src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Major: builds/emits WebCIL payload as Wasm data segments; adds DataCount/Global handling and relocation resolution changes.
src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs Adds WasmGlobal encoding support.
src/coreclr/tools/Common/Compiler/ObjectWriter/WasmInstructions.cs Adds instruction helpers needed for emitted Wasm stubs (locals + memory.init).
src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs Adds Wasm-related adjustments and several debug Console.WriteLine statements during emission/relocation.
src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypes.cs Formatting tweak in WasmValueType.
src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs Exposes WASM_PADDED_RELOC_SIZE_32 publicly for reuse.
src/coreclr/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs Places AssemblyStubNode into read-only data for Wasm targets.

You can also share your feedback on Copilot code review. Take the survey.

Copilot AI review requested due to automatic review settings March 13, 2026 18:46
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 13 out of 14 changed files in this pull request and generated 5 comments.


You can also share your feedback on Copilot code review. Take the survey.

Copilot AI review requested due to automatic review settings March 13, 2026 19:34
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 13 out of 14 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs:389

  • This change makes all ISymbolRangeNode handling unconditional (previously gated by LayoutMode == CodeDataLayout.Unified). If the original condition was important for non-Wasm backends or for separate-layout scenarios, this risks changing behavior beyond Wasm. Consider restricting this to the Wasm path (or otherwise documenting why it is now correct for all targets/layout modes).
                // TODO-WASM: emit symbol ranges properly when code and data are separated
                // Right now we still need to determine placements for some traditionally text-placed nodes,
                // such as DebugDirectoryEntryNode and AssemblyStubNode
                if (depNode is ISymbolRangeNode symbolRange)
                {
                    symbolRangeNodes.Add(symbolRange);
                    continue;
                }

You can also share your feedback on Copilot code review. Take the survey.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…m/Webcil.cs and unify type definition with WasmObjectWriter
Copilot AI review requested due to automatic review settings March 17, 2026 18:54
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 18 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs:456

  • AssemblyStubNode is no longer skipped for Wasm during object emission, but the Wasm implementations of several AssemblyStubNode derivatives still throw NotImplementedException (e.g. Target_Wasm/WasmReadyToRunHelperNode.cs). If any of these nodes are present (they’re created by NodeFactory.CreateReadyToRunHelperNode), this change will cause the Wasm/R2R build to fail at emit time. Consider restoring the Wasm AssemblyStubNode skip until the Wasm stub emitters are implemented, or implement the required Wasm emitters before allowing these nodes to be emitted.
                if (node is INodeWithTypeSignature codeNode && _nodeFactory.Target.IsWasm)
                {
                    Debug.Assert(codeNode.Signature != null, $"Wasm code node {codeNode.GetType()} has null signature");

                    // TODO: eventually this should check IMethodCodeNodeWithTypeSignature
                    // Once we have signatures implemented for all code-carrying nodes
                    if (node is IMethodBodyNode methodNode)
                    {
                        // Record only information we can get from the MethodDesc here. The actual
                        // body will be emitted by the call to EmitData() at the end
                        // of this loop iteration.
                        RecordMethodDeclaration(codeNode, methodNode.Method);
                    }
                }

You can also share your feedback on Copilot code review. Take the survey.

Copilot AI review requested due to automatic review settings March 17, 2026 19:56
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 18 changed files in this pull request and generated 4 comments.


You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +783 to +790
Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset - (virtualRelocOffset + relocLength) + addend);
break;
case RelocType.IMAGE_REL_FILE_ABSOLUTE:
// Debug.Assert(betweenWebcilSections && symbolWebcilSection != null);
Debug.Assert(symbolWebcilSection != null);
long fileOffset = symbolWebcilSection.Header.PointerToRawData + definedSymbol.Value;
Relocation.WriteValue(reloc.Type, pData, fileOffset + addend);
break;
// TODO-WASM: Consider alignment needs for data sections
public static readonly ObjectNodeSection DataSection = new ObjectNodeSection("wasm.data", SectionType.Writeable, needsAlign: false);
public static readonly ObjectNodeSection DataCountSection = new ObjectNodeSection("wasm.datacount", SectionType.ReadOnly, needsAlign: false);
public static readonly ObjectNodeSection CombinedDataSection = new ObjectNodeSection("wasm.alldata", SectionType.Writeable, needsAlign: false);
adamperlin and others added 2 commits March 17, 2026 15:25
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 17, 2026 22:27
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 16 out of 16 changed files in this pull request and generated 2 comments.


You can also share your feedback on Copilot code review. Take the survey.

Comment on lines 233 to 245
protected internal override void UpdateSectionAlignment(int sectionIndex, int alignment)
{
// This is a no-op for now under Wasm
WebcilSection section = _sections[sectionIndex] as WebcilSection;
// We should only be updating the alignment of Webcil sections; Wasm-native sections should
// not have alignment constraints.
Debug.Assert(section != null, $"Section: {sectionIndex} is not a WebcilSection");
if (section == null)
{
return;
}

section.MinAlignment = Math.Max(section.MinAlignment, alignment);
}
@@ -468,19 +842,22 @@ private void WriteImports()
if (import.Index.HasValue)
{
int assigned = assignedImportIndices[(int)import.Kind];
Copy link
Member

@pavelsavara pavelsavara left a comment

Choose a reason for hiding this comment

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

LGTM.

I wonder if we can add smoke test.
Produce trivial IL-only webcil with the object writer and test it with coreCLR loader.
Even manual/unmerged test doing this would be nice.

@adamperlin
Copy link
Contributor Author

LGTM.

I wonder if we can add smoke test. Produce trivial IL-only webcil with the object writer and test it with coreCLR loader. Even manual/unmerged test doing this would be nice.

I have validated that the basic structure is correct for a simple example using the existing Microsoft.NET.WebAssembly.WebcilReader (and a simple driver program that calls the reader), but I'd definitely like to have a smoke test! What would it take to use the CoreCLR loader at the moment?

Copy link
Member

@davidwrighton davidwrighton left a comment

Choose a reason for hiding this comment

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

LGTM modulo comments.

foreach (var symbolicRelocation in relocationList)
{
if (!_definedSymbols.ContainsKey(symbolicRelocation.SymbolName))
foreach (var symbolicRelocation in relocationList)
Copy link
Member

Choose a reason for hiding this comment

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

Add another set of curly braces here for clarity.


uint rawSectionSize = (uint)webcilSection.Stream.Length;
uint alignedSectionSize = (uint)AlignmentHelper.AlignUp((int)rawSectionSize, (int)WebcilSectionAlignment);
uint virtualSize = alignedSectionSize;
Copy link
Member

Choose a reason for hiding this comment

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

Needs a comment that virtualSize needs to be the same as alignedSectionSize so that RVA's can be constant, and that loading the Webcil image doesn't require interesting layout in memory.

@pavelsavara
Copy link
Member

What would it take to use the CoreCLR loader at the moment?

Just produce valid WebCIL 1 IL-only assembly (no R2R). I think you are close to it, right ?

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.

6 participants