bytecodealliance / wasmtime-dotnet

.NET embedding of Wasmtime https://bytecodealliance.github.io/wasmtime-dotnet/
Apache License 2.0
426 stars 50 forks source link

How to pass a function to WebAssembly? #251

Closed IS4Code closed 1 year ago

IS4Code commented 1 year ago

Hello, sorry if this is not the best place to ask; I have already asked on StackOverflow but nobody could help there.

I have a simple function compiled using the WASI SDK, intended to receive a function pointer to pass to another C library that is supposed to call it at a later time (and with an arbitrary signature):

__attribute__((export_name("add_func")))
void add_func(void* func) {
    // pass func to some other API expecting void*
}

When the compiled WASM module is loaded and executed, I want to dynamically create an arbitrary number of functions and pass them to add_func, in this manner:

Instance inst = ...;
var add_func = inst.GetAction<Function>("add_func");
add_func(Function.FromCallback(_store, (caller, arguments, results) => {
   ...
});

However, inst.GetAction<Function> returns null, and the only way to retrieve and call this function seems to be with an int parameter, like GetAction<int>.

How do I pass a function created in this way to WASM? I could not find any way to either change the signature of the function to allow funcref arguments, or to obtain the index of the created function (I reckon function pointers are indexes in WASM anyway).

peterhuene commented 1 year ago

I don't believe the WASI SDK supports passing functions via funcref parameters as Clang currently assumes function pointers are passed as indexes into a function table only.

I can't think of a way to accomplish what you'd like to do from C; it's possible to do what you want from handcrafted WebAssembly (e.g. the text format) by taking a funcref, setting the reference in a table, and then using call_indirect.

There might be some way to use wasm-ld together with some handcrafted Wasm object file to define add_func using funcrefs and link against your C code, but I don't know offhand if it's possible.

The reason GetAction<Function> is returning null is because the signature of the function is i32 for the void*, and any place you cast it to a function pointer will result in it being passed as the table index argument to call_indirect (the cast expression controls what type is used).

IS4Code commented 1 year ago

I see, that makes sense. Well, I guess I'll have to find another way for now. Thank you for the help!

xylobol commented 7 months ago

@IS4Code Sorry for the necro, but what did you end up doing?

IS4Code commented 7 months ago

@Xylobol Not much, I did not touch the project I wanted it for since, unfortunately.