从JavaScript调用WebAssembly中的C样式函数指针 [英] Calling a C style function pointer in a WebAssembly from JavaScript

查看:132
本文介绍了从JavaScript调用WebAssembly中的C样式函数指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法访问生活在WebAssembly模块中的函数指针?

Is there any way to get access to function pointers living inside a WebAssembly module?

例如,给定以下编译为WebAssembly的模块:

For example, given the following "module" compiled to WebAssembly:

extern void set_callback(void (*callback)(void *arg), void *arg);

static void callback(void *arg)
{
  /* ... */
}

int main() {
  set_callback(&callback, 0);
  return 0;
}

可以实现 do_callback 在JavaScript中调用回调而不必依赖中间C函数导出来进行实际的函数调用?

Can an implementation of do_callback in JavaScript invoke the callback without having to rely on an intermediary C function export to do the actual function call?

var instance = new WebAssembly.Instance(module, {
  memory: /* ... */
  env: {
    set_callback: function set_callback(callbackptr, argptr) {
      // We only got the pointer, is there any  
    },
  },
}); 

通过中间函数导出,我的意思是我可以添加一个具有公共可见性的内部函数。

By intermediary function export, I mean that I could add an internal function with public visibility.

do_callback(void (*callback)(void *arg), void *arg)
{
  callback();
} 

然后JavaScript set_callback function可以通过委托 do_callback 函数调用函数指针。

Then the JavaScript set_callback function can call the function pointer via the delegate do_callback function.

function set_callback(callbackptr, argptr) {
  instance.exports.do_callback(callbackptr, argptr);
}

但是,最好这样做而不必经过那个明确的间接,可能,功能表可能吗?

But, it's preferable to do this without having to go through that explicit indirection, is it possible, with function tables maybe?

推荐答案

你可以从Javascript调用函数指针。

You can invoke function pointers from Javascript.

函数指针存储在表中。当函数指针传递给Javascript时,您将在表中接收该函数指针的整数索引。将该索引传递给 Table.prototype.get(),然后您可以调用该函数。

Function pointers are stored in a Table. When a function pointer is passed to Javascript you are receiving the integer index into the table for that function pointer. Pass that index to Table.prototype.get() and you can call the function.

...

set_callback: function set_callback(callbackptr, argptr) {
  tbl.get(callbackptr)(argptr);
},

...

您可以阅读更多关于这个在这个MDN页面下的表格部分:
https ://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API#Tables

You can read more about this on this MDN page under the Tables section: https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API#Tables

编辑:这是我用来测试这个的最小例子。

Here is the minimal example I used to test this.

第一个文件是 fptr.c 用<$ c $编译c> emcc fptr.c -Os -s WASM = 1 -s SIDE_MODULE = 1 -o fptr.wasm

typedef int (*fptr_type)(void);

extern void pass_fptr_to_js(fptr_type fptr);

static int callback_0(void)
{
    return 26;
}

static int callback_1(void)
{
    return 42;
}

void run_test()
{
    pass_fptr_to_js(callback_0);
    pass_fptr_to_js(callback_1);
}

这里是 fptr.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebAssembly Experiment</title>
</head>
<body>
    <h3>Check the console.</h3>
    <script type="text/javascript">
        fetch('fptr.wasm').then(function(response) {
            response.arrayBuffer().then(function(buffer) {
                WebAssembly.compile(buffer).then(function(module) {
                    var imports = {};

                    imports.env = {};

                    imports.env.memoryBase = 0;
                    imports.env.memory = new WebAssembly.Memory({ initial: 256 });
                    imports.env.tableBase = 0;
                    imports.env.table = new WebAssembly.Table({ initial: 4, element: 'anyfunc' });

                    imports.env["abort"] = function() {
                        console.error("ABORT");
                    };

                    imports.env["_pass_fptr_to_js"] = function(fptr) {
                        console.log("table index: " + fptr + ", return value: " + imports.env.table.get(fptr)());
                    };

                    WebAssembly.instantiate(module, imports).then(function(instance) {
                        instance.exports["__post_instantiate"]();
                        instance.exports["_run_test"]();
                    });
                });
            });
        });
    </script>
</body>
</html>

这篇关于从JavaScript调用WebAssembly中的C样式函数指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆