Stream: wasmtime

Topic: recursive function calls between host and guest


view this post on Zulip code red art (Jan 31 2023 at 23:19):

Recursion is weird, so i will try to explain this in as few words as possible.

I want to register a host fn which can take a wasm fn as argument.
and i want that argument (wasm fn) to also be able to take a fn as an argument so that i can recursively call it if needed so which itself might call into the original host fn and so on...

I am basically looking into egui + wasm scripting. egui uses a heavy closure based api like

Window::new("hello window").show(|ui| {
  ui.button("top ui");
  ui.horizontal(|hui| {
    hui.label("horizontal ui label");
    hui.child_ui(|cui| {
      cui.label("inner child ui");
    });
  });
});

here, show is a host fn, and this wasm closure needs to be called by that fn with ui as argument. and ofcourse, all the button/horizontal/child_ui/label fns are host bindings too.

so, to provide those bindings, i need to take wasm closures and wasm closures might call host bindings (like child_ui or horizontal) recursively.

I am thinking that its not possible, but wanted to ask here just in case.

view this post on Zulip Alex Crichton (Feb 01 2023 at 00:55):

This is all theoretically possible with building blocks in the Wasmtime API. For example if you'd like you can use the funcref type which is Option<Func> as an argument. Both a wasm and a host function can become a Func. Few wasm guests have native support for funcref, though, so an analogue would instead be to communicate with indices that are actually indexes into a Table where the host can store functions in there along with the guest.

Your hardest part, however, is likely going to be wrangling mutability. Invocations of wasm require &mut Store<T> which means that you have to thread that all the way from when the host was called into back to where the wasm is being invoked. If this is spread out across an application that probably won't work too well, but if it's a local decision it may be easier.

In any case what you want is possible in theory, but you may run into limitations trying to wrangle this all into Rust (as I'm sure the egui folks did as they designed APIs in Rust too!)

view this post on Zulip code red art (Feb 01 2023 at 01:07):

Few wasm guests have native support for funcref

can rust as a guest turn a closure into funcref?

view this post on Zulip Alex Crichton (Feb 01 2023 at 01:09):

a funcref is akin to a function pointer, so no, it doesn't have data associated with that. If you need data then you would need to forward that along through arguments

view this post on Zulip Jakob Lilliemarck (Feb 01 2023 at 07:24):

Is there any way you could pass a more complex type to a host function or set it on the store from within the wasm module? What's really the "standard" way to get data back from a module when running it with wasmtime? Just beeing able to pass a json-serialized string in between would be a huge benefit.

I did attempt to pipe stdout as described in the link @Dan Gohman was kind enough to provide, but without luck. After dropping the store and printing the contents there was just an empty vector. Will it pipe return-values from the functions in wasm or should I explicitly write to stdout from inside the module like io::stdout().write_all(b"hello world")?;?

view this post on Zulip Ramon Klass (Feb 01 2023 at 12:35):

you most likely would want to use interface types and optimally the component model, but I would honestly suggest to give them air to breathe, the way in which you load and call complex functions (returning more than u32) is being fleshed out right now, Dan mentioned he thinks he should have a working example to showcase around March :)

view this post on Zulip Jakob Lilliemarck (Feb 02 2023 at 06:50):

Ramon Klass said:

you most likely would want to use interface types and optimally the component model, but I would honestly suggest to give them air to breathe, the way in which you load and call complex functions (returning more than u32) is being fleshed out right now, Dan mentioned he thinks he should have a working example to showcase around March :)

I see, wow, that's a fantastic spec! Looking forward to see that in place :)

In the meantime, i suppose reading/writing into shared memory would be the way to go to pass more complex types in between rust and wasm? I'm thinking I may give that a go for now. I found the wasmtime Memory documentation, so I can probably figure out how to pass stuff in and how to read them out - but I'm not sure how to interact with the memory inside the wasm module - grateful for any tips that might help

Repository for design and specification of the Component Model - component-model/Explainer.md at main · WebAssembly/component-model

view this post on Zulip Jakob Lilliemarck (Feb 02 2023 at 07:35):

This looks like an example of reading/writing to a shared memory buffer - right?
https://wasmbyexample.dev/examples/webassembly-linear-memory/webassembly-linear-memory.rust.en-us.html


Last updated: Oct 23 2024 at 20:03 UTC