3

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.

2
  • What's your goal exactly? You still don't want to use Emscripten to import the JS function? As a note, it's not a hack. Emscripten doesn't create a new wasm module neither. Commented Aug 18, 2019 at 2:18
  • @BumsikKim My goal is to be able to call a JavaScript function as a function pointer from C. 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. I'm not currently using Emscripten nor do I want to. Commented Aug 19, 2019 at 6:14

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

My problem is that tables seem to be designed for getting function pointers out of wasm and into JS rather than the other way around like I want. The value passed to a table's set method must be an exported wasm function. So I can't just push a JS function into a table. Since I asked this question I've been using the method that I discovered viewing the emscripten source. I create a tiny module that imports a JS function and exports it back out so I can insert it into a table. This works. It just feels like the JS API is missing functionality to nicely handle this situation.
@Ghillie They're designed to go both ways. There are just a lot of new features that haven't hit the implementations yet. Ideally you can use new WebAssembly.Function({ type descriptor }, fn), but i don't think anything has it yet.
Is there a place I can track the progress of upcoming features such as that one? I saw a comment inside the emscripten source about the possibility of getting the WebAssembly.Function constructor some day. I couldn't find any other information on it though. And thank you for taking the time to answer this. I'll go ahead and accept this answer.
0

You can checkout this simple generator with helps with function exported by emscripten

https://libamtrack.github.io/c2JsGenerator/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.