Learning WASM #13
November 16, 2023•170 words
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();