Files
wasmtime/crates/misc/dotnet/src/Bindings/GlobalBinding.cs
Peter Huene ae0b4090ce Implement WASI C API.
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.
2020-02-24 17:42:44 -08:00

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