ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javascript-如何在Rust和WebAssembly中解析函数指针

2019-11-10 18:34:19  阅读:44  来源: 互联网

标签:webassembly rust shared-memory javascript pointers



我想为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优化,请查看以下示例:

Playground

#![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

专注分享技术,共同学习,共同进步。侵权联系[admin#icode9.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有