Learning WASM #13

WASM側でTaskを使ったらどうなるんだろう。


準備のためにホスト側に関数を生やしてそれをWASM側から実行できるようにしてみる。

ゲスト側ではホストの関数を参照するのに[DllImport]をつかう


using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Text;

namespace classlib;

public static class Class1
{
    [DllImport("*")]
    static extern void return_string(IntPtr ptr, int len);
 
    [UnmanagedCallersOnly(EntryPoint = "ReadAsync")]
    public static void ReadAsync() 
    {
        var str = ManagedString();
        var bytes = Encoding.ASCII.GetBytes(str);

        unsafe {
            fixed(byte* ptr = bytes) {
                return_string((nint)ptr, bytes.Length);
            }
        }
    }

    private static string ManagedString() {
        return "This is managed string value";
    }
}


csprojでWasmImportを設定しないとWASMファイルにimport宣言が出力されなかった。


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <OutputType>Library</OutputType>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PublishTrimmed>true</PublishTrimmed>
    <RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
    <MSBuildEnableWorkloadResolver>false</MSBuildEnableWorkloadResolver>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
    <PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
    <WasmImport Include="env!return_string" />
  </ItemGroup>
</Project>


ホスト側ではLinkerに関数を生やす。


using System.Text;
using Wasmtime;

var wasm = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "lib.wasm");
using var engine = new Engine(new Config().WithWasmThreads(true));
using var module = Module.FromFile(engine, wasm);
using var linker = new Linker(engine);
using var store = new Store(engine);

linker.DefineWasi();
linker.Define("env", "return_string", Function.FromCallback(store, (Caller caller, int ptr, int length) => {
    var value = caller.GetMemory("memory")!.ReadString(ptr, length, Encoding.ASCII);
    Console.WriteLine(value);
}));

store.SetWasiConfiguration(new WasiConfiguration());

var instance = linker.Instantiate(store, module);

var init = instance.GetAction("_initialize")!;

init();

var readasync = instance.GetAction("ReadAsync")!;

readasync.Invoke();