From 20a74b37706d2e0df470c65f1f63e24710734760 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 18 Nov 2025 14:51:40 -0800 Subject: [PATCH 01/23] Begin Stubbing out Wasm Object Writer --- .../Compiler/ObjectWriter/WasmNative.cs | 6 + .../Compiler/ObjectWriter/WasmObjectWriter.cs | 33 + .../tools/Common/JitInterface/CorInfoImpl.cs | 40 +- .../ILCompiler.ReadyToRun/ClassDiagram1.cd | 603 ++++++++++++++++++ .../ILCompiler.ReadyToRun.csproj | 6 + 5 files changed, 686 insertions(+), 2 deletions(-) create mode 100644 src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs create mode 100644 src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.ReadyToRun/ClassDiagram1.cd diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs new file mode 100644 index 00000000000000..c2df6a398e57e3 --- /dev/null +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -0,0 +1,6 @@ +using System.Runtime.CompilerServices; + +namespace ILCompiler.ObjectWriter +{ + // TODO: fill in with Wasm specific section information +} diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs new file mode 100644 index 00000000000000..b657990df29233 --- /dev/null +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using ILCompiler.DependencyAnalysis; + +namespace ILCompiler.ObjectWriter +{ + /// + /// Wasm object file format writer. + /// + internal sealed class WasmObjectWriter : ObjectWriter + { + private const uint InvalidIndex = uint.MaxValue; + private const uint InvalidOffset = uint.MaxValue; + + public WasmObjectWriter(NodeFactory factory, ObjectWritingOptions options, OutputInfoBuilder outputInfoBuilder) + : base(factory, options, outputInfoBuilder) + { + } + + protected internal override void UpdateSectionAlignment(int sectionIndex, int alignment) => throw new NotImplementedException(); + private protected override void CreateSection(ObjectNodeSection section, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) + { + } + + private protected override void EmitObjectFile(Stream outputFileStream) => throw new NotImplementedException(); + private protected override void EmitRelocations(int sectionIndex, List relocationList) => throw new NotImplementedException(); + private protected override void EmitSymbolTable(IDictionary definedSymbols, SortedSet undefinedSymbols) => throw new NotImplementedException(); + + } + +} diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 3bc5a00ce08d49..9eb85bce151e27 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -328,6 +328,34 @@ IntPtr LocalObjectToHandle(object input) return null; } + + private CorJitResult CompileWasmStub(out IntPtr exception, ref CORINFO_METHOD_INFO methodInfo, out uint codeSize) + { + byte[] stub = new byte[] { + 0x41, // i32.const + 0x0, // uleb128 0 + 0x0f, // return + }; + AllocMemArgs args = new AllocMemArgs + { + hotCodeSize = (uint)stub.Length, + coldCodeSize = (uint)0, + roDataSize = (uint)0, + xcptnsCount = _ehClauses != null ? (uint)_ehClauses.Length : 0, + flag = CorJitAllocMemFlag.CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN, + }; + allocMem(ref args); + + _code = stub; + + codeSize = (uint)stub.Length; + exception = IntPtr.Zero; + + _codeRelocs = new(); + + return CorJitResult.CORJIT_OK; + } + private CompilationResult CompileMethodInternal(IMethodNode methodCodeNodeNeedingCode, MethodIL methodIL) { // methodIL must not be null @@ -350,9 +378,17 @@ private CompilationResult CompileMethodInternal(IMethodNode methodCodeNodeNeedin IntPtr exception; IntPtr nativeEntry; uint codeSize; - var result = JitCompileMethod(out exception, + + TargetArchitecture architecture = _compilation.TypeSystemContext.Target.Architecture; + + var result = architecture switch { + // We currently do not have WASM codegen support, but for testing, we will return a stub + TargetArchitecture.Wasm32 => CompileWasmStub(out exception, ref methodInfo, out codeSize), + _ => JitCompileMethod(out exception, _jit, (IntPtr)(&_this), _unmanagedCallbacks, - ref methodInfo, (uint)CorJitFlag.CORJIT_FLAG_CALL_GETJITFLAGS, out nativeEntry, out codeSize); + ref methodInfo, (uint)CorJitFlag.CORJIT_FLAG_CALL_GETJITFLAGS, out nativeEntry, out codeSize) + }; + if (exception != IntPtr.Zero) { if (_lastException != null) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ClassDiagram1.cd b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ClassDiagram1.cd new file mode 100644 index 00000000000000..69e8947568b8e1 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ClassDiagram1.cd @@ -0,0 +1,603 @@ + + + + + + AAIQEACAGACAAAAAAAAAAAAAABQAAAAAAAAAAAAAnAA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs + + + + + + + AAAQAAIAEAGAAAAAAAAAA0QEAAAAAAAAAAAAAAEAAEA= + tools\Common\Compiler\DependencyAnalysis\ObjectNode.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAEQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs + + + + + + AAAAAAAAAAAAAAAAAAAgAAAAAAQAAAEAAAAAAAAAEQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs + + + + + + AQAAEAAACAAAAAEAAAAABgAAAAAAAAEAAgAAACAABQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodGCInfoNode.cs + + + + + + AAQQAAIAAEEAAAEAIACgAAQEAAAAAAIAAAAAAAEAAEA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\EmbeddedObjectNode.cs + + + + + + AAAAAAAAgAAAAAAAAAAAAAAAAAAAAAEAIAAAAAAABQA= + tools\Common\Compiler\DependencyAnalysis\SortableDependencyNode.cs + + + + + + + AAAAEAAACAAAAAEAAAggQiQAAAAAAAGAAgAAACAABQE= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\Import.cs + + + + + + + + + + + + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ImportSectionNode.cs + + + + + AAAEMQiCAAAKAAUAAAgAAgQAAAIAQQEAAAAAAAQAFQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ImportSectionNode.cs + + + + + + AAAAEAAACAAAAAEAAAAAAiAAAAAAAACAAACAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\EmbeddedPointerIndirectionNode.cs + + + + + + + AAAAAAAACAAAAAEAAAAAAgAAAAAAAAEAAAAAAAAABQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\SignatureEmbeddedPointerIndirectionNode.cs + + + + + + AAAAAAAACAAAAAEAAAAAAgAgAACAAAEAAAAgACAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DelayLoadHelperImport.cs + + + + + + AAAAAAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAAAAAABQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\PrecodeHelperImport.cs + + + + + + AAAAAAAAAAAACAEAAAAAAAQAAAAAAAEAAAAAAAAABQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\StringImport.cs + + + + + + QAAAAAAACACAAAAAAABgAgAAAAAAAAEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\PrecodeMethodImport.cs + + + + + + + AAAAAAAAAAAAAAAAAABgAgAAAAAAABEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DelayLoadHelperMethodImport.cs + + + + + + + QAAAAAAAAACAAAAAAAAgAgAAAAAAAAEAAAAAAgAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DelayLoadMethodImport.cs + + + + + + + AAAEAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAACAABQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ImportSectionsTableNode.cs + + + + + + + AAAQEIAIEACABAAEAAAAAUAAABAEAAAAAAAAACAADQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ArrayOfEmbeddedDataNode.cs + + + + + + AAAAAAAACAAAAAQAAAAAAAAAAAAAAAEAAAAAAAAAgQA= + tools\Common\Compiler\DependencyAnalysis\EmbeddedDataContainerNode.cs + + + + + + + AAAQEAAACACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\Signature.cs + + + + + + + AAAAAAAAGAAAAAAAACAAAEAEAAAAAAEAAAAgAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DelegateCtorSignature.cs + + + + + + AAAAAAAAGAAAAAAAAAAAQAAAAAAAAQEAAAAAQAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\FieldFixupSignature.cs + + + + + + CAAAAAAAWAAACAAAAAAAAEAAAAAAAQECAAAAAAAAAwA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\GenericLookupSignature.cs + + + + + + AACAAAAAGAAAAAAEgABAAAAAAAAAAQEAAgAAAAAIAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ILBodyFixupSignature.cs + + + + + + + AAAACAAAGAAAAIAAAABgAEAAAAAAAQFQAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodFixupSignature.cs + + + + + + AAAAACAAGAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\NewArrayFixupSignature.cs + + + + + + AAAAAAAAGAAAAAAAAAAAAAAABAAAAAEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\NewObjectFixupSignature.cs + + + + + + AAAAAAAAGAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ReadyToRunHelperSignature.cs + + + + + + AAAAIAAAGAAAACAAAAAAgAAAAAAAAAEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ReadyToRunInstructionSetSupportSignature.cs + + + + + + AAAAAAAAGAAACAAAAAAAAAAAAAAAAAEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\StringImportSignature.cs + + + + + + AAAAAAAAGAAAAAAAAAAAEEAARAAAAQEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\TypeFixupSignature.cs + + + + + + AAABAAAAGAAAAAAEgAAAIAAAABAAAQEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\VirtualResolutionFixupSignature.cs + + + + + + + IAAAAgEAGCIICAAQAoEIFAAAAAgAAAAABAAAAAiAAQg= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ManifestMetadataTableNode.cs + + + + + + AAAAAEAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodEntryPointTableNode.cs + + + + + + AAAQEAAACACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhAA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs + + + + + + + ABAAAEAACAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs + + + + + + + + + + + + + + ABAQEAAAGACAgAAAAAgAAAAAAAAAAAEAAQAAAAAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedCorHeaderNode.cs + + + + + + + AAAAAAAAGAAAAAAAEAAAAAAAAAAAAAEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs + + + + + + + + + + + + + + ABAQEABAGACAAAAAAAAAAAAAAAAAAAEAAAAAAAABhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedFieldRvaNode.cs + + + + + + + + + + + + + + + + + + + ABAQEAAAGACAgAAAAAAAAAAAAAAAAAEAAAAAAAAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedManagedResourcesNode.cs + + + + + + + + + + + + + + + AAAQEAAAGACAgAABAACAAAAAAAAAAAEAAEAAAAAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedMetadataBlobNode.cs + + + + + + + + + + + + + + + AAAQEAAAGACAAAAAAABAAAAAAAAAAAEAAAAAAAAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedMethodILNode.cs + + + + + + + ABAQEAAAGACAgAAAAAAAAAAAAAAAAAEAAAAAAAAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedStrongNameSignatureNode.cs + + + + + + + + + + + + + + + AAAACAAAGACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CompilerIdentifierNode.cs + + + + + + AAIAAAAAGAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\AssemblyTableNode.cs + + + + + + + + + + + + + + ABAQEAAACACAAAAAAAAAAAAAAAAAAAEAAAAAAAAAhAA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs + + + + + + + AAAAAAAQGAAAAAAAAAAAABAQAAAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugInfoTableNode.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs + + + + + + AAAQEAAAWASAAAAAAAAAAAQAAAAAAAAAAAAAAAAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ExceptionInfoLookupTableNode.cs + + + + + + + AQAAAEAAEAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\EnclosingTypeMapNode.cs + + + + + + AAAAAAAAGAAACAgAAIAAAUAQAAAAAAAAAAAAACAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ExceptionInfoLookupTableNode.cs + + + + + + AABQEAAAGACQAIAAAAAAAAAAAAAAAQEAAAAAAgAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\GCRefMapNode.cs + + + + + + + AAAAAAAAGAABAAAAAAAAAAAAAAAAAAAAAAAAgAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HotColdMapNode.cs + + + + + + AAAAAAAACAAAAAAABgBAAEAAAgAAAAGAAgAEAAAABQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\Target_ARM\ImportThunk.cs + + + + + + + AAAQGAAAGACAAAAAAABAAAAAAAAAAAAAAAAAAAAAgAA= + tools\Common\Compiler\DependencyAnalysis\AssemblyStubNode.cs + + + + + + + AAAAAEAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\TypesTableNode.cs + + + + + + AQAAAEAAEAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\TypeGenericInfoMapNode.cs + + + + + + AAAEABAIHACACBAQAAAAAAAAAAAAAAAAAAAAACAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\RuntimeFunctionsTableNode.cs + + + + + + AAAQEAAAAACAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\RuntimeFunctionsGCInfoNode.cs + + + + + + AAAAABAAmAAAgAAAAAAAAAGAAAAoCAEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs + + + + + + AAAEAAAAGACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\OwnerCompositeExecutableNode.cs + + + + + + + + + + + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs + + + + + + AAAAAAQAGAQAgAAABAAAAAAAICAgAAEAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs + + + + + + AQAAAEAAEAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodIsGenericMapNode.cs + + + + + + AAEQEAAAGACAAAAAAAAAAIAAAAAAAAEAAAAAgAAAhQg= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodColdCodeNode.cs + + + + + + + AAgQEAAAGACAgAAAAAAAAAAAAAAAAAAAAAAAAAAAhQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ManifestAssemblyMvidHeaderNode.cs + + + + + + + AAAAAAAAGAAAAYACAAAAAEAAAAAAAAAEAAACAAAAEQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\InstrumentationDataTableNode.cs + + + + + + AAAEAAAAGgAAAAAAAAAAAAAAAAIAAAAAAAASAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\InstanceEntryPointTableNode.cs + + + + + + + AAAAAFAAMAAAAYAAAAAAAAAAAAAAAAAAAQAAAAAAAQA= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\InliningInfoNode.cs + + + + + + IYBTUBKAGFCCgiEEgEBgAUgIgECEAYUIAgIAAAJAlQg= + tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodWithGCInfo.cs + + + + + \ No newline at end of file diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index f145cbeae61297..eeac2820cf277e 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -158,6 +158,8 @@ + + @@ -361,4 +363,8 @@ + + + + From 8e9f6cc0b28203a78763e8b30dd53f4725a319a3 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 24 Nov 2025 14:46:44 -0800 Subject: [PATCH 02/23] crossgen2: Fill in wasm header producing code in WasmObjectWriter, fix wasm arch+os target validation, add obj-format option for Wasm --- .../Compiler/ObjectWriter/ObjectWriter.cs | 4 +- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 63 ++++++++++++++++++- .../CodeGen/ReadyToRunContainerFormat.cs | 1 + .../CodeGen/ReadyToRunObjectWriter.cs | 6 ++ .../aot/crossgen2/Crossgen2RootCommand.cs | 5 +- src/coreclr/tools/aot/crossgen2/Program.cs | 2 +- 6 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs index ce8347cd072975..1935547e223ac7 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs @@ -78,7 +78,7 @@ private protected ObjectWriter(NodeFactory factory, ObjectWritingOptions options /// For associated sections, such as exception or debugging information, the /// will be different. /// - private protected SectionWriter GetOrCreateSection(ObjectNodeSection section, string comdatName = null, string symbolName = null) + internal virtual SectionWriter GetOrCreateSection(ObjectNodeSection section, string comdatName = null, string symbolName = null) { int sectionIndex; SectionData sectionData; @@ -304,7 +304,7 @@ private SortedSet GetUndefinedSymbols() return undefinedSymbolSet; } - public void EmitObject(Stream outputFileStream, IReadOnlyCollection nodes, IObjectDumper dumper, Logger logger) + public virtual void EmitObject(Stream outputFileStream, IReadOnlyCollection nodes, IObjectDumper dumper, Logger logger) { // Pre-create some of the sections GetOrCreateSection(ObjectNodeSection.TextSection); diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index b657990df29233..cde1ef366bb511 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -3,6 +3,7 @@ using System.IO; using System.Runtime.InteropServices; using ILCompiler.DependencyAnalysis; +using ILCompiler.DependencyAnalysisFramework; namespace ILCompiler.ObjectWriter { @@ -11,20 +12,76 @@ namespace ILCompiler.ObjectWriter /// internal sealed class WasmObjectWriter : ObjectWriter { - private const uint InvalidIndex = uint.MaxValue; - private const uint InvalidOffset = uint.MaxValue; + // must be stored in little-endian order + private const uint WasmMagicNumber = 0x6d736100; + // must be stored in little-endian order + private const uint WasmVersion = 0x1; + private Dictionary _sectionIndexToData = new(); + public WasmObjectWriter(NodeFactory factory, ObjectWritingOptions options, OutputInfoBuilder outputInfoBuilder) : base(factory, options, outputInfoBuilder) { } + public override void EmitObject(Stream outputFileStream, IReadOnlyCollection nodes, IObjectDumper dumper, Logger logger) + { + // (module) + SectionData data = new(); + SectionWriter headerWriter = new(this, 0, data); + headerWriter.WriteLittleEndian(WasmMagicNumber); + headerWriter.WriteLittleEndian(WasmVersion); + + data.GetReadStream().CopyTo(outputFileStream); + } + protected internal override void UpdateSectionAlignment(int sectionIndex, int alignment) => throw new NotImplementedException(); + + private void CreateSection(WasmSectionType sectionType, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) + { + + } + private protected override void CreateSection(ObjectNodeSection section, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) { + throw new NotImplementedException(); } - private protected override void EmitObjectFile(Stream outputFileStream) => throw new NotImplementedException(); + public enum WasmSectionType + { + Custom = 0, + Type = 1, + Import = 2, + Function = 3, + Table = 4, + Memory = 5, + Global = 6, + Export = 7, + Start = 8, + Element = 9, + Code = 10, + Data = 11, + DataCount = 12, + Tag = 13, + } + + public class WasmSection + { + public WasmSectionType Type { get; } + public string Name { get; } + public WasmSection(WasmSectionType type, string name) + { + Type = type; + Name = name; + } + } + + private Dictionary _sectionNameToSectionIndex = new(); + + private protected override void EmitObjectFile(Stream outputFileStream) + { + + } private protected override void EmitRelocations(int sectionIndex, List relocationList) => throw new NotImplementedException(); private protected override void EmitSymbolTable(IDictionary definedSymbols, SortedSet undefinedSymbols) => throw new NotImplementedException(); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunContainerFormat.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunContainerFormat.cs index eac1177708eb13..b08f12011a657f 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunContainerFormat.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunContainerFormat.cs @@ -7,5 +7,6 @@ public enum ReadyToRunContainerFormat { PE, MachO, + Wasm, } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index 45a398dc225a03..a9379c16043805 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -183,6 +183,7 @@ public void EmitReadyToRunObjects(ReadyToRunContainerFormat format, Logger logge { ReadyToRunContainerFormat.PE => CreatePEObjectWriter(), ReadyToRunContainerFormat.MachO => CreateMachObjectWriter(), + ReadyToRunContainerFormat.Wasm => CreateWasmObjectWriter(), _ => throw new UnreachableException() }; @@ -297,6 +298,11 @@ private MachObjectWriter CreateMachObjectWriter() return new MachObjectWriter(_nodeFactory, ObjectWritingOptions.None, _outputInfoBuilder, baseSymbolName: "__mh_dylib_header"); } + private WasmObjectWriter CreateWasmObjectWriter() + { + return new WasmObjectWriter(_nodeFactory, ObjectWritingOptions.None, _outputInfoBuilder); + } + public static void EmitObject( string objectFilePath, EcmaModule componentModule, diff --git a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs index 3f9d6d2506765b..32b80fb00832d9 100644 --- a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs +++ b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs @@ -296,8 +296,8 @@ public static void PrintExtendedHelp(ParseResult _) Console.WriteLine(SR.DashDashHelp); Console.WriteLine(); - string[] ValidArchitectures = new string[] {"arm", "armel", "arm64", "x86", "x64", "riscv64", "loongarch64"}; - string[] ValidOS = new string[] {"windows", "linux", "osx", "ios", "iossimulator", "maccatalyst"}; + string[] ValidArchitectures = new string[] {"arm", "armel", "arm64", "x86", "x64", "riscv64", "loongarch64", "wasm"}; + string[] ValidOS = new string[] {"windows", "linux", "osx", "ios", "iossimulator", "maccatalyst", "wasi"}; Console.WriteLine(String.Format(SR.SwitchWithDefaultHelp, "--targetos", String.Join("', '", ValidOS), Helpers.GetTargetOS(null).ToString().ToLowerInvariant())); Console.WriteLine(); @@ -416,6 +416,7 @@ private static ReadyToRunContainerFormat MakeOutputFormat(ArgumentResult result) { "pe" => ReadyToRunContainerFormat.PE, "macho" => ReadyToRunContainerFormat.MachO, + "wasm" => ReadyToRunContainerFormat.Wasm, _ => throw new CommandLineException(SR.InvalidOutputFormat) }; } diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs index dfc8dd737d358c..6600e6a9dcf105 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -402,7 +402,7 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru } ReadyToRunContainerFormat format = Get(_command.OutputFormat); - if (!composite && format != ReadyToRunContainerFormat.PE) + if (!composite && format != ReadyToRunContainerFormat.PE && format != ReadyToRunContainerFormat.Wasm) { throw new Exception(string.Format(SR.ErrorContainerFormatRequiresComposite, format)); } From 299212110664927a1d16415b63b76a63e57b7496 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 1 Dec 2025 14:50:26 -0800 Subject: [PATCH 03/23] crossgen2: Add basic wasm object writer implementation. It currently only handles writing method body nodes to the code section, in addition to building the type, function, and exports section. It will export all written methods so that they can be called when the module is loaded. --- .../Compiler/ObjectWriter/SectionWriter.cs | 9 + .../Compiler/ObjectWriter/WasmNative.cs | 169 +++++++++++++ .../Compiler/ObjectWriter/WasmObjectWriter.cs | 238 +++++++++++++++--- .../tools/Common/JitInterface/CorInfoImpl.cs | 2 + .../CodeGen/ReadyToRunObjectWriter.cs | 4 +- 5 files changed, 389 insertions(+), 33 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/SectionWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/SectionWriter.cs index 7ccfa9651a2fc7..29c260569e0a79 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/SectionWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/SectionWriter.cs @@ -125,6 +125,15 @@ public readonly void WriteUtf8String(string value) bufferWriter.Advance(size); } + public readonly void WriteUtf8StringNoNull(string value) + { + IBufferWriter bufferWriter = _sectionData.BufferWriter; + int size = Encoding.UTF8.GetByteCount(value); + Span buffer = bufferWriter.GetSpan(size); + Encoding.UTF8.GetBytes(value, buffer); + bufferWriter.Advance(size); + } + public readonly void WritePadding(int size) => _sectionData.AppendPadding(size); public readonly long Position => _sectionData.Length; diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs index c2df6a398e57e3..bb489f632bb9de 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -1,6 +1,175 @@ +using System; +using System.Buffers; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Numerics; using System.Runtime.CompilerServices; namespace ILCompiler.ObjectWriter { // TODO: fill in with Wasm specific section information + public enum WasmSectionType + { + Custom = 0, + Type = 1, + Import = 2, + Function = 3, + Table = 4, + Memory = 5, + Global = 6, + Export = 7, + Start = 8, + Element = 9, + Code = 10, + Data = 11, + DataCount = 12, + Tag = 13, + } + public static class WasmHelpers + { + public static void WriteLittleEndian(T value, Span buffer) + where T : IBinaryInteger + { + value.WriteLittleEndian(buffer); + } + } + + public static class DummyValues + { + // Wasm function signature for (func (params i32) (result i32)) + public static WasmFuncType CreateWasmFunc_i32_i32() + { + return new WasmFuncType( + paramTypes: new([WasmValueType.I32]), + returnTypes: new([WasmValueType.I32]) + ); + } + } + + public enum WasmValueType + { + I32 = 0x7F, + I64 = 0x7E, + F32 = 0x7D, + F64 = 0x7C + } + + public static class WasmValueTypeExtensions + { + public static string ToString(this WasmValueType valueType) + { + return valueType switch + { + WasmValueType.I32 => "i32", + WasmValueType.I64 => "i64", + WasmValueType.F32 => "f32", + WasmValueType.F64 => "f64", + _ => "unknown", + }; + } + } + + public struct WasmResultType : IEquatable + { + private readonly WasmValueType[] _types; + public readonly Span Types => _types; + + public WasmResultType(WasmValueType[] types) + { + _types = types; + } + + public bool Equals(WasmResultType other) => Enumerable.SequenceEqual(_types, other._types); + public override bool Equals(object obj) + { + return obj is WasmResultType other && Equals(other); + } + + public override int GetHashCode() => _types.Aggregate(0, (acc, val) => HashCode.Combine(acc, val.GetHashCode())); + + public int EncodeSize() + { + uint sizeLength = DwarfHelper.SizeOfULEB128((ulong)_types.Length); + return (int)(sizeLength + (uint)_types.Length); + } + + public int Encode(Span buffer) + { + DwarfHelper.WriteULEB128(buffer, (ulong)_types.Length); + uint sizeLength = DwarfHelper.SizeOfULEB128((ulong)_types.Length); + for (int i = 0; i < _types.Length; i++) + { + buffer[(int)sizeLength + i] = (byte)_types[i]; + } + return (int)(sizeLength + (uint)_types.Length); + } + } + + public struct WasmFuncType : IEquatable + { + private readonly WasmResultType _params; + private readonly WasmResultType _returns; + + public WasmFuncType(WasmResultType paramTypes, WasmResultType returnTypes) + { + _params = paramTypes; + _returns = returnTypes; + } + + public readonly byte[] Encode() + { + int totalSize = 1+_params.EncodeSize() + _returns.EncodeSize(); + byte[] buffer = new byte[totalSize]; + buffer[0] = 0x60; // function type indicator + + var span = buffer.AsSpan(); + + int paramSize = _params.Encode(span.Slice(1)); + int returnSize = _returns.Encode(span.Slice(1+paramSize)); + Debug.Assert(totalSize == 1 + paramSize + returnSize); + return buffer; + } + + public bool Equals(WasmFuncType other) + { + return _params.Equals(other._params) && _returns.Equals(other._returns); + } + + public override bool Equals(object obj) + { + return obj is WasmFuncType other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(_params.GetHashCode(), _returns.GetHashCode()); + } + + public override string ToString() + { + string paramList = _params.ToTypeListString(); + string returnList = _returns.ToTypeListString(); + + if (string.IsNullOrEmpty(returnList)) + return $"(func (param {paramList}))"; + return $"(func (param {paramList}) (result {returnList}))"; + } + } + + // Add this extension to WasmResultType for ToString support + public static class WasmResultTypeExtensions + { + public static string ToTypeListString(this WasmResultType result) + { + // Use reflection to access _types since it's private and readonly + var types = result.Types.ToArray(); + + if (types == null || types.Length == 0) + return string.Empty; + + return string.Join(" ", types.Select(t => t.ToString())); + } + } } diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index cde1ef366bb511..911cd860b83f55 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -1,12 +1,90 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Numerics; using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Text; +using System.Xml.Linq; using ILCompiler.DependencyAnalysis; using ILCompiler.DependencyAnalysisFramework; +using Internal.TypeSystem; namespace ILCompiler.ObjectWriter { + // This is a placeholder for now. It will need to be filled in with ABI-specific signatures + // for any method we want to emit into the Wasm module. + public class WasmAbiContext + { + private Dictionary _methodSignatureMap = new(); + public WasmFuncType GetSignature(MethodDesc method) + { + return DummyValues.CreateWasmFunc_i32_i32(); + } + } + + internal class WasmSection + { + public WasmSectionType Type { get; } + public string Name { get; } + public SectionData Data => _data; + public SectionData PrependData => _prepend; + private SectionWriter? _writer; + private SectionWriter? _prependWriter; + + private SectionData _data; + private SectionData _prepend; + + public Span Header + { + get + { + // Section header consists of: + // 1 byte: section type + // ULEB128: size of section (including prepend and data) (max = ceil(64/7) = 10 bytes) + Span header = new byte[1+10]; + ulong sectionSize = (ulong)(_prepend.Length) + (ulong)_data.Length; + + header[0] = (byte)Type; + DwarfHelper.WriteULEB128(header.Slice(1), (ulong)sectionSize); + return header.Slice(0, (int)(1 + DwarfHelper.SizeOfULEB128(sectionSize))); + } + } + + public SectionWriter Writer + { + get + { + if (_writer == null) + { + _writer = new SectionWriter(null, 0, _data); + } + return _writer.Value; + } + } + + public SectionWriter PrependWriter + { + get + { + if (_prependWriter == null) + { + _prependWriter = new SectionWriter(null, 0, _prepend); + } + return _prependWriter.Value; + } + } + + public WasmSection(WasmSectionType type, SectionData data, string name) + { + Type = type; + Name = name; + _data = data; + _prepend = new SectionData(); + } + } + /// /// Wasm object file format writer. /// @@ -17,16 +95,17 @@ internal sealed class WasmObjectWriter : ObjectWriter // must be stored in little-endian order private const uint WasmVersion = 0x1; - private Dictionary _sectionIndexToData = new(); - - public WasmObjectWriter(NodeFactory factory, ObjectWritingOptions options, OutputInfoBuilder outputInfoBuilder) + + private WasmAbiContext _wasmAbiContext; + + public WasmObjectWriter(NodeFactory factory, ObjectWritingOptions options, WasmAbiContext ctx, OutputInfoBuilder outputInfoBuilder) : base(factory, options, outputInfoBuilder) { + _wasmAbiContext = ctx; } - public override void EmitObject(Stream outputFileStream, IReadOnlyCollection nodes, IObjectDumper dumper, Logger logger) + private void EmitWasmHeader(Stream outputFileStream) { - // (module) SectionData data = new(); SectionWriter headerWriter = new(this, 0, data); headerWriter.WriteLittleEndian(WasmMagicNumber); @@ -35,52 +114,147 @@ public override void EmitObject(Stream outputFileStream, IReadOnlyCollection throw new NotImplementedException(); + public override void EmitObject(Stream outputFileStream, IReadOnlyCollection nodes, IObjectDumper dumper, Logger logger) + { + ArrayBuilder methodSignatures = new(); + ArrayBuilder methodBodies = new(); + foreach (DependencyNode node in nodes) + { + if (node is not ObjectNode) + { + continue; + } + + if (node is IMethodBodyNode methodNode) + { + methodSignatures.Add(_wasmAbiContext.GetSignature(methodNode.Method)); + methodBodies.Add(methodNode); + // TODO: record relocations + } + } - private void CreateSection(WasmSectionType sectionType, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) + Dictionary signatureMap = new(); + int signatureIndex = 0; + for (int i = 0; i < methodSignatures.Count; i++) + { + if (!signatureMap.ContainsKey(methodSignatures[i])) + { + signatureMap[methodSignatures[i]] = signatureIndex++; + } + } + + WasmFuncType[] uniqueSignatures = new WasmFuncType[signatureMap.Count]; + foreach (var kvp in signatureMap) + { + uniqueSignatures[kvp.Value] = kvp.Key; + } + + EmitWasmHeader(outputFileStream); + EmitSection(() => WriteTypeSection(uniqueSignatures, logger), outputFileStream, logger); + EmitSection(() => WriteFunctionSection(methodSignatures.ToArray(), signatureMap, logger), outputFileStream, logger); + EmitSection(() => WriteExportSection(methodBodies.ToArray(), methodSignatures.ToArray(), signatureMap, logger), outputFileStream, logger); + EmitSection(() => WriteCodeSection(methodBodies.ToArray(), logger), outputFileStream, logger); + } + + private WasmSection WriteExportSection(IReadOnlyCollection methodNodes, IReadOnlyCollection methodSignatures, + Dictionary signatureMap, Logger logger) { + WasmSection exportSection = new WasmSection(WasmSectionType.Export, new SectionData(), "export"); + SectionWriter writer = exportSection.Writer; + // Write the number of exports + writer.WriteULEB128((ulong)methodNodes.Count); + for (int i = 0; i < methodNodes.Count; i++) + { + var methodNode = methodNodes.ElementAt(i); + var methodSignature = methodSignatures.ElementAt(i); + string exportName = methodNode.GetMangledName(_nodeFactory.NameMangler); + var length = Encoding.UTF8.GetByteCount(exportName); + writer.WriteULEB128((ulong)length); + writer.WriteUtf8StringNoNull(exportName); + writer.WriteByte(0x00); // export kind: function + writer.WriteULEB128((ulong)i); + logger.LogMessage($"Emitting export: {exportName} for function index {signatureMap[methodSignature]}"); + } + + return exportSection; } - private protected override void CreateSection(ObjectNodeSection section, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) + private WasmSection WriteCodeSection(IReadOnlyCollection methodBodies, Logger logger) { - throw new NotImplementedException(); + WasmSection codeSection = new WasmSection(WasmSectionType.Code, new SectionData(), "code"); + + SectionWriter prependWriter = codeSection.PrependWriter; + SectionWriter writer = codeSection.Writer; + + // Write the number of functions + prependWriter.WriteULEB128((ulong)methodBodies.Count); + foreach (IMethodBodyNode methodBody in methodBodies) + { + ObjectNode objectNode = methodBody as ObjectNode; + ObjectNode.ObjectData body = objectNode.GetData(_nodeFactory); + + writer.WriteULEB128((ulong)body.Data.Length); + writer.EmitData(body.Data); + } + + return codeSection; } - public enum WasmSectionType + private WasmSection WriteTypeSection(Span functionSignatures, Logger logger) { - Custom = 0, - Type = 1, - Import = 2, - Function = 3, - Table = 4, - Memory = 5, - Global = 6, - Export = 7, - Start = 8, - Element = 9, - Code = 10, - Data = 11, - DataCount = 12, - Tag = 13, + WasmSection typeSection = new WasmSection(WasmSectionType.Type, new SectionData(), "type"); + SectionWriter writer = typeSection.Writer; + + // Write the number of types + writer.WriteULEB128((ulong)functionSignatures.Length); + foreach (WasmFuncType signature in functionSignatures) + { + logger.LogMessage($"Emitting function signature: {signature}"); + writer.EmitData(signature.Encode()); + } + return typeSection; } - public class WasmSection + private WasmSection WriteFunctionSection(WasmFuncType[] allFunctionSignatures, IDictionary signatureMap, Logger logger) { - public WasmSectionType Type { get; } - public string Name { get; } - public WasmSection(WasmSectionType type, string name) + WasmSection functionSection = new WasmSection(WasmSectionType.Function, new SectionData(), "function"); + + SectionWriter writer = functionSection.Writer; + // Write the number of functions + writer.WriteULEB128((ulong)allFunctionSignatures.Length); + for (int i = 0; i < allFunctionSignatures.Length; i++) { - Type = type; - Name = name; + var signature = allFunctionSignatures[i]; + writer.WriteULEB128((ulong)signatureMap[signature]); } + return functionSection; } - private Dictionary _sectionNameToSectionIndex = new(); + private void EmitSection(Func writeFunc, Stream outputFileStream, Logger logger) + { + var section = writeFunc(); - private protected override void EmitObjectFile(Stream outputFileStream) + outputFileStream.Write(section.Header); + section.PrependData.GetReadStream().CopyTo(outputFileStream); + + logger.LogMessage($"Wrote section header of size {section.Header.Length} bytes."); + + section.Data.GetReadStream().CopyTo(outputFileStream); + logger.LogMessage($"Emitted section: {section.Name} of type `{section.Type}` with prepend size {section.PrependData.Length} bytes and size {section.Data.Length} bytes."); + } + + protected internal override void UpdateSectionAlignment(int sectionIndex, int alignment) => throw new NotImplementedException(); + + private WasmSection CreateSection(WasmSectionType sectionType, string symbolName, int sectionIndex) => throw new NotImplementedException(); + + private protected override void CreateSection(ObjectNodeSection section, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) { + throw new NotImplementedException(); + } + private protected override void EmitObjectFile(Stream outputFileStream) + { } private protected override void EmitRelocations(int sectionIndex, List relocationList) => throw new NotImplementedException(); private protected override void EmitSymbolTable(IDictionary definedSymbols, SortedSet undefinedSymbols) => throw new NotImplementedException(); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 26a3c93d4dd1e7..c9fb3335b06523 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -321,9 +321,11 @@ IntPtr LocalObjectToHandle(object input) private CorJitResult CompileWasmStub(out IntPtr exception, ref CORINFO_METHOD_INFO methodInfo, out uint codeSize) { byte[] stub = new byte[] { + 0x00, 0x41, // i32.const 0x0, // uleb128 0 0x0f, // return + 0x0b, // end }; AllocMemArgs args = new AllocMemArgs { diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index a9379c16043805..0ad4af96f29c37 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -300,7 +300,9 @@ private MachObjectWriter CreateMachObjectWriter() private WasmObjectWriter CreateWasmObjectWriter() { - return new WasmObjectWriter(_nodeFactory, ObjectWritingOptions.None, _outputInfoBuilder); + // empty for now as a placeholder, this will be needed when we have Wasm specific ABI handling + var abiContext = new WasmAbiContext(); + return new WasmObjectWriter(_nodeFactory, ObjectWritingOptions.None, abiContext, _outputInfoBuilder); } public static void EmitObject( From 369d221f88da47afe7a0e52110385a4e00c6f58e Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 2 Dec 2025 10:54:41 -0800 Subject: [PATCH 04/23] crossgen2: wasm object writer: remove unnecessary slice --- .../Compiler/ObjectWriter/WasmNative.cs | 50 ++++++------- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 72 ++++++++----------- 2 files changed, 54 insertions(+), 68 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs index bb489f632bb9de..73b6cc2bd4016e 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -9,7 +9,6 @@ namespace ILCompiler.ObjectWriter { - // TODO: fill in with Wasm specific section information public enum WasmSectionType { Custom = 0, @@ -27,14 +26,6 @@ public enum WasmSectionType DataCount = 12, Tag = 13, } - public static class WasmHelpers - { - public static void WriteLittleEndian(T value, Span buffer) - where T : IBinaryInteger - { - value.WriteLittleEndian(buffer); - } - } public static class DummyValues { @@ -87,7 +78,19 @@ public override bool Equals(object obj) return obj is WasmResultType other && Equals(other); } - public override int GetHashCode() => _types.Aggregate(0, (acc, val) => HashCode.Combine(acc, val.GetHashCode())); + public override int GetHashCode() + { + if (_types == null || _types.Length == 0) + return 0; + + int code = _types[0].GetHashCode(); + for (int i = 1; i < _types.Length; i++) + { + code = HashCode.Combine(code, _types[i].GetHashCode()); + } + + return code; + } public int EncodeSize() { @@ -107,6 +110,19 @@ public int Encode(Span buffer) } } + public static class WasmResultTypeExtensions + { + public static string ToTypeListString(this WasmResultType result) + { + var types = result.Types.ToArray(); + + if (types == null || types.Length == 0) + return string.Empty; + + return string.Join(" ", types.Select(t => WasmValueTypeExtensions.ToString(t))); + } + } + public struct WasmFuncType : IEquatable { private readonly WasmResultType _params; @@ -158,18 +174,4 @@ public override string ToString() } } - // Add this extension to WasmResultType for ToString support - public static class WasmResultTypeExtensions - { - public static string ToTypeListString(this WasmResultType result) - { - // Use reflection to access _types since it's private and readonly - var types = result.Types.ToArray(); - - if (types == null || types.Length == 0) - return string.Empty; - - return string.Join(" ", types.Select(t => t.ToString())); - } - } } diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 911cd860b83f55..4f64827d62ff16 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -29,12 +29,9 @@ internal class WasmSection public WasmSectionType Type { get; } public string Name { get; } public SectionData Data => _data; - public SectionData PrependData => _prepend; private SectionWriter? _writer; - private SectionWriter? _prependWriter; private SectionData _data; - private SectionData _prepend; public Span Header { @@ -42,13 +39,15 @@ public Span Header { // Section header consists of: // 1 byte: section type - // ULEB128: size of section (including prepend and data) (max = ceil(64/7) = 10 bytes) - Span header = new byte[1+10]; - ulong sectionSize = (ulong)(_prepend.Length) + (ulong)_data.Length; + // ULEB128: size of section + ulong sectionSize = (ulong)_data.Length; + var encodeLength = DwarfHelper.SizeOfULEB128(sectionSize); + Span header = new byte[1+encodeLength]; header[0] = (byte)Type; - DwarfHelper.WriteULEB128(header.Slice(1), (ulong)sectionSize); - return header.Slice(0, (int)(1 + DwarfHelper.SizeOfULEB128(sectionSize))); + DwarfHelper.WriteULEB128(header.Slice(1), sectionSize); + + return header; } } @@ -64,24 +63,11 @@ public SectionWriter Writer } } - public SectionWriter PrependWriter - { - get - { - if (_prependWriter == null) - { - _prependWriter = new SectionWriter(null, 0, _prepend); - } - return _prependWriter.Value; - } - } - public WasmSection(WasmSectionType type, SectionData data, string name) { Type = type; Name = name; _data = data; - _prepend = new SectionData(); } } @@ -129,8 +115,8 @@ public override void EmitObject(Stream outputFileStream, IReadOnlyCollection signatureMap = new(); @@ -174,7 +160,10 @@ private WasmSection WriteExportSection(IReadOnlyCollection meth writer.WriteUtf8StringNoNull(exportName); writer.WriteByte(0x00); // export kind: function writer.WriteULEB128((ulong)i); - logger.LogMessage($"Emitting export: {exportName} for function index {signatureMap[methodSignature]}"); + if (logger.IsVerbose) + { + logger.LogMessage($"Emitting export: {exportName} for function index {signatureMap[methodSignature]}"); + } } return exportSection; @@ -184,11 +173,9 @@ private WasmSection WriteCodeSection(IReadOnlyCollection method { WasmSection codeSection = new WasmSection(WasmSectionType.Code, new SectionData(), "code"); - SectionWriter prependWriter = codeSection.PrependWriter; SectionWriter writer = codeSection.Writer; - // Write the number of functions - prependWriter.WriteULEB128((ulong)methodBodies.Count); + writer.WriteULEB128((ulong)methodBodies.Count); foreach (IMethodBodyNode methodBody in methodBodies) { ObjectNode objectNode = methodBody as ObjectNode; @@ -210,7 +197,10 @@ private WasmSection WriteTypeSection(Span functionSignatures, Logg writer.WriteULEB128((ulong)functionSignatures.Length); foreach (WasmFuncType signature in functionSignatures) { - logger.LogMessage($"Emitting function signature: {signature}"); + if (logger.IsVerbose) + { + logger.LogMessage($"Emitting function signature: {signature}"); + } writer.EmitData(signature.Encode()); } return typeSection; @@ -236,29 +226,23 @@ private void EmitSection(Func writeFunc, Stream outputFileStream, L var section = writeFunc(); outputFileStream.Write(section.Header); - section.PrependData.GetReadStream().CopyTo(outputFileStream); - - logger.LogMessage($"Wrote section header of size {section.Header.Length} bytes."); + if (logger.IsVerbose) + { + logger.LogMessage($"Wrote section header of size {section.Header.Length} bytes."); + } section.Data.GetReadStream().CopyTo(outputFileStream); - logger.LogMessage($"Emitted section: {section.Name} of type `{section.Type}` with prepend size {section.PrependData.Length} bytes and size {section.Data.Length} bytes."); + if (logger.IsVerbose) + { + logger.LogMessage($"Emitted section: {section.Name} of type `{section.Type}` with size {section.Data.Length} bytes."); + } } protected internal override void UpdateSectionAlignment(int sectionIndex, int alignment) => throw new NotImplementedException(); - private WasmSection CreateSection(WasmSectionType sectionType, string symbolName, int sectionIndex) => throw new NotImplementedException(); - - private protected override void CreateSection(ObjectNodeSection section, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) - { - throw new NotImplementedException(); - } - - private protected override void EmitObjectFile(Stream outputFileStream) - { - } + private protected override void CreateSection(ObjectNodeSection section, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) => throw new NotImplementedException(); + private protected override void EmitObjectFile(Stream outputFileStream) => throw new NotImplementedException(); private protected override void EmitRelocations(int sectionIndex, List relocationList) => throw new NotImplementedException(); private protected override void EmitSymbolTable(IDictionary definedSymbols, SortedSet undefinedSymbols) => throw new NotImplementedException(); - } - } From 984551e399909a8264a7585e2c91de40d817cae7 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 2 Dec 2025 11:11:01 -0800 Subject: [PATCH 05/23] crossgen2: wasm object writer: remove class diagram --- .../ILCompiler.ReadyToRun/ClassDiagram1.cd | 603 ------------------ 1 file changed, 603 deletions(-) delete mode 100644 src/coreclr/tools/aot/ILCompiler.ReadyToRun/ClassDiagram1.cd diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ClassDiagram1.cd b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ClassDiagram1.cd deleted file mode 100644 index 69e8947568b8e1..00000000000000 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ClassDiagram1.cd +++ /dev/null @@ -1,603 +0,0 @@ - - - - - - AAIQEACAGACAAAAAAAAAAAAAABQAAAAAAAAAAAAAnAA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs - - - - - - - AAAQAAIAEAGAAAAAAAAAA0QEAAAAAAAAAAAAAAEAAEA= - tools\Common\Compiler\DependencyAnalysis\ObjectNode.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAEQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs - - - - - - AAAAAAAAAAAAAAAAAAAgAAAAAAQAAAEAAAAAAAAAEQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs - - - - - - AQAAEAAACAAAAAEAAAAABgAAAAAAAAEAAgAAACAABQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodGCInfoNode.cs - - - - - - AAQQAAIAAEEAAAEAIACgAAQEAAAAAAIAAAAAAAEAAEA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\EmbeddedObjectNode.cs - - - - - - AAAAAAAAgAAAAAAAAAAAAAAAAAAAAAEAIAAAAAAABQA= - tools\Common\Compiler\DependencyAnalysis\SortableDependencyNode.cs - - - - - - - AAAAEAAACAAAAAEAAAggQiQAAAAAAAGAAgAAACAABQE= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\Import.cs - - - - - - - - - - - - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ImportSectionNode.cs - - - - - AAAEMQiCAAAKAAUAAAgAAgQAAAIAQQEAAAAAAAQAFQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ImportSectionNode.cs - - - - - - AAAAEAAACAAAAAEAAAAAAiAAAAAAAACAAACAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\EmbeddedPointerIndirectionNode.cs - - - - - - - AAAAAAAACAAAAAEAAAAAAgAAAAAAAAEAAAAAAAAABQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\SignatureEmbeddedPointerIndirectionNode.cs - - - - - - AAAAAAAACAAAAAEAAAAAAgAgAACAAAEAAAAgACAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DelayLoadHelperImport.cs - - - - - - AAAAAAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAAAAAABQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\PrecodeHelperImport.cs - - - - - - AAAAAAAAAAAACAEAAAAAAAQAAAAAAAEAAAAAAAAABQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\StringImport.cs - - - - - - QAAAAAAACACAAAAAAABgAgAAAAAAAAEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\PrecodeMethodImport.cs - - - - - - - AAAAAAAAAAAAAAAAAABgAgAAAAAAABEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DelayLoadHelperMethodImport.cs - - - - - - - QAAAAAAAAACAAAAAAAAgAgAAAAAAAAEAAAAAAgAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DelayLoadMethodImport.cs - - - - - - - AAAEAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAACAABQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ImportSectionsTableNode.cs - - - - - - - AAAQEIAIEACABAAEAAAAAUAAABAEAAAAAAAAACAADQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ArrayOfEmbeddedDataNode.cs - - - - - - AAAAAAAACAAAAAQAAAAAAAAAAAAAAAEAAAAAAAAAgQA= - tools\Common\Compiler\DependencyAnalysis\EmbeddedDataContainerNode.cs - - - - - - - AAAQEAAACACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\Signature.cs - - - - - - - AAAAAAAAGAAAAAAAACAAAEAEAAAAAAEAAAAgAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DelegateCtorSignature.cs - - - - - - AAAAAAAAGAAAAAAAAAAAQAAAAAAAAQEAAAAAQAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\FieldFixupSignature.cs - - - - - - CAAAAAAAWAAACAAAAAAAAEAAAAAAAQECAAAAAAAAAwA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\GenericLookupSignature.cs - - - - - - AACAAAAAGAAAAAAEgABAAAAAAAAAAQEAAgAAAAAIAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ILBodyFixupSignature.cs - - - - - - - AAAACAAAGAAAAIAAAABgAEAAAAAAAQFQAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodFixupSignature.cs - - - - - - AAAAACAAGAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\NewArrayFixupSignature.cs - - - - - - AAAAAAAAGAAAAAAAAAAAAAAABAAAAAEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\NewObjectFixupSignature.cs - - - - - - AAAAAAAAGAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ReadyToRunHelperSignature.cs - - - - - - AAAAIAAAGAAAACAAAAAAgAAAAAAAAAEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ReadyToRunInstructionSetSupportSignature.cs - - - - - - AAAAAAAAGAAACAAAAAAAAAAAAAAAAAEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\StringImportSignature.cs - - - - - - AAAAAAAAGAAAAAAAAAAAEEAARAAAAQEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\TypeFixupSignature.cs - - - - - - AAABAAAAGAAAAAAEgAAAIAAAABAAAQEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\VirtualResolutionFixupSignature.cs - - - - - - - IAAAAgEAGCIICAAQAoEIFAAAAAgAAAAABAAAAAiAAQg= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ManifestMetadataTableNode.cs - - - - - - AAAAAEAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodEntryPointTableNode.cs - - - - - - AAAQEAAACACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhAA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs - - - - - - - ABAAAEAACAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HeaderNode.cs - - - - - - - - - - - - - - ABAQEAAAGACAgAAAAAgAAAAAAAAAAAEAAQAAAAAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedCorHeaderNode.cs - - - - - - - AAAAAAAAGAAAAAAAEAAAAAAAAAAAAAEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs - - - - - - - - - - - - - - ABAQEABAGACAAAAAAAAAAAAAAAAAAAEAAAAAAAABhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedFieldRvaNode.cs - - - - - - - - - - - - - - - - - - - ABAQEAAAGACAgAAAAAAAAAAAAAAAAAEAAAAAAAAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedManagedResourcesNode.cs - - - - - - - - - - - - - - - AAAQEAAAGACAgAABAACAAAAAAAAAAAEAAEAAAAAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedMetadataBlobNode.cs - - - - - - - - - - - - - - - AAAQEAAAGACAAAAAAABAAAAAAAAAAAEAAAAAAAAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedMethodILNode.cs - - - - - - - ABAQEAAAGACAgAAAAAAAAAAAAAAAAAEAAAAAAAAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CopiedStrongNameSignatureNode.cs - - - - - - - - - - - - - - - AAAACAAAGACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\CompilerIdentifierNode.cs - - - - - - AAIAAAAAGAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\AssemblyTableNode.cs - - - - - - - - - - - - - - ABAQEAAACACAAAAAAAAAAAAAAAAAAAEAAAAAAAAAhAA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs - - - - - - - AAAAAAAQGAAAAAAAAAAAABAQAAAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugInfoTableNode.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs - - - - - - AAAQEAAAWASAAAAAAAAAAAQAAAAAAAAAAAAAAAAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ExceptionInfoLookupTableNode.cs - - - - - - - AQAAAEAAEAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\EnclosingTypeMapNode.cs - - - - - - AAAAAAAAGAAACAgAAIAAAUAQAAAAAAAAAAAAACAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ExceptionInfoLookupTableNode.cs - - - - - - AABQEAAAGACQAIAAAAAAAAAAAAAAAQEAAAAAAgAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\GCRefMapNode.cs - - - - - - - AAAAAAAAGAABAAAAAAAAAAAAAAAAAAAAAAAAgAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\HotColdMapNode.cs - - - - - - AAAAAAAACAAAAAAABgBAAEAAAgAAAAGAAgAEAAAABQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\Target_ARM\ImportThunk.cs - - - - - - - AAAQGAAAGACAAAAAAABAAAAAAAAAAAAAAAAAAAAAgAA= - tools\Common\Compiler\DependencyAnalysis\AssemblyStubNode.cs - - - - - - - AAAAAEAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\TypesTableNode.cs - - - - - - AQAAAEAAEAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\TypeGenericInfoMapNode.cs - - - - - - AAAEABAIHACACBAQAAAAAAAAAAAAAAAAAAAAACAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\RuntimeFunctionsTableNode.cs - - - - - - AAAQEAAAAACAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\RuntimeFunctionsGCInfoNode.cs - - - - - - AAAAABAAmAAAgAAAAAAAAAGAAAAoCAEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs - - - - - - AAAEAAAAGACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\OwnerCompositeExecutableNode.cs - - - - - - - - - - - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs - - - - - - AAAAAAQAGAQAgAAABAAAAAAAICAgAAEAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs - - - - - - AQAAAEAAEAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodIsGenericMapNode.cs - - - - - - AAEQEAAAGACAAAAAAAAAAIAAAAAAAAEAAAAAgAAAhQg= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodColdCodeNode.cs - - - - - - - AAgQEAAAGACAgAAAAAAAAAAAAAAAAAAAAAAAAAAAhQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\ManifestAssemblyMvidHeaderNode.cs - - - - - - - AAAAAAAAGAAAAYACAAAAAEAAAAAAAAAEAAACAAAAEQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\InstrumentationDataTableNode.cs - - - - - - AAAEAAAAGgAAAAAAAAAAAAAAAAIAAAAAAAASAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\InstanceEntryPointTableNode.cs - - - - - - - AAAAAFAAMAAAAYAAAAAAAAAAAAAAAAAAAQAAAAAAAQA= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\InliningInfoNode.cs - - - - - - IYBTUBKAGFCCgiEEgEBgAUgIgECEAYUIAgIAAAJAlQg= - tools\aot\ILCompiler.ReadyToRun\Compiler\DependencyAnalysis\ReadyToRun\MethodWithGCInfo.cs - - - - - \ No newline at end of file From 152c5c91732301ab84c536b68a90abd2d73d3c3f Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:22:35 -0800 Subject: [PATCH 06/23] Add license header to src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> --- src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs index 73b6cc2bd4016e..3c6dadb4f06b58 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; using System.Buffers; using System.Diagnostics; From 63386989ab9a6228784d12908ccc239483a53214 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:22:55 -0800 Subject: [PATCH 07/23] Add license header to src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 4f64827d62ff16..fdb9922fca25ee 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -1,4 +1,7 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; using System.Collections.Generic; using System.IO; using System.Linq; From da98f247d1092bdca5b9bd47677d7fa142b71de2 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:23:50 -0800 Subject: [PATCH 08/23] Update src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index fdb9922fca25ee..65b181788bc4f3 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -212,7 +212,6 @@ private WasmSection WriteTypeSection(Span functionSignatures, Logg private WasmSection WriteFunctionSection(WasmFuncType[] allFunctionSignatures, IDictionary signatureMap, Logger logger) { WasmSection functionSection = new WasmSection(WasmSectionType.Function, new SectionData(), "function"); - SectionWriter writer = functionSection.Writer; // Write the number of functions writer.WriteULEB128((ulong)allFunctionSignatures.Length); From 319d0a610c7faf77c11e5601bf7df00fe65b53e3 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:32:47 -0800 Subject: [PATCH 09/23] Update src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs index 3c6dadb4f06b58..b5142f5fb4a76e 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -2,13 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Buffers; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Linq; -using System.Numerics; -using System.Runtime.CompilerServices; namespace ILCompiler.ObjectWriter { From 3f8bef1b64dc14fa2e2148f6e4877a3ae0d4f3d3 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:33:29 -0800 Subject: [PATCH 10/23] Update src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 65b181788bc4f3..5b5f1c426b62be 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -165,7 +165,7 @@ private WasmSection WriteExportSection(IReadOnlyCollection meth writer.WriteULEB128((ulong)i); if (logger.IsVerbose) { - logger.LogMessage($"Emitting export: {exportName} for function index {signatureMap[methodSignature]}"); + logger.LogMessage($"Emitting export: {exportName} for function index {i}"); } } From b3f7b740a6464298e7d755391166d4d74a320443 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:33:43 -0800 Subject: [PATCH 11/23] Update src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index c9fb3335b06523..3f870fa992a945 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -371,7 +371,6 @@ private CompilationResult CompileMethodInternal(IMethodNode methodCodeNodeNeedin uint codeSize; TargetArchitecture architecture = _compilation.TypeSystemContext.Target.Architecture; - var result = architecture switch { // We currently do not have WASM codegen support, but for testing, we will return a stub TargetArchitecture.Wasm32 => CompileWasmStub(out exception, ref methodInfo, out codeSize), From 8ce8bd6adf7cf25377ff52d8d4241bd1ae69b660 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:34:21 -0800 Subject: [PATCH 12/23] Update src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 5b5f1c426b62be..5b01d72c1a8ca3 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -5,11 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Numerics; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; using System.Text; -using System.Xml.Linq; using ILCompiler.DependencyAnalysis; using ILCompiler.DependencyAnalysisFramework; using Internal.TypeSystem; From 8b3fbeeedbf280d812db28d24e0d1dee0841978a Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:34:51 -0800 Subject: [PATCH 13/23] Update src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index dd8fddcca4aaa5..61f1c9a6bb39e6 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -370,7 +370,5 @@ - - - + From 72c063b9dde1499477b7522dc586eb82b908f5e0 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:35:20 -0800 Subject: [PATCH 14/23] Update src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 5b01d72c1a8ca3..8b300c5ae88f2f 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -100,7 +100,7 @@ private void EmitWasmHeader(Stream outputFileStream) } public override void EmitObject(Stream outputFileStream, IReadOnlyCollection nodes, IObjectDumper dumper, Logger logger) - { + { ArrayBuilder methodSignatures = new(); ArrayBuilder methodBodies = new(); foreach (DependencyNode node in nodes) From 30e03672b8825fcd2b7ecc3e3f885455c3b87089 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:35:43 -0800 Subject: [PATCH 15/23] Update src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 3f870fa992a945..41a9e27b368309 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -321,7 +321,7 @@ IntPtr LocalObjectToHandle(object input) private CorJitResult CompileWasmStub(out IntPtr exception, ref CORINFO_METHOD_INFO methodInfo, out uint codeSize) { byte[] stub = new byte[] { - 0x00, + 0x00, // local variable count 0x41, // i32.const 0x0, // uleb128 0 0x0f, // return From ec632e406f93324429ce62bc54c989a1c4984d41 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 2 Dec 2025 11:53:17 -0800 Subject: [PATCH 16/23] Use collection expression for crossgen valid OS+Arch lists Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> --- src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs index 32b80fb00832d9..9a4761ea16c522 100644 --- a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs +++ b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs @@ -296,8 +296,8 @@ public static void PrintExtendedHelp(ParseResult _) Console.WriteLine(SR.DashDashHelp); Console.WriteLine(); - string[] ValidArchitectures = new string[] {"arm", "armel", "arm64", "x86", "x64", "riscv64", "loongarch64", "wasm"}; - string[] ValidOS = new string[] {"windows", "linux", "osx", "ios", "iossimulator", "maccatalyst", "wasi"}; + string[] ValidArchitectures = ["arm", "armel", "arm64", "x86", "x64", "riscv64", "loongarch64", "wasm"]; + string[] ValidOS = ["windows", "linux", "osx", "ios", "iossimulator", "maccatalyst", "wasi"]; Console.WriteLine(String.Format(SR.SwitchWithDefaultHelp, "--targetos", String.Join("', '", ValidOS), Helpers.GetTargetOS(null).ToString().ToLowerInvariant())); Console.WriteLine(); From 9c3586511fb2be47ca4f93868afbc6acf50a3a3c Mon Sep 17 00:00:00 2001 From: adamperlin Date: Tue, 2 Dec 2025 13:49:37 -0800 Subject: [PATCH 17/23] Fix some copilot suggested changes --- .../Compiler/ObjectWriter/WasmNative.cs | 4 +-- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 25 +++++++++++-------- .../tools/Common/JitInterface/CorInfoImpl.cs | 3 ++- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs index b5142f5fb4a76e..cefd7507b9aab1 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -47,7 +47,7 @@ public enum WasmValueType public static class WasmValueTypeExtensions { - public static string ToString(this WasmValueType valueType) + public static string ToTypeString(this WasmValueType valueType) { return valueType switch { @@ -117,7 +117,7 @@ public static string ToTypeListString(this WasmResultType result) if (types == null || types.Length == 0) return string.Empty; - return string.Join(" ", types.Select(t => WasmValueTypeExtensions.ToString(t))); + return string.Join(" ", types.Select(t => WasmValueTypeExtensions.ToTypeString(t))); } } diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 8b300c5ae88f2f..df6785667b33d5 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -16,7 +16,6 @@ namespace ILCompiler.ObjectWriter // for any method we want to emit into the Wasm module. public class WasmAbiContext { - private Dictionary _methodSignatureMap = new(); public WasmFuncType GetSignature(MethodDesc method) { return DummyValues.CreateWasmFunc_i32_i32(); @@ -138,7 +137,7 @@ public override void EmitObject(Stream outputFileStream, IReadOnlyCollection WriteTypeSection(uniqueSignatures, logger), outputFileStream, logger); EmitSection(() => WriteFunctionSection(methodSignatures.ToArray(), signatureMap, logger), outputFileStream, logger); EmitSection(() => WriteExportSection(methodBodies.ToArray(), methodSignatures.ToArray(), signatureMap, logger), outputFileStream, logger); - EmitSection(() => WriteCodeSection(methodBodies.ToArray(), logger), outputFileStream, logger); + EmitSection(() => WriteCodeSection(methodBodies.ToArray(), logger), outputFileStream, logger); } private WasmSection WriteExportSection(IReadOnlyCollection methodNodes, IReadOnlyCollection methodSignatures, @@ -177,11 +176,17 @@ private WasmSection WriteCodeSection(IReadOnlyCollection method writer.WriteULEB128((ulong)methodBodies.Count); foreach (IMethodBodyNode methodBody in methodBodies) { - ObjectNode objectNode = methodBody as ObjectNode; - ObjectNode.ObjectData body = objectNode.GetData(_nodeFactory); + if (methodBody is ObjectNode objectNode) + { + ObjectNode.ObjectData body = objectNode.GetData(_nodeFactory); - writer.WriteULEB128((ulong)body.Data.Length); - writer.EmitData(body.Data); + writer.WriteULEB128((ulong)body.Data.Length); + writer.EmitData(body.Data); + } + else + { + throw new InvalidOperationException($"Expected method body node to be an ObjectNode, but got {methodBody.GetType()}"); + } } return codeSection; @@ -205,15 +210,15 @@ private WasmSection WriteTypeSection(Span functionSignatures, Logg return typeSection; } - private WasmSection WriteFunctionSection(WasmFuncType[] allFunctionSignatures, IDictionary signatureMap, Logger logger) + private WasmSection WriteFunctionSection(IReadOnlyCollection allFunctionSignatures, IDictionary signatureMap, Logger logger) { WasmSection functionSection = new WasmSection(WasmSectionType.Function, new SectionData(), "function"); SectionWriter writer = functionSection.Writer; // Write the number of functions - writer.WriteULEB128((ulong)allFunctionSignatures.Length); - for (int i = 0; i < allFunctionSignatures.Length; i++) + writer.WriteULEB128((ulong)allFunctionSignatures.Count); + for (int i = 0; i < allFunctionSignatures.Count; i++) { - var signature = allFunctionSignatures[i]; + var signature = allFunctionSignatures.ElementAt(i); writer.WriteULEB128((ulong)signatureMap[signature]); } return functionSection; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 41a9e27b368309..7b1bd79fcf839b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -371,7 +371,8 @@ private CompilationResult CompileMethodInternal(IMethodNode methodCodeNodeNeedin uint codeSize; TargetArchitecture architecture = _compilation.TypeSystemContext.Target.Architecture; - var result = architecture switch { + var result = architecture switch + { // We currently do not have WASM codegen support, but for testing, we will return a stub TargetArchitecture.Wasm32 => CompileWasmStub(out exception, ref methodInfo, out codeSize), _ => JitCompileMethod(out exception, From e7feb17041df4c38492b71ce0c6a3c02d00632d4 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Wed, 3 Dec 2025 08:41:38 -0800 Subject: [PATCH 18/23] crossgen2: wasm object writer: address review feedback --- .../Compiler/ObjectWriter/WasmNative.cs | 38 ++++++++++-------- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 40 +++++-------------- .../tools/Common/JitInterface/CorInfoImpl.cs | 10 ++--- .../CodeGen/ReadyToRunObjectWriter.cs | 2 +- .../ILCompiler.ReadyToRun.csproj | 2 - .../aot/crossgen2/Crossgen2RootCommand.cs | 2 +- 6 files changed, 40 insertions(+), 54 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs index cefd7507b9aab1..4f4c360efdefba 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Linq; +using System.Collections.Generic; namespace ILCompiler.ObjectWriter { @@ -25,7 +26,7 @@ public enum WasmSectionType Tag = 13, } - public static class DummyValues + public static class PlaceholderValues { // Wasm function signature for (func (params i32) (result i32)) public static WasmFuncType CreateWasmFunc_i32_i32() @@ -37,7 +38,12 @@ public static WasmFuncType CreateWasmFunc_i32_i32() } } - public enum WasmValueType + // For now, we only encode Wasm numeric value types. + // These are encoded as a single byte. However, + // not all value types can be encoded this way. + // For example, reference types (see https://webassembly.github.io/spec/core/binary/types.html#reference-types) + // require a more complex encoding. + public enum WasmValueType : byte { I32 = 0x7F, I64 = 0x7E, @@ -60,17 +66,22 @@ public static string ToTypeString(this WasmValueType valueType) } } - public struct WasmResultType : IEquatable + public readonly struct WasmResultType : IEquatable { private readonly WasmValueType[] _types; - public readonly Span Types => _types; + public ReadOnlySpan Types => _types; + /// + /// Initializes a new instance of the WasmResultType class with the specified value types. + /// + /// An array of WasmValueType elements representing the types included in the result. If null, an empty array is + /// used. public WasmResultType(WasmValueType[] types) { - _types = types; + _types = types ?? Array.Empty(); } - public bool Equals(WasmResultType other) => Enumerable.SequenceEqual(_types, other._types); + public bool Equals(WasmResultType other) => Types.SequenceEqual(other.Types); public override bool Equals(object obj) { return obj is WasmResultType other && Equals(other); @@ -98,11 +109,11 @@ public int EncodeSize() public int Encode(Span buffer) { - DwarfHelper.WriteULEB128(buffer, (ulong)_types.Length); - uint sizeLength = DwarfHelper.SizeOfULEB128((ulong)_types.Length); + int sizeLength = DwarfHelper.WriteULEB128(buffer, (ulong)_types.Length); + var rest = buffer.Slice(sizeLength); for (int i = 0; i < _types.Length; i++) { - buffer[(int)sizeLength + i] = (byte)_types[i]; + rest[i] = (byte)_types[i]; } return (int)(sizeLength + (uint)_types.Length); } @@ -112,12 +123,7 @@ public static class WasmResultTypeExtensions { public static string ToTypeListString(this WasmResultType result) { - var types = result.Types.ToArray(); - - if (types == null || types.Length == 0) - return string.Empty; - - return string.Join(" ", types.Select(t => WasmValueTypeExtensions.ToTypeString(t))); + return string.Join(" ", result.Types.ToArray().Select(t => WasmValueTypeExtensions.ToTypeString(t))); } } @@ -134,7 +140,7 @@ public WasmFuncType(WasmResultType paramTypes, WasmResultType returnTypes) public readonly byte[] Encode() { - int totalSize = 1+_params.EncodeSize() + _returns.EncodeSize(); + int totalSize = 1 + _params.EncodeSize() + _returns.EncodeSize(); byte[] buffer = new byte[totalSize]; buffer[0] = 0x60; // function type indicator diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index df6785667b33d5..0909988b391c68 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -18,7 +18,7 @@ public class WasmAbiContext { public WasmFuncType GetSignature(MethodDesc method) { - return DummyValues.CreateWasmFunc_i32_i32(); + return PlaceholderValues.CreateWasmFunc_i32_i32(); } } @@ -31,7 +31,7 @@ internal class WasmSection private SectionData _data; - public Span Header + public byte[] Header { get { @@ -41,9 +41,9 @@ public Span Header ulong sectionSize = (ulong)_data.Length; var encodeLength = DwarfHelper.SizeOfULEB128(sectionSize); - Span header = new byte[1+encodeLength]; + byte[] header = new byte[1+encodeLength]; header[0] = (byte)Type; - DwarfHelper.WriteULEB128(header.Slice(1), sectionSize); + DwarfHelper.WriteULEB128(header.AsSpan(1), sectionSize); return header; } @@ -104,11 +104,6 @@ public override void EmitObject(Stream outputFileStream, IReadOnlyCollection methodBodies = new(); foreach (DependencyNode node in nodes) { - if (node is not ObjectNode) - { - continue; - } - if (node is IMethodBodyNode methodNode) { methodSignatures.Add(_wasmAbiContext.GetSignature(methodNode.Method)); @@ -117,21 +112,8 @@ public override void EmitObject(Stream outputFileStream, IReadOnlyCollection signatureMap = new(); - int signatureIndex = 0; - for (int i = 0; i < methodSignatures.Count; i++) - { - if (!signatureMap.ContainsKey(methodSignatures[i])) - { - signatureMap[methodSignatures[i]] = signatureIndex++; - } - } - - WasmFuncType[] uniqueSignatures = new WasmFuncType[signatureMap.Count]; - foreach (var kvp in signatureMap) - { - uniqueSignatures[kvp.Value] = kvp.Key; - } + var uniqueSignatures = methodSignatures.ToArray().Distinct(); + var signatureMap = uniqueSignatures.Select((sig, i) => (sig, i)).ToDictionary(); EmitWasmHeader(outputFileStream); EmitSection(() => WriteTypeSection(uniqueSignatures, logger), outputFileStream, logger); @@ -140,7 +122,7 @@ public override void EmitObject(Stream outputFileStream, IReadOnlyCollection WriteCodeSection(methodBodies.ToArray(), logger), outputFileStream, logger); } - private WasmSection WriteExportSection(IReadOnlyCollection methodNodes, IReadOnlyCollection methodSignatures, + private WasmSection WriteExportSection(IReadOnlyList methodNodes, IReadOnlyList methodSignatures, Dictionary signatureMap, Logger logger) { WasmSection exportSection = new WasmSection(WasmSectionType.Export, new SectionData(), "export"); @@ -149,8 +131,8 @@ private WasmSection WriteExportSection(IReadOnlyCollection meth writer.WriteULEB128((ulong)methodNodes.Count); for (int i = 0; i < methodNodes.Count; i++) { - var methodNode = methodNodes.ElementAt(i); - var methodSignature = methodSignatures.ElementAt(i); + var methodNode = methodNodes[i]; + var methodSignature = methodSignatures[i]; string exportName = methodNode.GetMangledName(_nodeFactory.NameMangler); var length = Encoding.UTF8.GetByteCount(exportName); @@ -192,13 +174,13 @@ private WasmSection WriteCodeSection(IReadOnlyCollection method return codeSection; } - private WasmSection WriteTypeSection(Span functionSignatures, Logger logger) + private WasmSection WriteTypeSection(IEnumerable functionSignatures, Logger logger) { WasmSection typeSection = new WasmSection(WasmSectionType.Type, new SectionData(), "type"); SectionWriter writer = typeSection.Writer; // Write the number of types - writer.WriteULEB128((ulong)functionSignatures.Length); + writer.WriteULEB128((ulong)functionSignatures.Count()); foreach (WasmFuncType signature in functionSignatures) { if (logger.IsVerbose) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 7b1bd79fcf839b..8c778991c87e02 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -317,16 +317,16 @@ IntPtr LocalObjectToHandle(object input) return null; } - private CorJitResult CompileWasmStub(out IntPtr exception, ref CORINFO_METHOD_INFO methodInfo, out uint codeSize) { - byte[] stub = new byte[] { + byte[] stub = + [ 0x00, // local variable count 0x41, // i32.const 0x0, // uleb128 0 - 0x0f, // return - 0x0b, // end - }; + 0x0F, // return + 0x0B, // end + ]; AllocMemArgs args = new AllocMemArgs { hotCodeSize = (uint)stub.Length, diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index 0ad4af96f29c37..cabd4f76116d73 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -300,7 +300,7 @@ private MachObjectWriter CreateMachObjectWriter() private WasmObjectWriter CreateWasmObjectWriter() { - // empty for now as a placeholder, this will be needed when we have Wasm specific ABI handling + // TODO: empty for now as a placeholder, this will be needed when we have Wasm specific ABI handling var abiContext = new WasmAbiContext(); return new WasmObjectWriter(_nodeFactory, ObjectWritingOptions.None, abiContext, _outputInfoBuilder); } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 61f1c9a6bb39e6..e45a14e9331f59 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -369,6 +369,4 @@ - - diff --git a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs index 9a4761ea16c522..b63e33f17ac23b 100644 --- a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs +++ b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs @@ -297,7 +297,7 @@ public static void PrintExtendedHelp(ParseResult _) Console.WriteLine(); string[] ValidArchitectures = ["arm", "armel", "arm64", "x86", "x64", "riscv64", "loongarch64", "wasm"]; - string[] ValidOS = ["windows", "linux", "osx", "ios", "iossimulator", "maccatalyst", "wasi"]; + string[] ValidOS = ["windows", "linux", "osx", "ios", "iossimulator", "maccatalyst", "browser"]; Console.WriteLine(String.Format(SR.SwitchWithDefaultHelp, "--targetos", String.Join("', '", ValidOS), Helpers.GetTargetOS(null).ToString().ToLowerInvariant())); Console.WriteLine(); From bf32f248ef4f13f1088db1d87a488a4200334362 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Wed, 3 Dec 2025 09:43:32 -0800 Subject: [PATCH 19/23] crossgen2: wasm object writer: nullable annotations for WasmResultType --- .../tools/Common/Compiler/ObjectWriter/WasmNative.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs index 4f4c360efdefba..c3eed71eeb9361 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -66,6 +66,7 @@ public static string ToTypeString(this WasmValueType valueType) } } + #nullable enable public readonly struct WasmResultType : IEquatable { private readonly WasmValueType[] _types; @@ -76,13 +77,13 @@ public static string ToTypeString(this WasmValueType valueType) /// /// An array of WasmValueType elements representing the types included in the result. If null, an empty array is /// used. - public WasmResultType(WasmValueType[] types) + public WasmResultType(WasmValueType[]? types) { _types = types ?? Array.Empty(); } public bool Equals(WasmResultType other) => Types.SequenceEqual(other.Types); - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is WasmResultType other && Equals(other); } @@ -157,7 +158,7 @@ public bool Equals(WasmFuncType other) return _params.Equals(other._params) && _returns.Equals(other._returns); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is WasmFuncType other && Equals(other); } From 30e2feb59a4ee503c65cc90ea413e1619ccb3bfc Mon Sep 17 00:00:00 2001 From: adamperlin Date: Thu, 4 Dec 2025 14:54:46 -0800 Subject: [PATCH 20/23] Address additional review feedback --- .../Compiler/ObjectWriter/WasmNative.cs | 23 +- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 205 +++++++++--------- .../CodeGen/ReadyToRunObjectWriter.cs | 4 +- 3 files changed, 119 insertions(+), 113 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs index c3eed71eeb9361..aa4c4738ae26aa 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs @@ -111,7 +111,7 @@ public int EncodeSize() public int Encode(Span buffer) { int sizeLength = DwarfHelper.WriteULEB128(buffer, (ulong)_types.Length); - var rest = buffer.Slice(sizeLength); + Span rest = buffer.Slice(sizeLength); for (int i = 0; i < _types.Length; i++) { rest[i] = (byte)_types[i]; @@ -124,7 +124,7 @@ public static class WasmResultTypeExtensions { public static string ToTypeListString(this WasmResultType result) { - return string.Join(" ", result.Types.ToArray().Select(t => WasmValueTypeExtensions.ToTypeString(t))); + return string.Join(" ", result.Types.ToArray().Select(t => t.ToTypeString())); } } @@ -139,18 +139,21 @@ public WasmFuncType(WasmResultType paramTypes, WasmResultType returnTypes) _returns = returnTypes; } - public readonly byte[] Encode() + public readonly int EncodeSize() { - int totalSize = 1 + _params.EncodeSize() + _returns.EncodeSize(); - byte[] buffer = new byte[totalSize]; - buffer[0] = 0x60; // function type indicator + return 1 + _params.EncodeSize() + _returns.EncodeSize(); + } - var span = buffer.AsSpan(); + public readonly int Encode(Span buffer) + { + int totalSize = EncodeSize(); + buffer[0] = 0x60; // function type indicator - int paramSize = _params.Encode(span.Slice(1)); - int returnSize = _returns.Encode(span.Slice(1+paramSize)); + int paramSize = _params.Encode(buffer.Slice(1)); + int returnSize = _returns.Encode(buffer.Slice(1+paramSize)); Debug.Assert(totalSize == 1 + paramSize + returnSize); - return buffer; + + return totalSize; } public bool Equals(WasmFuncType other) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 0909988b391c68..c82b4a08c02aa3 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -2,128 +2,77 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Buffers; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using ILCompiler.DependencyAnalysis; +using ILCompiler.DependencyAnalysis.ReadyToRun; using ILCompiler.DependencyAnalysisFramework; using Internal.TypeSystem; +using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData; + namespace ILCompiler.ObjectWriter { - // This is a placeholder for now. It will need to be filled in with ABI-specific signatures - // for any method we want to emit into the Wasm module. - public class WasmAbiContext - { - public WasmFuncType GetSignature(MethodDesc method) - { - return PlaceholderValues.CreateWasmFunc_i32_i32(); - } - } - - internal class WasmSection - { - public WasmSectionType Type { get; } - public string Name { get; } - public SectionData Data => _data; - private SectionWriter? _writer; - - private SectionData _data; - - public byte[] Header - { - get - { - // Section header consists of: - // 1 byte: section type - // ULEB128: size of section - ulong sectionSize = (ulong)_data.Length; - var encodeLength = DwarfHelper.SizeOfULEB128(sectionSize); - - byte[] header = new byte[1+encodeLength]; - header[0] = (byte)Type; - DwarfHelper.WriteULEB128(header.AsSpan(1), sectionSize); - - return header; - } - } - - public SectionWriter Writer - { - get - { - if (_writer == null) - { - _writer = new SectionWriter(null, 0, _data); - } - return _writer.Value; - } - } - - public WasmSection(WasmSectionType type, SectionData data, string name) - { - Type = type; - Name = name; - _data = data; - } - } - /// /// Wasm object file format writer. /// internal sealed class WasmObjectWriter : ObjectWriter { - // must be stored in little-endian order - private const uint WasmMagicNumber = 0x6d736100; - - // must be stored in little-endian order - private const uint WasmVersion = 0x1; - - private WasmAbiContext _wasmAbiContext; - - public WasmObjectWriter(NodeFactory factory, ObjectWritingOptions options, WasmAbiContext ctx, OutputInfoBuilder outputInfoBuilder) + public WasmObjectWriter(NodeFactory factory, ObjectWritingOptions options, OutputInfoBuilder outputInfoBuilder) : base(factory, options, outputInfoBuilder) { - _wasmAbiContext = ctx; } private void EmitWasmHeader(Stream outputFileStream) { SectionData data = new(); SectionWriter headerWriter = new(this, 0, data); - headerWriter.WriteLittleEndian(WasmMagicNumber); - headerWriter.WriteLittleEndian(WasmVersion); + headerWriter.Write("\0asm"u8); + headerWriter.Write([0x1, 0x0, 0x0, 0x0]); data.GetReadStream().CopyTo(outputFileStream); } + // TODO: for now, we are fully overriding EmitObject. As we support more features, we should + // see if we can re-use the base, or refactor the base method to allow for code sharing. public override void EmitObject(Stream outputFileStream, IReadOnlyCollection nodes, IObjectDumper dumper, Logger logger) { ArrayBuilder methodSignatures = new(); - ArrayBuilder methodBodies = new(); + ArrayBuilder methodNames = new(); + ArrayBuilder methodBodies = new(); foreach (DependencyNode node in nodes) { + if (node is not ObjectNode) + { + continue; + } + if (node is IMethodBodyNode methodNode) { - methodSignatures.Add(_wasmAbiContext.GetSignature(methodNode.Method)); - methodBodies.Add(methodNode); + ObjectNode methodObject = (ObjectNode)node; + methodSignatures.Add(WasmAbiContext.GetSignature(methodNode.Method)); + methodNames.Add(methodNode.GetMangledName(_nodeFactory.NameMangler)); + methodBodies.Add(methodObject.GetData(_nodeFactory)); // TODO: record relocations and attached data } } - var uniqueSignatures = methodSignatures.ToArray().Distinct(); - var signatureMap = uniqueSignatures.Select((sig, i) => (sig, i)).ToDictionary(); + IEnumerable uniqueSignatures = methodSignatures.ToArray().Distinct(); + Dictionary signatureMap = uniqueSignatures.Select((sig, i) => (sig, i)).ToDictionary(); EmitWasmHeader(outputFileStream); EmitSection(() => WriteTypeSection(uniqueSignatures, logger), outputFileStream, logger); EmitSection(() => WriteFunctionSection(methodSignatures.ToArray(), signatureMap, logger), outputFileStream, logger); - EmitSection(() => WriteExportSection(methodBodies.ToArray(), methodSignatures.ToArray(), signatureMap, logger), outputFileStream, logger); - EmitSection(() => WriteCodeSection(methodBodies.ToArray(), logger), outputFileStream, logger); + EmitSection(() => WriteExportSection(methodBodies, methodSignatures, methodNames, signatureMap, logger), outputFileStream, logger); + EmitSection(() => WriteCodeSection(methodBodies, logger), outputFileStream, logger); } - private WasmSection WriteExportSection(IReadOnlyList methodNodes, IReadOnlyList methodSignatures, - Dictionary signatureMap, Logger logger) + private WasmSection WriteExportSection(ArrayBuilder methodNodes, ArrayBuilder methodSignatures, + ArrayBuilder methodNames, Dictionary signatureMap, Logger logger) { WasmSection exportSection = new WasmSection(WasmSectionType.Export, new SectionData(), "export"); SectionWriter writer = exportSection.Writer; @@ -131,11 +80,11 @@ private WasmSection WriteExportSection(IReadOnlyList methodNode writer.WriteULEB128((ulong)methodNodes.Count); for (int i = 0; i < methodNodes.Count; i++) { - var methodNode = methodNodes[i]; - var methodSignature = methodSignatures[i]; - string exportName = methodNode.GetMangledName(_nodeFactory.NameMangler); + ObjectData methodNode = methodNodes[i]; + WasmFuncType methodSignature = methodSignatures[i]; + string exportName = methodNames[i]; - var length = Encoding.UTF8.GetByteCount(exportName); + int length = Encoding.UTF8.GetByteCount(exportName); writer.WriteULEB128((ulong)length); writer.WriteUtf8StringNoNull(exportName); writer.WriteByte(0x00); // export kind: function @@ -149,26 +98,18 @@ private WasmSection WriteExportSection(IReadOnlyList methodNode return exportSection; } - private WasmSection WriteCodeSection(IReadOnlyCollection methodBodies, Logger logger) + private WasmSection WriteCodeSection(ArrayBuilder methodBodies, Logger logger) { WasmSection codeSection = new WasmSection(WasmSectionType.Code, new SectionData(), "code"); - SectionWriter writer = codeSection.Writer; + // Write the number of functions writer.WriteULEB128((ulong)methodBodies.Count); - foreach (IMethodBodyNode methodBody in methodBodies) + for ( int i = 0; i < methodBodies.Count; i++) { - if (methodBody is ObjectNode objectNode) - { - ObjectNode.ObjectData body = objectNode.GetData(_nodeFactory); - - writer.WriteULEB128((ulong)body.Data.Length); - writer.EmitData(body.Data); - } - else - { - throw new InvalidOperationException($"Expected method body node to be an ObjectNode, but got {methodBody.GetType()}"); - } + ObjectData methodBody = methodBodies[i]; + writer.WriteULEB128((ulong)methodBody.Data.Length); + writer.EmitData(methodBody.Data); } return codeSection; @@ -176,19 +117,26 @@ private WasmSection WriteCodeSection(IReadOnlyCollection method private WasmSection WriteTypeSection(IEnumerable functionSignatures, Logger logger) { - WasmSection typeSection = new WasmSection(WasmSectionType.Type, new SectionData(), "type"); + SectionData sectionData = new(); + WasmSection typeSection = new WasmSection(WasmSectionType.Type, sectionData, "type"); SectionWriter writer = typeSection.Writer; // Write the number of types writer.WriteULEB128((ulong)functionSignatures.Count()); + + IBufferWriter buffer = sectionData.BufferWriter; foreach (WasmFuncType signature in functionSignatures) { if (logger.IsVerbose) { logger.LogMessage($"Emitting function signature: {signature}"); } - writer.EmitData(signature.Encode()); + + int signatureSize = signature.EncodeSize(); + signature.Encode(buffer.GetSpan(signatureSize)); + buffer.Advance(signatureSize); } + return typeSection; } @@ -200,7 +148,7 @@ private WasmSection WriteFunctionSection(IReadOnlyCollection allFu writer.WriteULEB128((ulong)allFunctionSignatures.Count); for (int i = 0; i < allFunctionSignatures.Count; i++) { - var signature = allFunctionSignatures.ElementAt(i); + WasmFuncType signature = allFunctionSignatures.ElementAt(i); writer.WriteULEB128((ulong)signatureMap[signature]); } return functionSection; @@ -208,7 +156,7 @@ private WasmSection WriteFunctionSection(IReadOnlyCollection allFu private void EmitSection(Func writeFunc, Stream outputFileStream, Logger logger) { - var section = writeFunc(); + WasmSection section = writeFunc(); outputFileStream.Write(section.Header); if (logger.IsVerbose) @@ -230,4 +178,61 @@ private void EmitSection(Func writeFunc, Stream outputFileStream, L private protected override void EmitRelocations(int sectionIndex, List relocationList) => throw new NotImplementedException(); private protected override void EmitSymbolTable(IDictionary definedSymbols, SortedSet undefinedSymbols) => throw new NotImplementedException(); } + + // TODO: This is a placeholder implementation. The real implementation will derive the Wasm function signature + // from the MethodDesc's signature and type system information. + public static class WasmAbiContext + { + public static WasmFuncType GetSignature(MethodDesc method) + { + return PlaceholderValues.CreateWasmFunc_i32_i32(); + } + } + + internal class WasmSection + { + public WasmSectionType Type { get; } + public string Name { get; } + public SectionData Data => _data; + private SectionWriter? _writer; + + private SectionData _data; + + public byte[] Header + { + get + { + // Section header consists of: + // 1 byte: section type + // ULEB128: size of section + ulong sectionSize = (ulong)_data.Length; + uint encodeLength = DwarfHelper.SizeOfULEB128(sectionSize); + + byte[] header = new byte[1+encodeLength]; + header[0] = (byte)Type; + DwarfHelper.WriteULEB128(header.AsSpan(1), sectionSize); + + return header; + } + } + + public SectionWriter Writer + { + get + { + if (_writer == null) + { + _writer = new SectionWriter(null, 0, _data); + } + return _writer.Value; + } + } + + public WasmSection(WasmSectionType type, SectionData data, string name) + { + Type = type; + Name = name; + _data = data; + } + } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index cabd4f76116d73..d0cd1542163e5c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -300,9 +300,7 @@ private MachObjectWriter CreateMachObjectWriter() private WasmObjectWriter CreateWasmObjectWriter() { - // TODO: empty for now as a placeholder, this will be needed when we have Wasm specific ABI handling - var abiContext = new WasmAbiContext(); - return new WasmObjectWriter(_nodeFactory, ObjectWritingOptions.None, abiContext, _outputInfoBuilder); + return new WasmObjectWriter(_nodeFactory, ObjectWritingOptions.None, _outputInfoBuilder); } public static void EmitObject( From ce53862098e02a07444b4a555b5623b4b1fd1ae7 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Thu, 4 Dec 2025 16:31:45 -0800 Subject: [PATCH 21/23] Address additional review feedback --- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index c82b4a08c02aa3..0161d43900f5b1 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -29,12 +29,8 @@ public WasmObjectWriter(NodeFactory factory, ObjectWritingOptions options, Outpu private void EmitWasmHeader(Stream outputFileStream) { - SectionData data = new(); - SectionWriter headerWriter = new(this, 0, data); - headerWriter.Write("\0asm"u8); - headerWriter.Write([0x1, 0x0, 0x0, 0x0]); - - data.GetReadStream().CopyTo(outputFileStream); + outputFileStream.Write("\0asm"u8); + outputFileStream.Write([0x1, 0x0, 0x0, 0x0]); } // TODO: for now, we are fully overriding EmitObject. As we support more features, we should @@ -64,9 +60,11 @@ public override void EmitObject(Stream outputFileStream, IReadOnlyCollection uniqueSignatures = methodSignatures.ToArray().Distinct(); Dictionary signatureMap = uniqueSignatures.Select((sig, i) => (sig, i)).ToDictionary(); + // TODO: The EmitSection calls here can be moved to this class' `EmitObjectFile` implementation + // when we can share more code with the base class. EmitWasmHeader(outputFileStream); EmitSection(() => WriteTypeSection(uniqueSignatures, logger), outputFileStream, logger); - EmitSection(() => WriteFunctionSection(methodSignatures.ToArray(), signatureMap, logger), outputFileStream, logger); + EmitSection(() => WriteFunctionSection(methodSignatures, signatureMap, logger), outputFileStream, logger); EmitSection(() => WriteExportSection(methodBodies, methodSignatures, methodNames, signatureMap, logger), outputFileStream, logger); EmitSection(() => WriteCodeSection(methodBodies, logger), outputFileStream, logger); } @@ -105,7 +103,7 @@ private WasmSection WriteCodeSection(ArrayBuilder methodBodies, Logg // Write the number of functions writer.WriteULEB128((ulong)methodBodies.Count); - for ( int i = 0; i < methodBodies.Count; i++) + for (int i = 0; i < methodBodies.Count; i++) { ObjectData methodBody = methodBodies[i]; writer.WriteULEB128((ulong)methodBody.Data.Length); @@ -140,7 +138,7 @@ private WasmSection WriteTypeSection(IEnumerable functionSignature return typeSection; } - private WasmSection WriteFunctionSection(IReadOnlyCollection allFunctionSignatures, IDictionary signatureMap, Logger logger) + private WasmSection WriteFunctionSection(ArrayBuilder allFunctionSignatures, Dictionary signatureMap, Logger logger) { WasmSection functionSection = new WasmSection(WasmSectionType.Function, new SectionData(), "function"); SectionWriter writer = functionSection.Writer; @@ -148,7 +146,7 @@ private WasmSection WriteFunctionSection(IReadOnlyCollection allFu writer.WriteULEB128((ulong)allFunctionSignatures.Count); for (int i = 0; i < allFunctionSignatures.Count; i++) { - WasmFuncType signature = allFunctionSignatures.ElementAt(i); + WasmFuncType signature = allFunctionSignatures[i]; writer.WriteULEB128((ulong)signatureMap[signature]); } return functionSection; @@ -157,11 +155,13 @@ private WasmSection WriteFunctionSection(IReadOnlyCollection allFu private void EmitSection(Func writeFunc, Stream outputFileStream, Logger logger) { WasmSection section = writeFunc(); + Span headerBuffer = stackalloc byte[section.HeaderSize]; - outputFileStream.Write(section.Header); + section.EncodeHeader(headerBuffer); + outputFileStream.Write(headerBuffer); if (logger.IsVerbose) { - logger.LogMessage($"Wrote section header of size {section.Header.Length} bytes."); + logger.LogMessage($"Wrote section header of size {headerBuffer.Length} bytes."); } section.Data.GetReadStream().CopyTo(outputFileStream); @@ -198,22 +198,28 @@ internal class WasmSection private SectionData _data; - public byte[] Header + public int HeaderSize { get { - // Section header consists of: - // 1 byte: section type - // ULEB128: size of section ulong sectionSize = (ulong)_data.Length; - uint encodeLength = DwarfHelper.SizeOfULEB128(sectionSize); + uint sizeEncodeLength = DwarfHelper.SizeOfULEB128(sectionSize); + return 1 + (int)sizeEncodeLength; + } + } - byte[] header = new byte[1+encodeLength]; - header[0] = (byte)Type; - DwarfHelper.WriteULEB128(header.AsSpan(1), sectionSize); + public int EncodeHeader(Span headerBuffer) + { + ulong sectionSize = (ulong)_data.Length; + uint encodeLength = DwarfHelper.SizeOfULEB128(sectionSize); - return header; - } + // Section header consists of: + // 1 byte: section type + // ULEB128: size of section + headerBuffer[0] = (byte)Type; + DwarfHelper.WriteULEB128(headerBuffer.Slice(1), sectionSize); + + return 1 + (int)encodeLength; } public SectionWriter Writer From 73ab2fa566e73907a8e33bc64deb2e7edf6ebf0b Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 8 Dec 2025 09:59:13 -0800 Subject: [PATCH 22/23] remove unnecessary access change to GetOrCreateSection --- src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs index 1935547e223ac7..8a974d93912476 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs @@ -78,7 +78,7 @@ private protected ObjectWriter(NodeFactory factory, ObjectWritingOptions options /// For associated sections, such as exception or debugging information, the /// will be different. /// - internal virtual SectionWriter GetOrCreateSection(ObjectNodeSection section, string comdatName = null, string symbolName = null) + private protected SectionWriter GetOrCreateSection(ObjectNodeSection section, string comdatName = null, string symbolName = null) { int sectionIndex; SectionData sectionData; From 0b96549b54a0934eb87c626f553a4e651e89198f Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 8 Dec 2025 12:12:58 -0800 Subject: [PATCH 23/23] Update signatures of inherited methods in WasmObjectWriter --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 0161d43900f5b1..d02cc5d4c30dca 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -11,6 +11,7 @@ using ILCompiler.DependencyAnalysis; using ILCompiler.DependencyAnalysis.ReadyToRun; using ILCompiler.DependencyAnalysisFramework; +using Internal.Text; using Internal.TypeSystem; using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData; @@ -173,10 +174,10 @@ private void EmitSection(Func writeFunc, Stream outputFileStream, L protected internal override void UpdateSectionAlignment(int sectionIndex, int alignment) => throw new NotImplementedException(); private WasmSection CreateSection(WasmSectionType sectionType, string symbolName, int sectionIndex) => throw new NotImplementedException(); - private protected override void CreateSection(ObjectNodeSection section, string comdatName, string symbolName, int sectionIndex, Stream sectionStream) => throw new NotImplementedException(); + private protected override void CreateSection(ObjectNodeSection section, Utf8String comdatName, Utf8String symbolName, int sectionIndex, Stream sectionStream) => throw new NotImplementedException(); private protected override void EmitObjectFile(Stream outputFileStream) => throw new NotImplementedException(); private protected override void EmitRelocations(int sectionIndex, List relocationList) => throw new NotImplementedException(); - private protected override void EmitSymbolTable(IDictionary definedSymbols, SortedSet undefinedSymbols) => throw new NotImplementedException(); + private protected override void EmitSymbolTable(IDictionary definedSymbols, SortedSet undefinedSymbols) => throw new NotImplementedException(); } // TODO: This is a placeholder implementation. The real implementation will derive the Wasm function signature