Skip to content

Commit

Permalink
Instance Get All Exports (#290)
Browse files Browse the repository at this point in the history
* - Added methods to fetch all exports from an instance
 - Removed `wasmtime_instancetype_delete` (doesn't appear to be part of the c-api any more)

* Added another import with no module name

* Update tests/InstanceTests.cs

Co-authored-by: Konstantin Preißer <[email protected]>

* Apply suggestions from code review

Co-authored-by: Peter Huene <[email protected]>

* Removed unnecessary doc comment on private method

---------

Co-authored-by: Konstantin Preißer <[email protected]>
Co-authored-by: Peter Huene <[email protected]>
  • Loading branch information
3 people authored Jan 2, 2024
1 parent bd71441 commit c976fb2
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 3 deletions.
99 changes: 96 additions & 3 deletions src/Instance.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

Expand Down Expand Up @@ -579,6 +580,101 @@ public Instance(Store store, Module module, params object[] imports)
return _store.GetCachedExtern(ext.of.global);
}

/// <summary>
/// Get all exported functions
/// </summary>
/// <returns>An enumerable of functions exported from this instance</returns>
public IEnumerable<(string Name, Function Function)> GetFunctions()
{
for (var i = 0; i < int.MaxValue; i++)
{
if (TryGetExtern(i, ExternKind.Func) is not var (name, @extern))
{
break;
}

yield return (name, _store.GetCachedExtern(@extern.of.func));
}

GC.KeepAlive(_store);
}

/// <summary>
/// Get all exported tables
/// </summary>
/// <returns>An enumerable of tables exported from this instance</returns>
public IEnumerable<(string Name, Table Table)> GetTables()
{
for (var i = 0; i < int.MaxValue; i++)
{
if (TryGetExtern(i, ExternKind.Table) is not var (name, @extern))
{
break;
}

yield return (name, new Table(_store, @extern.of.table));
}

GC.KeepAlive(_store);
}

/// <summary>
/// Get all exported memories
/// </summary>
/// <returns>An enumerable of memories exported from this instance</returns>
public IEnumerable<(string Name, Memory Memory)> GetMemories()
{
for (var i = 0; i < int.MaxValue; i++)
{
if (TryGetExtern(i, ExternKind.Memory) is not var (name, @extern))
{
break;
}

yield return (name, _store.GetCachedExtern(@extern.of.memory));
}

GC.KeepAlive(_store);
}

/// <summary>
/// Get all exported globals
/// </summary>
/// <returns>An enumerable of globals exported from this instance</returns>
public IEnumerable<(string Name, Global Global)> GetGlobals()
{
for (var i = 0; i < int.MaxValue; i++)
{
if (TryGetExtern(i, ExternKind.Global) is not var (name, @extern))
{
break;
}

yield return (name, _store.GetCachedExtern(@extern.of.global));
}

GC.KeepAlive(_store);
}

private (string name, Extern @extern)? TryGetExtern(int index, ExternKind? type = null)
{
unsafe
{
if (!Native.wasmtime_instance_export_nth(_store.Context.handle, instance, (UIntPtr)index, out var namePtr, out var nameLen, out var @extern))
{
return null;
}

if (type != null && type.Value != @extern.kind)
{
return null;
}

var name = Encoding.UTF8.GetString(namePtr, checked((int)nameLen));
return (name, @extern);
}
}

private bool TryGetExtern(StoreContext context, string name, out Extern ext)
{
using var nameBytes = name.ToUTF8(stackalloc byte[Math.Min(64, name.Length * 2)]);
Expand Down Expand Up @@ -615,9 +711,6 @@ private static class Native
[DllImport(Engine.LibraryName)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern unsafe bool wasmtime_instance_export_nth(IntPtr context, in ExternInstance instance, UIntPtr index, out byte* name, out UIntPtr len, out Extern ext);

[DllImport(Engine.LibraryName)]
public static extern void wasmtime_instancetype_delete(IntPtr handle);
}

private readonly Store _store;
Expand Down
52 changes: 52 additions & 0 deletions tests/InstanceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Linq;
using FluentAssertions;
using Xunit;

namespace Wasmtime.Tests
{
public class InstanceFixture
: ModuleFixture
{
protected override string ModuleFileName => "hello.wat";
}

public class InstanceTests
: IClassFixture<InstanceFixture>, IDisposable
{
private Store Store { get; set; }

private Linker Linker { get; set; }

public InstanceTests(InstanceFixture fixture)
{
Fixture = fixture;
Linker = new Linker(Fixture.Engine);
Store = new Store(Fixture.Engine);

Linker.DefineFunction("env", "add", (int x, int y) => x + y);
Linker.DefineFunction("env", "swap", (int x, int y) => (y, x));
Linker.DefineFunction("", "hi", (int x, int y) => (y, x));

Linker.DefineFunction("", "hello", () => { });
}

private InstanceFixture Fixture { get; }

[Fact]
public void ItGetsExportedFunctions()
{
var instance = Linker.Instantiate(Store, Fixture.Module);

var results = instance.GetFunctions();

results.Single().Name.Should().Be("run");
}

public void Dispose()
{
Store.Dispose();
Linker.Dispose();
}
}
}

0 comments on commit c976fb2

Please sign in to comment.