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.
This commit is contained in:
Peter Huene
2020-02-07 11:24:26 -08:00
parent f8abe1169c
commit ae0b4090ce
28 changed files with 1303 additions and 268 deletions

View File

@@ -11,7 +11,7 @@ namespace Wasmtime.Bindings
/// <summary>
/// Represents a host function binding.
/// </summary>
public class FunctionBinding : Binding
internal class FunctionBinding : Binding
{
/// <summary>
/// Constructs a new function binding.
@@ -46,22 +46,19 @@ namespace Wasmtime.Bindings
/// </summary>
public MethodInfo Method { get; private set; }
internal override SafeHandle Bind(Store store, IHost host)
public override SafeHandle Bind(Store store, IHost host)
{
unsafe
{
if (_callback != null)
{
throw new InvalidOperationException("Cannot bind more than once.");
}
_callback = CreateCallback(store, host);
var parameters = Interop.ToValueTypeVec(Import.Parameters);
var results = Interop.ToValueTypeVec(Import.Results);
using (var funcType = Interop.wasm_functype_new(ref parameters, ref results))
{
return Interop.wasm_func_new(store.Handle, funcType, _callback);
var callback = CreateCallback(store, host);
var func = Interop.wasm_func_new(store.Handle, funcType, callback);
// Store the callback with the safe handle to keep the delegate GC reachable
func.Callback = callback;
return func;
}
}
}
@@ -70,17 +67,17 @@ namespace Wasmtime.Bindings
{
if (Method.IsStatic)
{
ThrowBindingException(Import, Method, "method cannot be static");
throw CreateBindingException(Import, Method, "method cannot be static");
}
if (Method.IsGenericMethod)
{
ThrowBindingException(Import, Method, "method cannot be generic");
throw CreateBindingException(Import, Method, "method cannot be generic");
}
if (Method.IsConstructor)
{
ThrowBindingException(Import, Method, "method cannot be a constructor");
throw CreateBindingException(Import, Method, "method cannot be a constructor");
}
ValidateParameters();
@@ -93,7 +90,7 @@ namespace Wasmtime.Bindings
var parameters = Method.GetParameters();
if (parameters.Length != Import.Parameters.Count)
{
ThrowBindingException(
throw CreateBindingException(
Import,
Method,
$"parameter mismatch: import requires {Import.Parameters.Count} but the method has {parameters.Length}");
@@ -106,18 +103,18 @@ namespace Wasmtime.Bindings
{
if (parameter.IsOut)
{
ThrowBindingException(Import, Method, $"parameter '{parameter.Name}' cannot be an 'out' parameter");
throw CreateBindingException(Import, Method, $"parameter '{parameter.Name}' cannot be an 'out' parameter");
}
else
{
ThrowBindingException(Import, Method, $"parameter '{parameter.Name}' cannot be a 'ref' parameter");
throw CreateBindingException(Import, Method, $"parameter '{parameter.Name}' cannot be a 'ref' parameter");
}
}
var expected = Import.Parameters[i];
if (!Interop.TryGetValueKind(parameter.ParameterType, out var kind) || !Interop.IsMatchingKind(kind, expected))
{
ThrowBindingException(Import, Method, $"method parameter '{parameter.Name}' is expected to be of type '{Interop.ToString(expected)}'");
throw CreateBindingException(Import, Method, $"method parameter '{parameter.Name}' is expected to be of type '{Interop.ToString(expected)}'");
}
}
}
@@ -129,7 +126,7 @@ namespace Wasmtime.Bindings
{
if (Method.ReturnType != typeof(void))
{
ThrowBindingException(Import, Method, "method must return void");
throw CreateBindingException(Import, Method, "method must return void");
}
}
else if (resultsCount == 1)
@@ -137,14 +134,14 @@ namespace Wasmtime.Bindings
var expected = Import.Results[0];
if (!Interop.TryGetValueKind(Method.ReturnType, out var kind) || !Interop.IsMatchingKind(kind, expected))
{
ThrowBindingException(Import, Method, $"return type is expected to be '{Interop.ToString(expected)}'");
throw CreateBindingException(Import, Method, $"return type is expected to be '{Interop.ToString(expected)}'");
}
}
else
{
if (!IsTupleOfSize(Method.ReturnType, resultsCount))
{
ThrowBindingException(Import, Method, $"return type is expected to be a tuple of size {resultsCount}");
throw CreateBindingException(Import, Method, $"return type is expected to be a tuple of size {resultsCount}");
}
var typeArguments =
@@ -163,7 +160,7 @@ namespace Wasmtime.Bindings
var expected = Import.Results[i];
if (!Interop.TryGetValueKind(typeArgument, out var kind) || !Interop.IsMatchingKind(kind, expected))
{
ThrowBindingException(Import, Method, $"return tuple item #{i} is expected to be of type '{Interop.ToString(expected)}'");
throw CreateBindingException(Import, Method, $"return tuple item #{i} is expected to be of type '{Interop.ToString(expected)}'");
}
++i;
@@ -340,7 +337,5 @@ namespace Wasmtime.Bindings
throw new NotSupportedException("Unsupported return value type.");
}
}
private Interop.WasmFuncCallback _callback;
}
}