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

Code before:

                var 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(IReadOnlyCollection<IMethodBodyNode> 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)
            {
                ObjectNode objectNode = methodBody as ObjectNode;
                ObjectNode.ObjectData body = objectNode.GetData(_nodeFactory);

                writer.WriteULEB128((ulong)body.Data.Length);
                writer.EmitData(body.Data);
            }

            return codeSection;
        }

        private WasmSection WriteTypeSection(Span<WasmFuncType> 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);
            foreach (WasmFuncType signature in functionSignatures)
            {
                if (logger.IsVerbose)
                {
                    logger.LogMessage($"Emitting function signature: {signature}");
                }
                writer.EmitData(signature.Encode());
            }
            return typeSection;
        }

Review comment (bug):
`as T` followed by `.GetData` without a null check is probably best written as `(ObjectNode)methodBody` instead so we get a cast failure instead of a null reference

Code after:
        private void EmitSection(Func<WasmSection> writeFunc, Stream outputFileStream, Logger logger)
        {
            WasmSection section = writeFunc();
            Span<byte> headerBuffer = stackalloc byte[section.HeaderSize];

            section.EncodeHeader(headerBuffer);
            outputFileStream.Write(headerBuffer);
            if (logger.IsVerbose)
            {
                logger.LogMessage($"Wrote section header of size {headerBuffer.Length} bytes.");
            }

            section.Data.GetReadStream().CopyTo(outputFileStream);
            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, 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<SymbolicRelocation> relocationList) => throw new NotImplementedException();
        private protected override void EmitSymbolTable(IDictionary<Utf8String, SymbolDefinition> definedSymbols, SortedSet<Utf8String> 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 int HeaderSize
        {
            get
            {
                ulong sectionSize = (ulong)_data.Length;