using System; using System.IO; using System.Text; using System.Collections.Generic; using System.Runtime.InteropServices; namespace Wasmtime { /// /// Represents a WebAssembly host environment. /// /// /// A host is used to configure the environment for WebAssembly modules to execute in. /// public class Host : IDisposable { /// /// Constructs a new host. /// public Host() { Initialize(Interop.wasm_engine_new()); } /// /// Defines a WASI implementation in the host. /// /// The name of the WASI module to define. /// The to configure the WASI implementation with. public void DefineWasi(string name, WasiConfiguration config = null) { CheckDisposed(); if (string.IsNullOrEmpty(name)) { throw new ArgumentException("Name cannot be null or empty.", nameof(name)); } if (config is null) { config = new WasiConfiguration(); } using var wasi = config.CreateWasi(Store, name); if (!Interop.wasmtime_linker_define_wasi(Linker, wasi)) { throw new WasmtimeException($"Failed to define WASI module '{name}'."); } } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Action func) { return DefineFunction(moduleName, name, func, false); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a host function. /// /// The module name of the host function. /// The name of the host function. /// The callback for when the host function is invoked. /// Returns a representing the host function. public Function DefineFunction(string moduleName, string name, Func func) { return DefineFunction(moduleName, name, func, true); } /// /// Defines a new host global variable. /// /// The module name of the host variable. /// The name of the host variable. /// The initial value of the host variable. /// The type of the host variable. /// Returns a new representing the defined global variable. public Global DefineGlobal(string moduleName, string name, T initialValue) { CheckDisposed(); if (moduleName is null) { throw new ArgumentNullException(nameof(moduleName)); } if (name is null) { throw new ArgumentNullException(nameof(name)); } var global = new Global(Store, initialValue); if (!Define(moduleName, name, Interop.wasm_global_as_extern(global.Handle))) { global.Dispose(); throw new WasmtimeException($"Failed to define global '{name}' in module '{moduleName}'."); } return global; } /// /// Defines a new host mutable global variable. /// /// The module name of the host variable. /// The name of the host variable. /// The initial value of the host variable. /// The type of the host variable. /// Returns a new representing the defined mutable global variable. public MutableGlobal DefineMutableGlobal(string moduleName, string name, T initialValue) { CheckDisposed(); if (moduleName is null) { throw new ArgumentNullException(nameof(moduleName)); } if (name is null) { throw new ArgumentNullException(nameof(name)); } var global = new MutableGlobal(Store, initialValue); if (!Define(moduleName, name, Interop.wasm_global_as_extern(global.Handle))) { global.Dispose(); throw new WasmtimeException($"Failed to define global '{name}' in module '{moduleName}'."); } return global; } /// /// Defines a new host memory. /// /// The module name of the host memory. /// The name of the host memory. /// The minimum number of pages for the host memory. /// The maximum number of pages for the host memory. /// Returns a new representing the defined memory. public Memory DefineMemory(string moduleName, string name, uint minimum = 1, uint maximum = uint.MaxValue) { CheckDisposed(); if (moduleName is null) { throw new ArgumentNullException(nameof(moduleName)); } if (name is null) { throw new ArgumentNullException(nameof(name)); } var memory = new Memory(Store, minimum, maximum); if (!Define(moduleName, name, Interop.wasm_memory_as_extern(memory.Handle))) { memory.Dispose(); throw new WasmtimeException($"Failed to define memory '{name}' in module '{moduleName}'."); } return memory; } /// /// Loads a given the module name and bytes. /// /// The name of the module. /// The bytes of the module. /// Returns a new . public Module LoadModule(string name, byte[] bytes) { CheckDisposed(); if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } if (bytes is null) { throw new ArgumentNullException(nameof(bytes)); } return new Module(Store, name, bytes); } /// /// Loads a given the path to the WebAssembly file. /// /// The path to the WebAssembly file. /// Returns a new . public Module LoadModule(string path) { return LoadModule(Path.GetFileNameWithoutExtension(path), File.ReadAllBytes(path)); } /// /// Loads a based on a WebAssembly text format representation. /// /// The name of the module. /// The WebAssembly text format representation of the module. /// Returns a new . public Module LoadModuleText(string name, string text) { CheckDisposed(); if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } if (text is null) { throw new ArgumentNullException(nameof(text)); } var textBytes = Encoding.UTF8.GetBytes(text); unsafe { fixed (byte *ptr = textBytes) { Interop.wasm_byte_vec_t textVec; textVec.size = (UIntPtr)textBytes.Length; textVec.data = ptr; if (!Interop.wasmtime_wat2wasm(ref textVec, out var bytes, out var error)) { var errorSpan = new ReadOnlySpan(error.data, checked((int)error.size)); var message = Encoding.UTF8.GetString(errorSpan); Interop.wasm_byte_vec_delete(ref error); throw new WasmtimeException($"Failed to parse module text: {message}"); } var byteSpan = new ReadOnlySpan(bytes.data, checked((int)bytes.size)); var moduleBytes = byteSpan.ToArray(); Interop.wasm_byte_vec_delete(ref bytes); return LoadModule(name, moduleBytes); } } } /// /// Loads a based on the path to a WebAssembly text format file. /// /// The path to the WebAssembly text format file. /// Returns a new . public Module LoadModuleText(string path) { return LoadModuleText(Path.GetFileNameWithoutExtension(path), File.ReadAllText(path)); } /// /// Instantiates a WebAssembly module. /// /// The module to instantiate. /// Returns a new . public Instance Instantiate(Module module) { CheckDisposed(); if (module is null) { throw new ArgumentNullException(nameof(module)); } return new Instance(Linker, module); } /// /// Clears all existing definitions in the host. /// public void ClearDefinitions() { CheckDisposed(); var linker = Interop.wasmtime_linker_new(Store, allowShadowing: true); if (linker.IsInvalid) { throw new WasmtimeException("Failed to create Wasmtime linker."); } Linker.Dispose(); Linker = linker; } /// public void Dispose() { if (!Linker.IsInvalid) { Linker.Dispose(); Linker.SetHandleAsInvalid(); } if (!Store.IsInvalid) { Store.Dispose(); Store.SetHandleAsInvalid(); } if (!Engine.IsInvalid) { Engine.Dispose(); Engine.SetHandleAsInvalid(); } } internal Host(Interop.WasmConfigHandle config) { var engine = Interop.wasm_engine_new_with_config(config); config.SetHandleAsInvalid(); Initialize(engine); } private void Initialize(Interop.EngineHandle engine) { if (engine.IsInvalid) { throw new WasmtimeException("Failed to create Wasmtime engine."); } var store = Interop.wasm_store_new(engine); if (store.IsInvalid) { throw new WasmtimeException("Failed to create Wasmtime store."); } var linker = Interop.wasmtime_linker_new(store, allowShadowing: true); if (linker.IsInvalid) { throw new WasmtimeException("Failed to create Wasmtime linker."); } Engine = engine; Store = store; Linker = linker; } private void CheckDisposed() { if (Engine.IsInvalid) { throw new ObjectDisposedException(typeof(Host).FullName); } } private Function DefineFunction(string moduleName, string name, Delegate func, bool hasReturn) { if (moduleName is null) { throw new ArgumentNullException(nameof(moduleName)); } if (name is null) { throw new ArgumentNullException(nameof(name)); } if (func is null) { throw new ArgumentNullException(nameof(func)); } var function = new Function(Store, func, hasReturn); if (!Define(moduleName, name, Interop.wasm_func_as_extern(function.Handle))) { function.Dispose(); throw new WasmtimeException($"Failed to define function '{name}' in module '{moduleName}'."); } _callbacks.Add(function.Callback); return function; } private bool Define(string moduleName, string name, IntPtr ext) { var moduleNameBytes = Encoding.UTF8.GetBytes(moduleName); var nameBytes = Encoding.UTF8.GetBytes(name); unsafe { fixed (byte* moduleNamePtr = moduleNameBytes) fixed (byte* namePtr = nameBytes) { Interop.wasm_byte_vec_t moduleNameVec = new Interop.wasm_byte_vec_t(); moduleNameVec.size = (UIntPtr)moduleNameBytes.Length; moduleNameVec.data = moduleNamePtr; Interop.wasm_byte_vec_t nameVec = new Interop.wasm_byte_vec_t(); nameVec.size = (UIntPtr)nameBytes.Length; nameVec.data = namePtr; return Interop.wasmtime_linker_define(Linker, ref moduleNameVec, ref nameVec, ext); } } } internal Interop.EngineHandle Engine { get; private set; } internal Interop.StoreHandle Store { get; private set; } internal Interop.LinkerHandle Linker { get; private set; } private List _callbacks = new List(); } }