This commit implements an initial WASI C API that can be used to instantiate and configure a WASI instance from C. This also implements a `WasiBuilder` for the C# API enabling .NET hosts to bind to Wasmtime's WASI implementation.
126 lines
4.1 KiB
C#
126 lines
4.1 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using Wasmtime.Imports;
|
|
|
|
namespace Wasmtime.Bindings
|
|
{
|
|
/// <summary>
|
|
/// Represents a host global binding.
|
|
/// </summary>
|
|
internal class GlobalBinding : Binding
|
|
{
|
|
/// <summary>
|
|
/// Constructs a new global binding.
|
|
/// </summary>
|
|
/// <param name="import">The global import of the binding.</param>
|
|
/// <param name="field">The field the import is bound to.</param>
|
|
public GlobalBinding(GlobalImport import, FieldInfo field)
|
|
{
|
|
if (import is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(import));
|
|
}
|
|
|
|
if (field is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(field));
|
|
}
|
|
|
|
Import = import;
|
|
Field = field;
|
|
|
|
Validate();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The global import of the binding.
|
|
/// </summary>
|
|
public GlobalImport Import { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The field the import is bound to.
|
|
/// </summary>
|
|
public FieldInfo Field { get; private set; }
|
|
|
|
public override SafeHandle Bind(Store store, IHost host)
|
|
{
|
|
unsafe
|
|
{
|
|
dynamic global = Field.GetValue(host);
|
|
if (!(global.Handle is null))
|
|
{
|
|
throw new InvalidOperationException("Cannot bind more than once.");
|
|
}
|
|
|
|
var v = Interop.ToValue((object)global.InitialValue, Import.Kind);
|
|
|
|
var valueType = Interop.wasm_valtype_new(v.kind);
|
|
var valueTypeHandle = valueType.DangerousGetHandle();
|
|
valueType.SetHandleAsInvalid();
|
|
|
|
using (var globalType = Interop.wasm_globaltype_new(
|
|
valueTypeHandle,
|
|
Import.IsMutable ? Interop.wasm_mutability_t.WASM_VAR : Interop.wasm_mutability_t.WASM_CONST))
|
|
{
|
|
var handle = Interop.wasm_global_new(store.Handle, globalType, &v);
|
|
global.Handle = handle;
|
|
return handle;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Validate()
|
|
{
|
|
if (Field.IsStatic)
|
|
{
|
|
throw CreateBindingException(Import, Field, "field cannot be static");
|
|
}
|
|
|
|
if (!Field.IsInitOnly)
|
|
{
|
|
throw CreateBindingException(Import, Field, "field must be readonly");
|
|
}
|
|
|
|
if (!Field.FieldType.IsGenericType)
|
|
{
|
|
throw CreateBindingException(Import, Field, "field is expected to be of type 'Global<T>'");
|
|
}
|
|
|
|
var definition = Field.FieldType.GetGenericTypeDefinition();
|
|
if (definition == typeof(Global<>))
|
|
{
|
|
if (Import.IsMutable)
|
|
{
|
|
throw CreateBindingException(Import, Field, "the import is mutable (use the 'MutableGlobal' type)");
|
|
}
|
|
}
|
|
else if (definition == typeof(MutableGlobal<>))
|
|
{
|
|
if (!Import.IsMutable)
|
|
{
|
|
throw CreateBindingException(Import, Field, "the import is constant (use the 'Global' type)");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw CreateBindingException(Import, Field, "field is expected to be of type 'Global<T>' or 'MutableGlobal<T>'");
|
|
}
|
|
|
|
var arg = Field.FieldType.GetGenericArguments()[0];
|
|
|
|
if (Interop.TryGetValueKind(arg, out var kind))
|
|
{
|
|
if (!Interop.IsMatchingKind(kind, Import.Kind))
|
|
{
|
|
throw CreateBindingException(Import, Field, $"global type argument is expected to be of type '{Interop.ToString(Import.Kind)}'");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw CreateBindingException(Import, Field, $"'{arg}' is not a valid global type");
|
|
}
|
|
}
|
|
}
|
|
}
|