JavaScript宿主导入函数能否访问WebAssembly实例导出的内存
结论
WebAssembly 原生 JavaScript API 完全支持你需要的「模块自身导出内存、导入的宿主函数可访问该内存」能力,无需修改模块改为从宿主导入内存。
实现方案
你要的能力和 Wasmtime 中Caller的能力完全对应,在 JS API 中有两种实现方式:
通用方案(支持模块start阶段调用导入函数)
只要导入的宿主函数使用普通函数声明(不要使用箭头函数,箭头函数会固定绑定外层this),函数运行时的this上下文会自动绑定到当前触发调用的 Wasm 实例上,你可以直接通过this.exports拿到该实例的所有导出项,包括模块自身导出的内存:
const importObject = { env: { print_string: function (ptr) { // 直接从当前实例导出项中拿到内存 const memBuffer = new Uint8Array(this.exports.memory.buffer); // 读取\0结尾的字符串 let strEnd = ptr; while (memBuffer[strEnd] !== 0) strEnd++; const result = new TextDecoder().decode(memBuffer.subarray(ptr, strEnd)); console.log(result); } } }; // 实例化Wasm模块 WebAssembly.instantiateStreaming(fetch('你的模块文件路径.wasm'), importObject) .then(res => { // 调用导出的main函数 res.instance.exports.main(); // 控制台输出 example })
简单方案(仅适用于实例化完成后才调用导入函数的场景)
如果你的模块不会在实例化阶段(也就是start段)调用导入的函数,可以用更直观的变量占位方式实现:
// 提前声明内存占位变量 let wasmMemory = null; const importObject = { env: { print_string: (ptr) => { const memBuffer = new Uint8Array(wasmMemory.buffer); let strEnd = ptr; while (memBuffer[strEnd] !== 0) strEnd++; const result = new TextDecoder().decode(memBuffer.subarray(ptr, strEnd)); console.log(result); } } }; WebAssembly.instantiateStreaming(fetch('你的模块文件路径.wasm'), importObject) .then(res => { // 实例化完成后将模块导出的内存赋值给占位变量 wasmMemory = res.instance.exports.memory; // 此时调用main函数,导入的print_string已经可以正常访问内存 res.instance.exports.main(); })
内容的提问来源于stack exchange,提问作者Valmir Junior
相关产品推荐
相关产品推荐

