2017-07-29 82 views
6

有什么方法可以访问WebAssembly模块内部的函数指针吗?从JavaScript调用WebAssembly中的C风格函数指针

例如,给出下面的“模块”编译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函数出口做实际的函数调用?

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

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

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

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

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

但是,最好做到这一点,而不必经过明确的间接,是否有可能,功能表也许呢?

回答

0

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

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

... 

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

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

第一个文件fptr.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> 
+0

尝试这个已经作为函数表的描述基本上是读作“这是一个函数指针表,使用它适用于C风格函数指针“,但将表传递给模块的导入描述符没有明显效果,并且表最终为空? –

+0

@CasperBeyer我编辑了我的文章,包括我用来测试这个工作示例。 – Ghillie

+0

如何让clang为没有Emscripten的表和内存生成导入?在链接器级别执行它?例如wasm-link与包含导入的“空”模块? –