| // Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| part of 'dart:_wasm'; |
| |
| /// A [memory type] in WebAssembly, describing the address range and [Limits] |
| /// for memory instances. |
| /// |
| /// Dart currently only supports 32-bit memory instances. |
| /// |
| /// [memory type]: https://webassembly.github.io/spec/core/syntax/types.html#memory-types |
| @pragma("wasm:entry-point") |
| final class MemoryType { |
| /// Minimum and optional maximum size for the memory. |
| final Limits limits; |
| |
| const MemoryType({required this.limits}); |
| } |
| |
| /// Limits for the size of memories or tables in WebAssembly. |
| final class Limits { |
| /// The minimum size for the memory instance (in units of WebAssembly pages). |
| final int minimum; |
| |
| /// An optional maximum size for the instance (in units of WebAsembly pages). |
| final int? maximum; |
| |
| const Limits(this.minimum, [this.maximum]); |
| } |
| |
| /// An instance of linear memory available to this WebAssembly module. |
| /// |
| /// ## Using memories |
| /// |
| /// By default, compiling Dart to WebAssembly does not create a memory instance |
| /// (since Dart uses garbage collected types for everything instead). Especially |
| /// when interacting with other modules written in languages based on linear |
| /// memory though, it is necessary to access a linear memory instance from Dart. |
| /// |
| /// [MemoryAccessExtension] provides methods to load and store values at certain |
| /// positions in a linear memory instance (e.g. [MemoryAccessExtension.loadInt8] |
| /// or [MemoryAccessExtension.storeInt8]), to inspect its |
| /// [MemoryAccessExtension.size] of memory or to [MemoryAccessExtension.grow] |
| /// it (if supported by the memory instance). |
| /// |
| /// In WebAssembly, instructions can't be polymorphic with regards to the memory |
| /// instance they operate on: Each `i8.load` instruction has the target memory |
| /// instance encoded into it. |
| /// This also restricts how memory instances can be used in Dart: Every call |
| /// must use a top-level getter defining the memory as a receiver. It is not |
| /// allowed to call methods on other instances of [Memory]: |
| /// |
| /// ``` |
| /// @pragma('wasm:memory-type', MemoryType(limits: Limits(1, 10))) |
| /// external Memory get additionalMemory; |
| /// |
| /// void main() { |
| /// // Allowed: Direct access to memory instance |
| /// print(additionalMemory.size); |
| /// |
| /// // Not allowed: Loading a reference to the memory instance. |
| /// useMemory(additionalMemory); |
| /// } |
| /// |
| /// void useMemory(Memory memory) { |
| /// // Not allowed: Dynamic memory instance. |
| /// memory.loadInt32(0, 1337); |
| /// } |
| /// ``` |
| /// |
| /// Further, tearing-off methods from [MemoryAccessExtension] is a compile-time |
| /// error. |
| /// |
| /// ## Obtaining memory instances |
| /// |
| /// To access linear memory, a [Memory] instance needs to be defined or |
| /// imported. |
| /// |
| /// To define a memory instance, use a top-level getter defined as `external` |
| /// and with a [MemoryType] annotation: |
| /// |
| /// ``` |
| /// @pragma('wasm:memory-type', MemoryType(limits: Limits(1, 10))) |
| /// external Memory get additionalMemory; |
| /// ``` |
| /// |
| /// Memory instances can also be imported from the host environment by |
| /// annotating such getter with the `wasm:import` pragma: |
| /// |
| /// ``` |
| /// @pragma('wasm:memory-type', MemoryType(limits: Limits(1, 10))) |
| /// @pragma('wasm:import', 'module.name') |
| /// external Memory get mySecondMemory; |
| /// ``` |
| /// |
| /// ## Restrictions |
| /// |
| /// Note that only 32-bit [Memory] instances are supported by Dart at the |
| /// moment. |
| @pragma("wasm:entry-point") |
| final class Memory { |
| Memory._(); |
| |
| /// The size of a page in WebAssembly memory. |
| static const pageSize = 65536; |
| } |
| |
| /// Operators accessing [Memory] instances in WebAssembly. |
| extension MemoryAccessExtension on Memory { |
| /// Returns the size of this memory instance in units of [Memory.pageSize] |
| /// (65536 bytes). |
| @pragma("wasm:intrinsic") |
| external int get size; |
| |
| /// Grows the size of this memory instance by the amount of [pages]. |
| /// |
| /// This returns the old size (also in units of [Memory.pageSize]) if growing |
| /// this memory instance was successful, or `-1` otherwise (e.g. due to an |
| /// out-of-memory error). |
| @pragma("wasm:intrinsic") |
| external int grow(int pages); |
| |
| /// Copies the byte [value] to the memory region from [startOffset] to |
| /// [startOffset] plus [length] (exclusive). |
| /// |
| /// This causes a WebAssembly trap if the target region is out-of-bounds for |
| /// this memory. |
| @pragma("wasm:intrinsic") |
| external void fill(WasmI32 value, int startOffset, int length); |
| |
| @pragma("wasm:intrinsic") |
| external WasmF32 loadFloat32(int address, {int align = 0, int offset = 0}); |
| @pragma("wasm:intrinsic") |
| external WasmF64 loadFloat64(int address, {int align = 0, int offset = 0}); |
| |
| @pragma("wasm:intrinsic") |
| external WasmI32 loadInt8(int address, {int align = 0, int offset = 0}); |
| @pragma("wasm:intrinsic") |
| external WasmI32 loadInt16(int address, {int align = 0, int offset = 0}); |
| @pragma("wasm:intrinsic") |
| external WasmI32 loadInt32(int address, {int align = 0, int offset = 0}); |
| @pragma("wasm:intrinsic") |
| external WasmI64 loadInt64(int address, {int align = 0, int offset = 0}); |
| |
| @pragma("wasm:intrinsic") |
| external WasmI32 loadUint8(int address, {int align = 0, int offset = 0}); |
| @pragma("wasm:intrinsic") |
| external WasmI32 loadUint16(int address, {int align = 0, int offset = 0}); |
| @pragma("wasm:intrinsic") |
| external WasmI32 loadUint32(int address, {int align = 0, int offset = 0}); |
| |
| @pragma("wasm:intrinsic") |
| external void storeFloat32( |
| int address, |
| WasmF32 value, { |
| int align = 0, |
| int offset = 0, |
| }); |
| @pragma("wasm:intrinsic") |
| external void storeFloat64( |
| int address, |
| WasmF64 value, { |
| int align = 0, |
| int offset = 0, |
| }); |
| |
| @pragma("wasm:intrinsic") |
| external void storeInt8( |
| int address, |
| WasmI32 value, { |
| int align = 0, |
| int offset = 0, |
| }); |
| @pragma("wasm:intrinsic") |
| external void storeInt16( |
| int address, |
| WasmI32 value, { |
| int align = 0, |
| int offset = 0, |
| }); |
| @pragma("wasm:intrinsic") |
| external void storeInt32( |
| int address, |
| WasmI32 value, { |
| int align = 0, |
| int offset = 0, |
| }); |
| @pragma("wasm:intrinsic") |
| external void storeInt64( |
| int address, |
| WasmI64 value, { |
| int align = 0, |
| int offset = 0, |
| }); |
| } |