如何从WebAssembly函数返回JavaScriptstring?
如何从WebAssembly函数返回JavaScriptstring?
下面的模块可以写成C(++)吗?
export function foo() { return 'Hello World!'; }
另外:我可以通过这个JS引擎垃圾收集?
WebAssembly本身不支持stringtypes,而是支持i32
/ i64
/ f32
/ f64
值types以及i8
/ i16
存储。
您可以使用以下方式与WebAssembly实例进行交互:
-
exports
,从JavaScript调用WebAssembly,WebAssembly返回一个值types。 - WebAssembly调用到JavaScript中的导入,具有任意数量的值types(注意:必须在Module编译时知道该计数,这不是数组,也不是可变参数)。
-
Memory.buffer
,这是一个ArrayBuffer
,可以使用(其他)Uint8Array
索引。
这取决于你想做什么,但似乎直接访问缓冲区是最简单的:
const bin = ...; // WebAssembly binary, I assume below that it imports a memory from module "imports", field "memory". const module = new WebAssembly.Module(bin); const memory = new WebAssembly.Memory({ initial: 2 }); // Size is in pages. const instance = new WebAssembly.Instance(module, { imports: { memory: memory } }); const arrayBuffer = memory.buffer; const buffer = new Uint8Array(arrayBuffer);
如果你的模块有一个start
函数,那么它在实例化的时候被执行。 否则,你可能会有一个你调用的导出,例如instance.exports.doIt()
。
一旦完成,您需要在内存中获取string大小+索引,您还可以通过导出来显示该索引:
const size = instance.exports.myStringSize(); const index = instance.exports.myStringIndex();
然后你会读出缓冲区:
let s = ""; for (let i = index; i < index + size; ++i) s += String.fromCharCode(buffer[i]);
请注意,我正在从缓冲区中读取8位值,因此我假定string是ASCII。 这就是std::string
会给你(内存中的索引将是.c_str()
返回),但是要暴露其他的东西,如UTF-8,你需要使用支持UTF-8的C ++库,然后阅读UTF-8自己从JavaScript中获取代码点,并使用String.fromCodePoint
。
你也可以依靠string被空终止,我没有在这里做。
通过在WebAssembly.Memory
的buffer
(这是一个ArrayBuffer
)中创build一个ArrayBufferView
您也可以在浏览器中使用TextDecoder
API 。
相反,如果您正在做WebAssembly到JavaScript的日志logging,那么您可以像上面那样公开Memory
,然后从WebAssembly中声明一个调用JavaScript的导入,并调用大小为+的位置。 你可以实例化你的模块:
const memory = new WebAssembly.Memory({ initial: 2 }); const arrayBuffer = memory.buffer; const buffer = new Uint8Array(arrayBuffer); const instance = new WebAssembly.Instance(module, { imports: { memory: memory, logString: (size, index) => { let s = ""; for (let i = index; i < index + size; ++i) s += String.fromCharCode(buffer[i]); console.log(s); } });
这有个警告,如果你增长了内存(通过JavaScript使用Memory.prototype.grow
,或者使用grow_memory
操作码),那么ArrayBuffer
就会被grow_memory
,你需要重新创build它。
在垃圾收集上: WebAssembly.Module
/ WebAssembly.Instance
/ WebAssembly.Memory
都是由JavaScript引擎收集的垃圾,但这是一个相当大的锤子。 您可能想要GCstring,而这对于WebAssembly.Memory
内部的对象来说目前是不可能的。 我们已经讨论过未来添加GC支持 。
有一个更简单的方法来做到这一点。 首先,你需要你的二进制的实例:
const module = new WebAssembly.Module(bin); const memory = new WebAssembly.Memory({ initial: 2 }); const instance = new WebAssembly.Instance(module, { imports: { memory: memory } });
然后,如果你运行console.log(instance)
,几乎在这个对象的顶部,你会看到函数AsciiToString
。 从C ++返回string的函数,你会看到输出。 对于这种情况, 请检查这个库 。