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();
}
}