Repository: dotnet/runtime
File: src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs (C#)

Code before:
    /// Wasm object file format writer.
    /// </summary>
    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)
            : 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);

            data.GetReadStream().CopyTo(outputFileStream);
        }

        public override void EmitObject(Stream outputFileStream, IReadOnlyCollection<DependencyNode> nodes, IObjectDumper dumper, Logger logger)
        {
            ArrayBuilder<WasmFuncType> methodSignatures = new();
            ArrayBuilder<IMethodBodyNode> methodBodies = new();
            foreach (DependencyNode node in nodes)
            {
                if (node is IMethodBodyNode methodNode)
                {
                    methodSignatures.Add(_wasmAbiContext.GetSignature(methodNode.Method));
                    methodBodies.Add(methodNode);
                    // TODO: record relocations and attached data
                }
            }

            var uniqueSignatures = methodSignatures.ToArray().Distinct();
            var 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);
        }

Review comment (suggestion):
Nit: this could be written with a bit more [succinctly](https://github.com/dotnet/runtimelab/blob/aca244dd24e2e3dba3b45535ec9253e6e7cfbd79/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/WasmObjectWriter.cs#L185-L186).


Code after:
        private WasmSection WriteExportSection(ArrayBuilder<ObjectData> methodNodes, ArrayBuilder<WasmFuncType> methodSignatures,
            ArrayBuilder<string> methodNames, Dictionary<WasmFuncType, int> 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++)
            {
                ObjectData methodNode = methodNodes[i];
                WasmFuncType methodSignature = methodSignatures[i];
                string exportName = methodNames[i];

                int length = Encoding.UTF8.GetByteCount(exportName);
                writer.WriteULEB128((ulong)length);
                writer.WriteUtf8StringNoNull(exportName);
                writer.WriteByte(0x00); // export kind: function
                writer.WriteULEB128((ulong)i);
                if (logger.IsVerbose)
                {
                    logger.LogMessage($"Emitting export: {exportName} for function index {i}");
                }
            }

            return exportSection;
        }

        private WasmSection WriteCodeSection(ArrayBuilder<ObjectData> 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);
            for (int i = 0; i < methodBodies.Count; i++)
            {
                ObjectData methodBody = methodBodies[i];
                writer.WriteULEB128((ulong)methodBody.Data.Length);
                writer.EmitData(methodBody.Data);
            }

            return codeSection;
        }

        private WasmSection WriteTypeSection(IEnumerable<WasmFuncType> functionSignatures, Logger logger)
        {
            SectionData sectionData = new();
            WasmSection typeSection = new WasmSection(WasmSectionType.Type, sectionData, "type");
            SectionWriter writer = typeSection.Writer;

            // Write the number of types