Stream: general

Topic: Wasmtime .NET questions


view this post on Zulip AndreaEsposit (Feb 17 2021 at 10:11):

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?

view this post on Zulip AndreaEsposit (Feb 17 2021 at 11:26):

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

view this post on Zulip AndreaEsposit (Feb 17 2021 at 16:57):

I am stuck at the utilization of memory, how do this mem := instance.GetExport("memory").Memory()in C#?

view this post on Zulip Peter Huene (Feb 17 2021 at 17:50):

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();
            ...
        }
    }
}

view this post on Zulip Peter Huene (Feb 17 2021 at 17:50):

Likewise, instance.Memories[0] would return the same memory by ordinal (assuming there's just one).

view this post on Zulip Peter Huene (Feb 17 2021 at 17:51):

by storing a function in a variable, do you mean passing a function reference to Wasm?

view this post on Zulip Peter Huene (Feb 17 2021 at 17:56):

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();

view this post on Zulip AndreaEsposit (Feb 17 2021 at 22:41):

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?

view this post on Zulip Peter Huene (Feb 17 2021 at 22:44):

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?

view this post on Zulip Peter Huene (Feb 17 2021 at 22:46):

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)

view this post on Zulip Peter Huene (Feb 17 2021 at 22:47):

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.

view this post on Zulip AndreaEsposit (Feb 17 2021 at 23:19):

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)

view this post on Zulip Peter Huene (Feb 17 2021 at 23:57):

You can slice Memory.Span and use Array.CopyTo for copying without iterating by byte (ends up being a memcpy under the covers)

view this post on Zulip Peter Huene (Feb 18 2021 at 00:00):

e.g. bytes.CopyTo(memory.Span[offset..])


Last updated: Dec 23 2024 at 12:05 UTC