Reputation: 909
I want to pass a JavaScript function as an argument to a function that has been exported from WebAssembly with a function pointer as a parameter.
Consider the following example:
JavaScript Code:
function foo() {
console.log("foo");
}
wasmInstance.exports.expects_funcptr(foo);
C Code:
typedef void(*funcptr_type)(void);
void expects_funcptr(funcptr_type my_funcptr)
{
my_funcptr();
}
I'm not using Emscripten, but they have a section on the topic in their "Interacting with code" page here: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-call-function-pointers-from-c. They have a function called addFunction
for this.
I took a look at its implementation here: https://github.com/emscripten-core/emscripten/blob/incoming/src/support.js#L755
And it seems quite... hacky. It looks like they are creating a new wasm module that takes the javascript function as an import and exports it as a wasm function. Only then are they able to add the function to a WebAssembly Table.
Is there a better way to do this?
EDIT:
Here's how I'm currently handling this. By using the following function to convert a JS function to WASM I can pass a JS function to WASM like this:
// How the above example would be called using the converter function.
wasmInstance.exports.expects_funcptr(convertFunction(foo, Types.VOID));
// The actual converter function (minus some details for simplicity)
function convertFunction(func, ret, params) {
// Construct a .wasm binary by hand
const bytes = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, // magic
0x01, 0x00, 0x00, 0x00, // version
// ... generate type, import, export sections as well
]);
const module = new WebAssembly.Module(bytes);
const instance = new WebAssembly.Instance(module, {
a: {
b: func
}
});
const ret = table.length;
table.grow(1);
table.set(ret, instance.exports.f);
return ret;
}
This is a crude example to show the concept. An actual implementation has checks if the function has already been converted, handles errors, etc.
Upvotes: 3
Views: 2296
Reputation: 72
You can checkout this simple generator with helps with function exported by emscripten
https://libamtrack.github.io/c2JsGenerator/
Upvotes: 0
Reputation: 2161
Function tables are the primitive for function pointers in Wasm. You will have to use one for function pointers. Managing this separate address space can be very tricky, and all the "hacky" code in emscripten is to make sure this is done safely. In your own code, you don't need to enforce as many of the invariants that emscripten does, so you can probably get rid of most of it. Happy to clarify this in the comments as well.
Upvotes: 1