Hi, recently I have started working with wasmtime in .NET, I have very little experience with C# however, and it has been hard for to to understand the docs., so I am a bit confused on how this package works here. I have a WebAssembly module that simply creates a file and writes to it (originally made in rust), and I managed to use it in wasmtime go, py, and rust. What I am trying to do is to reproduce this Go code in .NET:
dir, err := ioutil.TempDir("", "out")
check(err)
defer os.RemoveAll(dir)
stdoutPath := filepath.Join(dir, "stdout")
engine := wasmtime.NewEngine()
store := wasmtime.NewStore(engine)
linker := wasmtime.NewLinker(store)
// configure WASI imports to write stdout into a file.
wasiConfig := wasmtime.NewWasiConfig()
wasiConfig.SetStdoutFile(stdoutPath)
// pass access to this folder directory to the Wasm module
err = wasiConfig.PreopenDir("./data", ".")
check(err)
// set the version to the same as in the module.
wasi, err := wasmtime.NewWasiInstance(store, wasiConfig, "wasi_snapshot_preview1")
check(err)
// link WASI
err = linker.DefineWasi(wasi)
check(err)
// create the WebAssembly-module
module, err := wasmtime.NewModuleFromFile(store.Engine, "../wasm_module/write.wasm")
check(err)
instance, err := linker.Instantiate(module)
check(err)
in := instance.GetExport("_initialize").Func()
_, err = in.Call()
if err != nil {
panic(err)
}
So far I have this:
using var engine = new Engine();
using var store = new Store(engine);
//using var linker = new Link ..there is no linker?
WasiConfiguration wasiConfiguration = new WasiConfiguration();
wasiConfiguration.WithPreopenedDirectory("./data", "");
//using var wasi = Wasi .. no wasi?
using var module = Module.FromFile(engine, "write.wasm");
using var host = new Host(store);
host.DefineWasi("wasi1", wasiConfiguration);
using dynamic instance = host.Instantiate(module);
instance._initialize();
instance.write();
But there are some things that I don't understand, like how do I export a function correctly? In rust there were like 3 ways to do it, do I just do it the way I did it here in the last line?
Am I setting the pre-opened directory correctly?
Alright, I was mostly doing right, I just wrote the version of wasi wrong, should have been "wasi_snapshot_preview", is there a way to store a function in a variable?, instead of just calling it. The point is that I need store those functions in a class
I am stuck at the utilization of memory, how do this mem := instance.GetExport("memory").Memory()
in C#?
Hi @AndreaEsposit . Rather than casting the Instance
to dynamic
upon assignment, you can keep it an Instance
and use instance.Memories
to get the memory (either by ordinal or using something like a LINQ query to find by name).
Something like this perhaps:
using System;
using System.Linq;
using Wasmtime;
namespace Example
{
class Program
{
static void Main(string[] args)
{
using var engine = new Engine();
using var module = Module.FromFile(engine, "write.wasm");
using var store = new Store(engine);
using var host = new Host(store);
host.DefineWasi("wasi_snapshot_preview1", new WasiConfiguration().WithPreopenedDirectory("./data", "."));
using var instance = host.Instantiate(module);
((dynamic)instance)._initialize();
((dynamic)instance).write();
var memory = instance.Memories.Where(m => m.Name == "memory").First();
...
}
}
}
Likewise, instance.Memories[0]
would return the same memory by ordinal (assuming there's just one).
by storing a function in a variable, do you mean passing a function reference to Wasm?
Oh I think you mean just getting the function rather than using dynamic
(which is a shortcut for looking up the function and invoking it).
var write = instance.Functions.Where(f => f.Name == "write").First();
write.Invoke();
Oh I see, thank you very much, I was really struggling with this. Do I need to specify what types the function is taking? or all type of functions are can be defined like that?
Are you trying to define a host function or do you want to validate that the write
export of the instance has the expected parameters and results?
if the latter, the Invoke
method will validate what is passed to it matches the function's signature, but you can also do it in the above Where
call by checking the Parameters
and Results
properties of the ExternFunction
(see docs here: https://bytecodealliance.github.io/wasmtime-dotnet/api/Wasmtime.Externs.ExternFunction.html)
if the former, you'd use Host.DefineFunction
(of which there are a ton of overloads, see: https://bytecodealliance.github.io/wasmtime-dotnet/api/Wasmtime.Host.html) which has a bunch of reflection magic to get the appropriate Wasm function type of the delegate passed to it.
Oh, brilliant, thank you for the good explanations, much appreciated. I think I got everything you said, and I guess that to write a byte array to memory I will just have to use the WriteByte
function in a loop. (that is at least how I did it in Go)
You can slice Memory.Span
and use Array.CopyTo
for copying without iterating by byte (ends up being a memcpy under the covers)
e.g. bytes.CopyTo(memory.Span[offset..])
Last updated: Dec 23 2024 at 12:05 UTC