| File: parent\parent\Common\Compiler\ObjectWriter\Wasm\IWasmDataSegment.cs | Web Access |
| Project: ILCompiler.ReadyToRun.csproj (ILCompiler.ReadyToRun) |
// 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.Diagnostics; using System.IO; using ILCompiler.DependencyAnalysis; using ILCompiler.ObjectWriter.WasmInstructions; namespace ILCompiler.ObjectWriter { internal enum WasmDataSegmentType : byte { // (data list(byte) (active offset-expr)) // Active segments are loaded by the wasm runtime into linear memory at the specified offset. Active = 0, // (data list(byte) passive) // Passive segments are not loaded into linear memory by the wasm runtime, but can be loaded by the program at runtime using the `memory.init` instruction. Passive = 1, // (data list(byte) (active memidx offset-expr)) // ActiveMemorySpecified sections are loaded by the wasm runtime into linear memory at the specified offset, but also specify a memory index to load into. // We do not create or read any segments of this type. // ActiveMemorySpecified = 2 } /// <summary> /// Interface for a data segment in a WASM data section. /// These members help ensure the Data section can properly align the segment content in the WASM module. /// </summary> internal interface IWasmDataSegment : IWasmEmittable { /// <summary> /// The size of the header of the segment. Alignment of the segments expects this to be constant for a given /// segment, so it should not depend on the content size. /// </summary> int HeaderSize { get; } /// <summary> /// The size of the content of the segment. /// </summary> int ContentSize { get; } /// <summary> /// The required alignment of the segment content in the WASM module. /// </summary> int FileAlignment { get; } WasmDataSegmentType SegmentType => WasmDataSegmentType.Passive; /// <summary> /// Sets the number of padding bytes to emit after the segment content. This is used to ensure that the next /// segment is aligned properly. /// </summary> void SetTrailingPadding(int trailingBytesCount); /// <summary> /// Gets the offset of the segment in linear memory when loaded. /// For passive segments, returns <paramref name="offsetInSegment"/> /// </summary> int GetMemoryAddressOfOffset(int offsetInSegment); } internal interface IWasmActiveDataSegment : IWasmDataSegment { WasmDataSegmentType IWasmDataSegment.SegmentType => WasmDataSegmentType.Active; /// <summary> /// The required alignment of the segment content in linear memory when loaded. /// </summary> int MemoryAlignment { get; } /// <summary> /// For active segments, sets the offset of the segment in linear memory. For passive segments, this is a no-op. /// </summary> void SetMemoryOffset(int offset); } internal static class WasmDataSegmentEncoding { public static int GetHeaderSize( WasmDataSegmentType type, WasmInstructionGroup initExpr) { return type switch { WasmDataSegmentType.Active => (int)DwarfHelper.SizeOfULEB128((ulong)type) + initExpr.EncodeSize() + Relocation.WASM_PADDED_RELOC_SIZE_32, WasmDataSegmentType.Passive => (int)DwarfHelper.SizeOfULEB128((ulong)type) + Relocation.WASM_PADDED_RELOC_SIZE_32, _ => throw new NotSupportedException(), }; } public static int EncodeHeader( Span<byte> headerBuffer, WasmDataSegmentType type, WasmInstructionGroup initExpr, int contentSize) { int length = DwarfHelper.WriteULEB128(headerBuffer, (ulong)type); Debug.Assert(length == 1); if (type == WasmDataSegmentType.Active) { length += initExpr.Encode(headerBuffer.Slice(length)); } Debug.Assert(headerBuffer.Slice(length).Length == Relocation.WASM_PADDED_RELOC_SIZE_32); // File alignment of data segments requires that the header doesn't change size based on the content size, // so we use a padded ULEB128 here. DwarfHelper.WritePaddedULEB128(headerBuffer.Slice(length), (ulong)contentSize); return headerBuffer.Length; } public static void EmitPadding(Stream outputFileStream, int padding) { if (padding == 0) return; Span<byte> paddingBytes = stackalloc byte[Math.Min(padding, 256)]; paddingBytes.Clear(); while (padding > 0) { int paddingSize = Math.Min(padding, paddingBytes.Length); outputFileStream.Write(paddingBytes.Slice(0, paddingSize)); padding -= paddingSize; } } } }