javascript-如何在Rust和WebAssembly中解析函数指针
作者:互联网
我想为WebAssembly模块提供一个接受Rust函数指针的外部JavaScript函数.
初始化此JS模块后,它将从.wasm模块调用run()函数,然后依次调用peekaboo:
window.Module = {};
const imports = {
env: {
memoryBase: 0,
tableBase: 0,
memory: new WebAssembly.Memory({ initial: 256 }),
table: new WebAssembly.Table({ initial: 4, element: 'anyfunc' })
}
};
imports.env.peekaboo = function(f) {
const fn = imports.env.table.get(f);
return fn(2);
};
fetch('game.wasm')
.then(response => response.arrayBuffer())
.then(bytes => WebAssembly.compile(bytes))
.then(mod => WebAssembly.instantiate(mod, imports))
.then(mod => {
mod.exports.run();
Module.memory = imports.env.memory;
Module.dealloc_str = mod.exports.dealloc_str;
});
我看到的示例表明,如果我以这种方式导入内存,则应该能够使用表来解析函数指针.这是Rust代码:
#![feature(wasm_import_memory)]
#![wasm_import_memory]
extern "C" {
fn peekaboo(f: fn(u32) -> u32);
}
fn main() {}
#[no_mangle]
pub fn run() {
let plus_one = |x: u32| -> u32 { x + 1 };
unsafe {
peekaboo(plus_one);
}
}
一切都可以正常编译,但是当我执行peekaboo函数时,fn变量为null,表明表无法找到函数指针.因此,执行fn(2)会导致:
Uncaught (in promise) TypeError: fn is not a function
我或多或少遵循了this example,但是由于我在Rust中工作,所以翻译不是一对一的.我怀疑我忽略了一些对我来说并不明显的东西,因为我对Rust和WebAssembly都是新手.谁能发现我的错误?
解决方法:
到目前为止,Rust中的WebAssembly后端似乎还没有提供导入或导出(功能)表的方式;索引f很好,但是import.env.table与wasm实例使用的表不同(即为空).
另外,您应该在FFI中使用extern fn.
如果您想了解一下Playground提供了一些不错的WebAssembly优化,请查看以下示例:
#![crate_type = "cdylib"]
#![feature(link_args)]
#![allow(unused_attributes)] // link_args actually is used
#![link_args = "--import-memory"]
extern "C" {
fn peekaboo(f: extern "C" fn(u32) -> u32);
}
#[no_mangle]
pub fn run() {
extern "C" fn plus_one(x: u32) -> u32 {
x + 1
}
unsafe {
peekaboo(plus_one);
}
}
结果应如下所示:
(module
(type $t0 (func))
(type $t1 (func (param i32) (result i32)))
(type $t2 (func (param i32)))
(import "env" "peekaboo" (func $peekaboo (type $t2)))
(import "env" "memory" (memory $env.memory 17))
(func $run (export "run") (type $t0)
(call $peekaboo
(i32.const 1)))
(func $playground::run::plus_one::h85275af105f0cc85 (type $t1) (param $p0 i32) (result i32)
(i32.add
(get_local $p0)
(i32.const 1)))
(table $T0 2 2 anyfunc)
(elem (i32.const 1) $playground::run::plus_one::h85275af105f0cc85))
如果要在本地复制,请在Cargo.toml中添加:
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
并使用每晚构建货物–release –target wasm32-unknown-unknown进行构建(假设使用夜间工具链的rustup设置和为夜间工具链启用的wasm32-unknown-unknown目标).
标签:webassembly,rust,shared-memory,javascript,pointers 来源: https://codeday.me/bug/20191110/2014338.html