Files
wasmtime/crates/misc/dotnet/src/Instance.cs

149 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Dynamic;
using Wasmtime.Externs;
namespace Wasmtime
{
/// <summary>
/// Represents an instantiated WebAssembly module.
/// </summary>
public class Instance : DynamicObject, IDisposable
{
internal Instance(Module module, IHost host)
{
Host = host;
Module = module;
//Save the bindings to root the objects.
//Otherwise the GC may collect the delegates from ExternFunction for example.
_bindings = host.GetImportBindings(module);
var handles = _bindings.Select(b => b.Bind(module.Store, host)).ToList();
unsafe
{
Handle = Interop.wasm_instance_new(
Module.Store.Handle,
Module.Handle,
handles.Select(h => ToExtern(h)).ToArray(),
out var trap);
if (trap != IntPtr.Zero)
{
throw TrapException.FromOwnedTrap(trap);
}
}
if (Handle.IsInvalid)
{
throw new WasmtimeException($"Failed to instantiate module '{module.Name}'.");
}
// Dispose of all function handles (not needed at runtime)
foreach (var h in handles.Where(h => h is Interop.FunctionHandle))
{
h.Dispose();
}
Interop.wasm_instance_exports(Handle, out _externs);
Externs = new Wasmtime.Externs.Externs(Module.Exports, _externs);
_functions = Externs.Functions.ToDictionary(f => f.Name);
_globals = Externs.Globals.ToDictionary(g => g.Name);
}
/// <summary>
/// The host associated with this instance.
/// </summary>
public IHost Host { get; private set; }
/// <summary>
/// The WebAssembly module associated with the instantiation.
/// </summary>
public Module Module { get; private set; }
/// <summary>
/// The external (instantiated) collection of functions, globals, tables, and memories.
/// </summary>
public Wasmtime.Externs.Externs Externs { get; private set; }
/// <inheritdoc/>
public void Dispose()
{
if (!Handle.IsInvalid)
{
Handle.Dispose();
Handle.SetHandleAsInvalid();
}
if (_externs.size != UIntPtr.Zero)
{
Interop.wasm_extern_vec_delete(ref _externs);
_externs.size = UIntPtr.Zero;
}
}
/// <inheritdoc/>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_globals.TryGetValue(binder.Name, out var global))
{
result = global.Value;
return true;
}
result = null;
return false;
}
/// <inheritdoc/>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (_globals.TryGetValue(binder.Name, out var global))
{
global.Value = value;
return true;
}
return false;
}
/// <inheritdoc/>
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (!_functions.TryGetValue(binder.Name, out var func))
{
result = null;
return false;
}
result = func.Invoke(args);
return true;
}
private static unsafe IntPtr ToExtern(SafeHandle handle)
{
switch (handle)
{
case Interop.FunctionHandle f:
return Interop.wasm_func_as_extern(f);
case Interop.GlobalHandle g:
return Interop.wasm_global_as_extern(g);
case Interop.MemoryHandle m:
return Interop.wasm_memory_as_extern(m);
default:
throw new NotSupportedException("Unexpected handle type.");
}
}
internal Interop.InstanceHandle Handle { get; private set; }
private Interop.wasm_extern_vec_t _externs;
private Dictionary<string, ExternFunction> _functions;
private Dictionary<string, ExternGlobal> _globals;
private List<Bindings.Binding> _bindings;
}
}