using System; using System.Text; using System.Buffers.Binary; namespace Wasmtime { /// /// Represents a WebAssembly memory. /// public class Memory { /// /// The size, in bytes, of a WebAssembly memory page. /// public const int PageSize = 65536; /// /// Creates a new memory with the given minimum and maximum page counts. /// /// /// public Memory(uint minimum = 1, uint maximum = uint.MaxValue) { if (minimum == 0) { throw new ArgumentException("The minimum cannot be zero..", nameof(minimum)); } if (maximum < minimum) { throw new ArgumentException("The maximum cannot be less than the minimum.", nameof(maximum)); } Minimum = minimum; Maximum = maximum; } /// /// The minimum memory size (in WebAssembly page units). /// public uint Minimum { get; private set; } /// /// The minimum memory size (in WebAssembly page units). /// public uint Maximum { get; private set; } /// /// The span of the memory. /// /// /// The span may become invalid if the memory grows. /// /// This may happen if the memory is explicitly requested to grow or /// grows as a result of WebAssembly execution. /// /// Therefore, the returned Span should not be stored. /// public unsafe Span Span { get { var data = Interop.wasm_memory_data(_handle.DangerousGetHandle()); var size = Convert.ToInt32(Interop.wasm_memory_data_size(_handle.DangerousGetHandle()).ToUInt32()); return new Span(data, size); } } /// /// Reads a UTF-8 string from memory. /// /// The zero-based address to read from. /// The length of bytes to read. /// Returns the string read from memory. public string ReadString(int address, int length) { return Encoding.UTF8.GetString(Span.Slice(address, length)); } /// /// Writes a UTF-8 string at the given address. /// /// The zero-based address to write to. /// The string to write. /// Returns the number of bytes written. public int WriteString(int address, string value) { return Encoding.UTF8.GetBytes(value, Span.Slice(address)); } /// /// Reads a byte from memory. /// /// The zero-based address to read from. /// Returns the byte read from memory. public byte ReadByte(int address) { return Span[address]; } /// /// Writes a byte to memory. /// /// The zero-based address to write to. /// The byte to write. public void WriteByte(int address, byte value) { Span[address] = value; } /// /// Reads a short from memory. /// /// The zero-based address to read from. /// Returns the short read from memory. public short ReadInt16(int address) { return BinaryPrimitives.ReadInt16LittleEndian(Span.Slice(address, 2)); } /// /// Writes a short to memory. /// /// The zero-based address to write to. /// The short to write. public void WriteInt16(int address, short value) { BinaryPrimitives.WriteInt16LittleEndian(Span.Slice(address, 2), value); } /// /// Reads an int from memory. /// /// The zero-based address to read from. /// Returns the int read from memory. public int ReadInt32(int address) { return BinaryPrimitives.ReadInt32LittleEndian(Span.Slice(address, 4)); } /// /// Writes an int to memory. /// /// The zero-based address to write to. /// The int to write. public void WriteInt32(int address, int value) { BinaryPrimitives.WriteInt32LittleEndian(Span.Slice(address, 4), value); } /// /// Reads a long from memory. /// /// The zero-based address to read from. /// Returns the long read from memory. public long ReadInt64(int address) { return BinaryPrimitives.ReadInt64LittleEndian(Span.Slice(address, 8)); } /// /// Writes a long to memory. /// /// The zero-based address to write to. /// The long to write. public void WriteInt64(int address, long value) { BinaryPrimitives.WriteInt64LittleEndian(Span.Slice(address, 8), value); } /// /// Reads an IntPtr from memory. /// /// The zero-based address to read from. /// Returns the IntPtr read from memory. public IntPtr ReadIntPtr(int address) { if (IntPtr.Size == 4) { return (IntPtr)ReadInt32(address); } return (IntPtr)ReadInt64(address); } /// /// Writes an IntPtr to memory. /// /// The zero-based address to write to. /// The IntPtr to write. public void WriteIntPtr(int address, IntPtr value) { if (IntPtr.Size == 4) { WriteInt32(address, value.ToInt32()); } else { WriteInt64(address, value.ToInt64()); } } /// /// Reads a long from memory. /// /// The zero-based address to read from. /// Returns the long read from memory. public float ReadSingle(int address) { unsafe { var i = ReadInt32(address); return *((float*)&i); } } /// /// Writes a single to memory. /// /// The zero-based address to write to. /// The single to write. public void WriteSingle(int address, float value) { unsafe { WriteInt32(address, *(int*)&value); } } /// /// Reads a double from memory. /// /// The zero-based address to read from. /// Returns the double read from memory. public double ReadDouble(int address) { unsafe { var i = ReadInt64(address); return *((double*)&i); } } /// /// Writes a double to memory. /// /// The zero-based address to write to. /// The double to write. public void WriteDouble(int address, double value) { unsafe { WriteInt64(address, *(long*)&value); } } internal Interop.MemoryHandle Handle { get { return _handle; } set { _handle = value; } } private Interop.MemoryHandle _handle; } }