menu

Wasmer

Wasmer is a organization dedicated to the advancement and development of WebAssembly through open-source software.

Channels
Team

Is it possible to call a WASM callback from Rust?

March 6, 2019 at 4:09am

Is it possible to call a WASM callback from Rust?

March 6, 2019 at 4:09am

You are all probably getting tired of my questions, so apologies in advance. My question is very similar to this one, but of course I'm looking for the Wasmer version of the solution:

https://stackoverflow.com/q/45387728

It's maybe a little difficult to describe because both sides are Rust. On the "host" side, which is embedding the VM, I want to receive a pointer to a function implemented on the WASM "app" side, and somehow lookup and dispatch that function from the host side. (The WASM function could be an export, but I guess ideally it wouldn't need to be.)

It might look something like this:

// set_callback: (callback: extern fn(x: u32) -> ()) -> ()
pub fn set_callback(ctx: &mut Ctx, callback_ptr: u32) {
// Somehow lookup callback_ptr in a table?
ctx.get_func(callback_ptr).call(123);
}

It seems that for web browsers, you can look up functions like these from a table, as explained in that Stack Overflow answer. I've been looking around, and I've found Instance::{func, dyn_func} but I'm not sure those are quite right for what I want. (Also, is it possible to get an instance from a context?)

I also noticed an __indirect_function_table in the WAST, but so far I haven't found any mention of this in the Wasmer source.


March 6, 2019 at 6:17pm

Yep, this is possible, but we haven't exposed an easy way to do it. To do so, the Ctx type has to have a method that exposed a table (like the memory method). I'm currently caught up in some other stuff for the next few days, but we'd be happy to merge any PRs if you'd like the functionality before we have time to implement it.

like-fill
1
  • reply
  • like

March 7, 2019 at 2:19am

Ok, cool, I'm going to give it a shot. I'm working on putting together a talk for a meetup. So I'm definitely motivated, I'm trying to finish the demo. :-)

  • reply
  • like

Awesome! Shoot us a link to the recording of the meetup if there is one afterwards!

  • reply
  • like

Ok, I'm feeling a bit stuck at the moment. I've got to the point where I have a vm::Anyfunc, but it doesn't seem like there's a way to call it. It seems like maybe I need to create a typed Func from the pointer and context? Which looks like it would need an ExternalFunction... but I'm not sure how to get that from the vm::Anyfunc. Any advice?

like-fill
1
  • reply
  • like

I think probably the best path is to add a "get" method that returns an Element.

  • reply
  • like

I'm not sure what's the best way to convert back though

  • reply
  • like

When's the meetup?

  • reply
  • like

Okay, I have an idea. So, the vm::Anyfunc type contains the function pointer, the signature id, and the context that should be used to call that function. We can construct a dyn func from that. There isn't a way exposed for that, but it shouldn't be too hard to add.

like-fill
1
  • reply
  • like

You can lookup the function signature from the signature id using the SigRegistry type

  • reply
  • like

Ok, that sounds like a plan.

  • reply
  • like

I'll work on that tomorrow. I need to sleep for now.

  • reply
  • like

Ideally, it'd be useful to convert the index of a table into either a DynFunc or a Func, depending on the specific usecase, but that's more of an optimization step later.

  • reply
  • like

Sounds good!

  • reply
  • like

The meetup is next week, but don't worry, I have a fallback.

  • reply
  • like

Basically there is a "publisher" and a "subscriber", the publisher is done but the subscriber requires this callback mechanism. But I can always just use the native version of the subscriber.

  • reply
  • like

So that should prove the concept anyway.

  • reply
  • like

This will definitely be functional by then, don't worry!

  • reply
  • like

I'm trying to get both running in Wasmer as a bonus.

  • reply
  • like

Cool, thanks again for your help!

  • reply
  • like

March 8, 2019 at 5:02am

So I was working on this some more and I think I hit a snag. DynFunc requires a reference to InstanceInner (enclosing it's lifetime) but there is no instance available from within the Ctx.

  • reply
  • like

But it looks like the protected call doesn't really need the instance, just an ImportBacking, which is available from the Ctx.

  • reply
  • like

So it looks like I might need to modify DynFunc to get this to work. Unless you have a better idea?

  • reply
  • like

March 9, 2019 at 10:53pm

Go ahead and modify dynfunc and we can see if that works with the api we want.

  • reply
  • like