import 'dart:typed_data'; import 'package:meta/meta.dart'; import 'module.dart'; import '../ffi/types.dart'; import '../internal/marshaller.dart'; import '../web_ffi_meta.dart'; final Map sizeMap = {}; /// Must be called with each type that extends Opaque before /// attemtping to use that type. @extra void registerOpaqueType() { sizeMap[T] = sizeOf(); registerNativeMarshallerOpaque(); } void _registerType(int size) { sizeMap[T] = size; registerNativeMarshallerType(); } /// Represents the native heap. @extra class Memory implements Allocator { /// The endianess of data stored. /// /// The WebAssembly speficiation defines little endianess, so this is a constant. static const Endian endianess = Endian.little; /// Must be called before working with `web_ffi` to initalize all type sizes. /// /// The optional parameter [pointerSizeBytes] can be used to adjust the size /// of pointers. It defaults to `4` since WebAssembly usually uses 32 bit pointers. /// If you want to use wasm64, set [pointerSizeBytes] to `8` to denote 64 bit pointers. static void init([int pointerSizeBytes = 4]) { _registerType(4); _registerType(8); _registerType(1); _registerType(1); _registerType(2); _registerType(2); _registerType(4); _registerType(4); _registerType(8); _registerType(8); _registerType(pointerSizeBytes); _registerType(pointerSizeBytes); registerNativeMarshallerType(); registerNativeMarshallerType>(); } /// The default [Memory] object to use. /// /// This field is null until it is either manually set to a [Memory] object, /// or automatically set by [DynamicLibrary.fromModule]. /// /// This is most notably used when creating a pointer using [Pointer.fromAddress] /// with no explicite memory to bind to given. static Memory? global; /// Can be used to directly access the memory of this object. /// /// The value of this field should not be stored in a state variable, /// since the returned buffer may change over time. @doNotStore ByteBuffer get buffer => _module.heap; final Module _module; final Map _symbolsByName; final Map _symbolsByAddress; Memory._(this._module) : _symbolsByAddress = new Map.fromEntries(_module.exports .map>((WasmSymbol symbol) => new MapEntry(symbol.address, symbol))), _symbolsByName = new Map.fromEntries(_module.exports .map>((WasmSymbol symbol) => new MapEntry(symbol.name, symbol))); @override Pointer allocate(int byteCount, {int? alignment}) { return new Pointer.fromAddress(_module.malloc(byteCount), this); } @override void free(Pointer pointer) { _module.free(pointer.address); } } Memory createMemory(Module module) => new Memory._(module); WasmSymbol symbolByAddress(Memory m, int address) { WasmSymbol? s = m._symbolsByAddress[address]; if (s != null) { return s; } else { throw new ArgumentError('Could not find symbol at $address!'); } } WasmSymbol symbolByName(Memory m, String name) { WasmSymbol? s = m._symbolsByName[name]; if (s != null) { return s; } else { throw new ArgumentError('Could not find symbol $name!'); } } /// Used on [DynamicLibrary] creation to control if the therby newly created /// [Memory] object should be registered as [Memory.global]. @extra enum MemoryRegisterMode { yes, no, onlyIfGlobalNotSet }