在emscripten C中,我有
class MyClass {
public:
MyClass() {}
std::shared_ptr<std::vector<uint8_t>> buffer;
int getPtr() {
return (int)(buffer->data());
}
int getLength() {
return buffer->size();
}
};
EMSCRIPTEN_BINDINGS() {
class_<MyClass>("MyClass").constructor()
.function("getLength",&MyClass::getLength)
.function("getPtr",&MyClass::getPtr,
allow_raw_pointers());
}
我可以从JS调用getLength()和getPtr(),但我不知道如何让JS将它作为一个ArrayBuffer来下载为Blob.
如何以一种形式将缓冲区数据导入JS,然后我可以使用类似于https://github.com/kennethjiang/js-file-download/blob/master/file-download.js的代码下载它.
解决方法:
目前,WebAssembly只定义了JS和WASM之间通信的基本数字类型.没有Object类型和Array类型. This is the WebAssembly’s design goal. Emscripten做了一些黑客攻击使C Class< => JS绑定,但它们不是WASM标准.
WebAssembly.Memory()
但有一种方法可以获得阵列.即使没有API,JS也可以直接访问WASM模块的内部存储器. WASM具有线性内存模型,线性内存通过WebAssembly.Memory()
接口.WebAssembly.Memory()是单个ArrayBuffer WebAssembly.Memory.buffer
,其中WASM模块用作堆内存区域,并且内存分配(例如malloc())发生.
1.以UInt8Array的形式访问它
这是什么意思?这意味着从getPtr()获得的指针(JS方面的整数)实际上是WebAssembly.Memory.buffer的偏移量.
Emscripten自动生成JS(这是从名为preamble.js的模板生成)代码,用于创建WebAssembly.Memory().您可以自己搜索Emscripten生成的代码,并且应该能够找到类似于to this line的行:
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE });
因此,您可以通过Module [‘wasmMemory’]访问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还为C开发人员提供了一个名为emscripten::val
的类,以便在JS和C之间进行交互.为方便起见,这抽象了任何JS / C类型.您可以使用此方法获取阵列.
这是从the documentation和格伦的评论中得到的例子:
#include <emscripten/bind.h>
#include <emscripten/val.h>
emscripten::val getBytes() {
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++端释放或修改对象时损坏数据;对于这一具体案例,需要了解低级别影响.