blob: 5302c9bd39c0c8d60767be01d3cdbe5f5d9e26cf [file] [log] [blame] [edit]
// 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,
});
}