目前 WebAssembly 只定义了基本的数字类型来在 JS 和 WASM 之间进行通信。没有对象类型也没有数组类型。 This is the WebAssembly's design goal. Emscripten 已经做了一些技巧来制作 C++ 类 JS 绑定,但它们不是 WASM 标准。
WebAssembly.Memory()
但是有一种方法可以获取数组。 JS 可以直接访问 WASM 模块的内部存储器,即使没有 API。 WASM 有一个线性内存模型,线性内存通过WebAssembly.Memory() 接口。 WebAssembly.Memory() 是单个 ArrayBuffer WebAssembly.Memory.buffer,您的 WASM 模块在其中用作堆内存区域以及发生内存分配(例如 malloc())的位置。
1。作为 UInt8Array 访问它
这是什么意思?这意味着您从getPtr() 获得的指针(JS 端的整数)实际上是到WebAssembly.Memory.buffer 的偏移量。
Emscripten 自动生成创建 WebAssembly.Memory() 的 JS(这是从名为 preamble.js 的模板生成的)代码。你可以自己搜索Emscripten生成的代码,应该能找到类似to this line的一行:
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE });
所以你可以通过Module['wasmMemory'].buffer访问你的WASM模块使用的ArrayBuffer:
let instance = new Module.MyClass();
// ... Do something
let ptr = instance.getPtr();
let size = instance.getLength();
// You can use Module['env']['memory'].buffer instead. They are the same.
let my_uint8_buffer = new Uint8Array(Module['wasmMemory'].buffer, ptr, size);
2。 Emscripten HEAPU8
另外,Emscripten 提供an official way to access the heap memory region as typed arrays:HEAPU8、HEAPU16、HEAPU32 等定义为here。所以你可以这样做:
let instance = new Module.MyClass();
// ... Do something
let ptr = instance.getPtr();
let size = instance.getLength();
let my_uint8_buffer = new Uint8Array(Module.HEAPU8.buffer, ptr, size);
使用HEAPU8 会更安全,因为HEAPU8 已记录在案,而Module['wasmMemory'] 的属性名称未记录在案,可能会发生变化;但他们做同样的事情。
3。使用 emscripten::val(仅限 C++)
Emscripten 还提供了一个名为 emscripten::val 的类,供 C++ 开发人员在 JS 和 C++ 之间进行交互。为了方便起见,这抽象了任何 JS/C++ 类型。你可以使用这个来获取数组。
这是取自 the documentation 和 Glenn 评论的示例:
#include <emscripten/bind.h>
#include <emscripten/val.h>
emscripten::val getInt8Array() {
return emscripten::val(
emscripten::typed_memory_view(buffer->size(),
buffer->data()));
}
EMSCRIPTEN_BINDINGS() {
function("getInt8Array", &getInt8Array);
}
然后可以在JS端调用getInt8Array()获取类型化数组。
结论
这里建议使用 3 个选项从 WASM 获取数组。无论如何,我认为您应该了解WebAssembly.Memory 的概念以及选项 1 背后的内容,因为这是从 WASM 获取数组的最低级别,而且,最重要的是,这是非托管和不安全的内存访问,所以在 C/C++ 端释放或修改对象时很容易损坏数据。对于这种特定情况,需要了解低级含义。