为了账号安全,请及时绑定邮箱和手机立即绑定

如何从WebAssembly函数返回JavaScript字符串

如何从WebAssembly函数返回JavaScript字符串

郎朗坤 2019-11-30 13:58:43
如何从WebAssembly函数返回JavaScript字符串?下列模块可以用C(++)编写吗?export function foo() {  return 'Hello World!';}另外:我可以将其传递给JS引擎进行垃圾回收吗?
查看完整描述

3 回答

?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

WebAssembly本身不支持字符串类型,它,而支撑件i32/ i64/ f32/ f64 值类型以及i8/ i16用于存储。


您可以使用以下方法与WebAssembly实例进行交互:


exports,您可以从JavaScript中调用WebAssembly,然后WebAssembly返回单个值类型。

imports 其中WebAssembly调用JavaScript,并具有所需的任意数量的值类型(注意:必须在模块编译时知道计数,这不是数组,也不是可变参数)。

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()。


完成后,您需要获取字符串大小+内存中的索引,您还可以通过导出将其公开:


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位值,因此我假设字符串是ASCII。那就是std::string给你的东西(内存中的索引就是.c_str()返回的东西),但是要暴露其他东西(例如UTF-8),您需要使用支持UTF-8的C ++库,然后自己从JavaScript中读取UTF-8,获得代码点,然后使用String.fromCodePoint。


您还可以依靠以null终止的字符串,我在这里没有这样做。


您也可以使用TextDecoderAPI,一旦它获得更广泛的浏览器中创建一个ArrayBufferView到WebAssembly.Memory的buffer(这是ArrayBuffer)。


相反,如果您正在执行从WebAssembly到JavaScript的日志记录等操作,则可以公开Memory上述内容,然后从WebAssembly声明一个导入,该导入以size + position调用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的JavaScript Memory.prototype.grow或使用grow_memory操作码),则内存将ArrayBuffer被清除,您需要重新创建。


垃圾收集器:WebAssembly.Module/ WebAssembly.Instance/ WebAssembly.Memory是由JavaScript引擎收集到的所有垃圾,但是这是一个相当大的锤子。您可能希望使用GC字符串,而对于位于中的对象,目前尚无法实现WebAssembly.Memory。我们已经讨论了将来增加GC支持的问题。


查看完整回答
反对 回复 2019-11-30
?
哆啦的时光机

TA贡献1779条经验 获得超6个赞

有一种更简单的方法可以做到这一点。首先,您需要二进制文件的实例:


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),则几乎在该对象的顶部,您将看到function AsciiToString。从C ++传递您的函数,该函数返回字符串,您将看到输出。对于这种情况,请查看此库。


查看完整回答
反对 回复 2019-11-30
  • 3 回答
  • 0 关注
  • 735 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号