Skip to content
Merged
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
95 changes: 73 additions & 22 deletions src/Linker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Wasmtime
/// </summary>
public partial class Linker : IDisposable
{
private const int StackallocThreshold = 256;

/// <summary>
/// Constructs a new linker from the given engine.
/// </summary>
Expand All @@ -39,13 +41,8 @@ public bool AllowShadowing
}
}

/// <summary>
/// Defines an item in the linker.
/// </summary>
/// <param name="module">The module name of the item.</param>
/// <param name="name">The name of the item.</param>
/// <param name="item">The item being defined (e.g. function, global, table, etc.).</param>
public void Define(string module, string name, object item)
private void Define<T>(string module, string name, T item)
where T : IExternal
{
if (module is null)
{
Expand All @@ -57,34 +54,90 @@ public void Define(string module, string name, object item)
throw new ArgumentNullException(nameof(name));
}

var external = item as IExternal;
if (external is null)
{
throw new ArgumentException($"Objects of type `{item.GetType()}` cannot be defined in a linker.");
}

if (external.Store is null)
var store = item.Store;
if (store is null)
{
throw new ArgumentException($"The item is not associated with a store.");
}

var ext = external.AsExtern();
var ext = item.AsExtern();

var nameLength = Encoding.UTF8.GetByteCount(name);
var nameBytes = nameLength <= StackallocThreshold ? stackalloc byte[nameLength] : new byte[nameLength];
Encoding.UTF8.GetBytes(name, nameBytes);

var moduleLength = Encoding.UTF8.GetByteCount(module);
var moduleBytes = moduleLength <= StackallocThreshold ? stackalloc byte[moduleLength] : new byte[moduleLength];
Encoding.UTF8.GetBytes(module, moduleBytes);

unsafe
{
var moduleBytes = Encoding.UTF8.GetBytes(module);
var nameBytes = Encoding.UTF8.GetBytes(name);
fixed (byte* modulePtr = moduleBytes, namePtr = nameBytes)
{
var error = Native.wasmtime_linker_define(handle, external.Store.Context.handle, modulePtr, (UIntPtr)moduleBytes.Length, namePtr, (UIntPtr)nameBytes.Length, ext);
var error = Native.wasmtime_linker_define(handle, store.Context.handle, modulePtr, (UIntPtr)moduleBytes.Length, namePtr, (UIntPtr)nameBytes.Length, ext);
if (error != IntPtr.Zero)
{
throw WasmtimeException.FromOwnedError(error);
}

GC.KeepAlive(external);
}
}

GC.KeepAlive(store);
}

/// <summary>
/// Defines an item in the linker.
/// </summary>
/// <param name="module">The module name of the item.</param>
/// <param name="name">The name of the item.</param>
/// <param name="function">The item being defined</param>
public void Define(string module, string name, Function function)
{
Define<Function>(module, name, function);
}

/// <summary>
/// Defines an item in the linker.
/// </summary>
/// <param name="module">The module name of the item.</param>
/// <param name="name">The name of the item.</param>
/// <param name="global">The item being defined</param>
public void Define(string module, string name, Global global)
{
Define<Global>(module, name, global);
}

/// <summary>
/// Defines an item in the linker.
/// </summary>
/// <param name="module">The module name of the item.</param>
/// <param name="name">The name of the item.</param>
/// <param name="global">The item being defined</param>
public void Define<T>(string module, string name, Global.Accessor<T> global)
{
Define<Global.Accessor<T>>(module, name, global);
}

/// <summary>
/// Defines an item in the linker.
/// </summary>
/// <param name="module">The module name of the item.</param>
/// <param name="name">The name of the item.</param>
/// <param name="memory">The item being defined</param>
public void Define(string module, string name, Memory memory)
{
Define<Memory>(module, name, memory);
}

/// <summary>
/// Defines an item in the linker.
/// </summary>
/// <param name="module">The module name of the item.</param>
/// <param name="name">The name of the item.</param>
/// <param name="table">The item being defined</param>
public void Define(string module, string name, Table table)
{
Define<Table>(module, name, table);
}

/// <summary>
Expand Down Expand Up @@ -389,8 +442,6 @@ public void DefineFunction(string module, string name, Function.UntypedCallbackD
return Function.InvokeUntypedCallback(callback, callerPtr, args, (int)nargs, results, (int)nresults, resultKinds);
};

const int StackallocThreshold = 256;

byte[]? moduleBytesBuffer = null;
var moduleLength = Encoding.UTF8.GetByteCount(module);
Span<byte> moduleBytes = moduleLength <= StackallocThreshold ? stackalloc byte[moduleLength] : (moduleBytesBuffer = ArrayPool<byte>.Shared.Rent(moduleLength)).AsSpan()[..moduleLength];
Expand Down