【发布时间】:2019-07-11 07:13:33
【问题描述】:
我有一段非常简单的 Typescript 代码可以解析特定的数据格式,输入是 UInt8Array。我已经尽可能地对其进行了优化,但我认为这个相当简单的解析器应该能够比我让它作为 JS 运行得更快。我想尝试使用 AssemblyScript 在 Web 汇编中编写它,以确保我没有遇到 Javascript 引擎的任何怪癖。
正如我现在所知道的,我不能只将 TypedArray 传递给 Wasm 并让它自动工作。据我了解,我可以将指针传递给数组,并且应该能够直接从 Wasm 访问它而无需复制数组。但我无法让它与 AssemblyScript 一起使用。
以下是一个最小示例,显示了我如何无法将 ArrayBuffer 传递给 Wasm。
设置 Wasm 导出的代码大部分来自自动生成的样板:
const fs = require("fs");
const compiled = new WebAssembly.Module(
fs.readFileSync(__dirname + "/build/optimized.wasm")
);
const imports = {
env: {
abort(msgPtr, filePtr, line, column) {
throw new Error(`index.ts: abort at [${line}:${column}]`);
}
}
};
Object.defineProperty(module, "exports", {
get: () => new WebAssembly.Instance(compiled, imports).exports
});
下面的代码调用了WASM,index.js就是上面的胶水代码。
const m = require("./index.js");
const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
const result = m.parse(data.buffer);
而编译成 WASM 的 AssemblyScript 如下:
import "allocator/arena";
export function parse(offset: usize): number {
return load<u8>(offset);
}
我在执行该代码时收到“RuntimeError: memory access out of bounds”。
主要问题是我从 Wasm 得到的错误对我自己解决这个问题没有帮助。我显然错过了这在幕后实际运作的一些主要方面。
如何使用 AssemblyScript 将 TypedArray 或 ArrayBuffer 从 JS 传递到 Wasm?
【问题讨论】:
-
offset是否应该是Unit8Array的属性?你想得到byteOffset吗?parse是否期望参数是Unit8Array或整数? -
@guest271314 ArrayBuffer 实际上并没有传递给 WASM,这就是我最初的想法。但是每次我尝试访问像数组长度这样的属性时,它都会抛出一个错误。据我了解,传递给 WASM 的只是一个指向内存中 ArrayBuffer 位置的指针。但我可能错了,虽然我很确定我是对的,真正的 ArrayBuffer 没有传入。
-
parse期望什么作为参数? -
@guest271314 我可以用来执行加载命令的内存地址。在真正的代码中,我会遍历数组,所以我也会传入长度。我尝试将参数视为 TypedArray,但没有奏效。据我所知,如果我传入一个 ArrayBuffer,我会得到一个指向 WASM 端数组的指针。
-
我不熟悉 AssemblyScript,但对 WASM 的 C/C++ 经验丰富。在您使用的任何语言中,您都不能传递数组对象,而是将其复制到 WAS 的堆区域。这是因为 WASM 严格禁止接触 WASM 堆之外的任何内存,并且 WASM 只能将 arrary 理解为一种类型,而只能理解为数字类型。在 WASM for C 中,你应该调用与 ArrayBuffer 大小相同的
malloc,将指针传递给 JS,然后将其转换为 Uint8Array,并使用 Uinit8Array.set() 方法将 ArrayBuffer 复制到 Uint8Array。真的没有别的办法了。我希望这会有所帮助。
标签: javascript typescript webassembly assemblyscript