Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to recent Wasmtime C API changes regarding values #318

Merged
merged 5 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/Externs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,35 @@ namespace Wasmtime
internal struct ExternFunc
{
public ulong store;
public UIntPtr index;
private nuint __private;
}

[StructLayout(LayoutKind.Sequential)]
internal struct ExternTable
{
public ulong store;
public UIntPtr index;
private nuint __private;
}

[StructLayout(LayoutKind.Sequential)]
internal struct ExternMemory
{
public ulong store;
public UIntPtr index;
private nuint __private;
}

[StructLayout(LayoutKind.Sequential)]
internal struct ExternInstance
{
public ulong store;
public UIntPtr index;
private nuint __private;
}

[StructLayout(LayoutKind.Sequential)]
internal struct ExternGlobal
{
public ulong store;
public UIntPtr index;
private nuint __private;
}

internal enum ExternKind : byte
Expand All @@ -44,6 +44,7 @@ internal enum ExternKind : byte
Global,
Table,
Memory,
SharedMemory,
}

[StructLayout(LayoutKind.Explicit)]
Expand All @@ -60,6 +61,9 @@ internal struct ExternUnion

[FieldOffset(0)]
public ExternMemory memory;

[FieldOffset(0)]
public IntPtr sharedmemory;
}

[StructLayout(LayoutKind.Sequential)]
Expand Down
50 changes: 39 additions & 11 deletions src/Function.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ out externFunc
/// <summary>
/// Determines if the underlying function reference is null.
/// </summary>
public bool IsNull => func.index == UIntPtr.Zero && func.store == 0;
public bool IsNull => func.IsNull();

/// <summary>
/// Represents a null function reference.
Expand Down Expand Up @@ -295,14 +295,28 @@ private unsafe void InvokeWithoutReturn(Span<ValueRaw> arguments, StoreContext s
Span<Value> args = stackalloc Value[Parameters.Count];
for (var i = 0; i < arguments.Length; ++i)
{
args[i] = arguments[i].ToValue(store, Parameters[i]);
}
try
{
args[i] = arguments[i].ToValue(store, Parameters[i]);
}
catch
{
// Clean-up the previous values in case an exception occured (e.g. when
// `wasmtime_externref_new` failed).
for (int releaseIndex = 0; releaseIndex < i; releaseIndex++)
{
args[releaseIndex].Release(store);
}

// Make some space to store the return results
Span<Value> resultsSpan = stackalloc Value[Results.Count];
throw;
}
}

try
{
// Make some space to store the return results
Span<Value> resultsSpan = stackalloc Value[Results.Count];

var trap = Invoke(args, resultsSpan);
if (trap != IntPtr.Zero)
{
Expand Down Expand Up @@ -333,18 +347,17 @@ private unsafe void InvokeWithoutReturn(Span<ValueRaw> arguments, StoreContext s
{
for (int i = 0; i < Results.Count; ++i)
{
resultsSpan[i].Dispose();
resultsSpan[i].Release(store);
}
}
}
finally
{
for (int i = 0; i < arguments.Length; ++i)
{
args[i].Dispose();
args[i].Release(store);
}
}

}

/// <summary>
Expand Down Expand Up @@ -444,8 +457,7 @@ Extern IExternal.AsExtern()
internal Function()
{
this.store = null;
this.func.store = 0;
this.func.index = (UIntPtr)0;
this.func = default;
this.Parameters = this.Results = Array.Empty<ValueKind>();
}

Expand Down Expand Up @@ -648,7 +660,23 @@ internal static unsafe IntPtr InvokeUntypedCallback(UntypedCallbackDelegate call

for (int i = 0; i < resultsSpan.Length; i++)
{
results[i] = resultsSpan[i].ToValue(caller.Store, resultKinds[i]);
try
{
results[i] = resultsSpan[i].ToValue(caller.Store, resultKinds[i]);
}
catch
{
// Clean-up the previous result values in case an exception occured
// (e.g. when `wasmtime_externref_new` failed), because we will
// return an error in that case and therefore can't pass ownership
// of already allocated result values.
for (int releaseIndex = 0; releaseIndex < i; releaseIndex++)
{
results[releaseIndex].Release(caller.Store);
}

throw;
}
}
}
finally
Expand Down
61 changes: 45 additions & 16 deletions src/Global.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,20 @@ public Global(Store store, ValueKind kind, object? initialValue, Mutability muta
}

var value = Value.FromObject(store, initialValue, Kind);
var error = Native.wasmtime_global_new(store.Context.handle, globalType, in value, out this.global);
GC.KeepAlive(store);

value.Dispose();
try
{
var error = Native.wasmtime_global_new(store.Context.handle, globalType, in value, out this.global);
GC.KeepAlive(store);

if (error != IntPtr.Zero)
if (error != IntPtr.Zero)
{
throw WasmtimeException.FromOwnedError(error);
}
}
finally
{
throw WasmtimeException.FromOwnedError(error);
value.Release(store);
}
}

Expand All @@ -139,9 +145,15 @@ public Global(Store store, ValueKind kind, object? initialValue, Mutability muta
Native.wasmtime_global_get(context.handle, this.global, out var v);
GC.KeepAlive(store);

var val = v.ToObject(store);
v.Dispose();
return val;
try
{
var val = v.ToObject(store);
return val;
}
finally
{
v.Release(store);
}
}

/// <summary>
Expand All @@ -156,10 +168,16 @@ public void SetValue(object? value)
}

var v = Value.FromObject(store, value, Kind);
Native.wasmtime_global_set(store.Context.handle, this.global, in v);
GC.KeepAlive(store);

v.Dispose();
try
{
Native.wasmtime_global_set(store.Context.handle, this.global, in v);
GC.KeepAlive(store);
}
finally
{
v.Release(store);
}
}

/// <summary>
Expand Down Expand Up @@ -300,10 +318,15 @@ public T GetValue()
Native.wasmtime_global_get(context.handle, _global.global, out var v);
GC.KeepAlive(_store);

var result = _converter.Unbox(_store, v.ToValueBox(_store));
v.Dispose();

return result;
try
{
var result = _converter.Unbox(_store, v.ToValueBox(_store));
return result;
}
finally
{
v.Release(_store);
}
}

/// <summary>
Expand All @@ -317,12 +340,18 @@ public void SetValue(T value)
throw new InvalidOperationException("The global is immutable and cannot be changed.");
}

using (var v = _converter.Box(value).ToValue(_store, _global.Kind))
var v = _converter.Box(value).ToValue(_store, _global.Kind);

try
{
var context = _store.Context;
Native.wasmtime_global_set(context.handle, _global.global, in v);
GC.KeepAlive(_store);
}
finally
{
v.Release(_store);
}
}

Extern IExternal.AsExtern()
Expand Down
28 changes: 12 additions & 16 deletions src/Store.cs
Original file line number Diff line number Diff line change
Expand Up @@ -340,45 +340,41 @@ private static class Native

private static readonly Native.Finalizer Finalizer = (p) => GCHandle.FromIntPtr(p).Free();

private readonly ConcurrentDictionary<(ExternKind kind, ulong store, nuint index), object> _externCache = new();
private readonly ConcurrentDictionary<ExternFunc, Function> _externFuncCache = new();
private readonly ConcurrentDictionary<ExternMemory, Memory> _externMemoryCache = new();
private readonly ConcurrentDictionary<ExternGlobal, Global> _externGlobalCache = new();

internal Function GetCachedExtern(ExternFunc @extern)
{
var key = (ExternKind.Func, @extern.store, @extern.index);

if (!_externCache.TryGetValue(key, out var func))
if (!_externFuncCache.TryGetValue(@extern, out var func))
{
func = new Function(this, @extern);
func = _externCache.GetOrAdd(key, func);
func = _externFuncCache.GetOrAdd(@extern, func);
}

return (Function)func;
return func;
}

internal Memory GetCachedExtern(ExternMemory @extern)
{
var key = (ExternKind.Memory, @extern.store, @extern.index);

if (!_externCache.TryGetValue(key, out var mem))
if (!_externMemoryCache.TryGetValue(@extern, out var mem))
{
mem = new Memory(this, @extern);
mem = _externCache.GetOrAdd(key, mem);
mem = _externMemoryCache.GetOrAdd(@extern, mem);
}

return (Memory)mem;
return mem;
}

internal Global GetCachedExtern(ExternGlobal @extern)
{
var key = (ExternKind.Global, @extern.store, @extern.index);

if (!_externCache.TryGetValue(key, out var global))
if (!_externGlobalCache.TryGetValue(@extern, out var global))
{
global = new Global(this, @extern);
global = _externCache.GetOrAdd(key, global);
global = _externGlobalCache.GetOrAdd(@extern, global);
}

return (Global)global;
return global;
}
}
}
Loading
Loading