如何从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.Memorybuffer (这是一个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的函数,你会看到输出。 对于这种情况, 请检查这个库 。