加载和运行 WebAssembly 代码 我试过了没成功,代码裁剪有点严重
加载WebAssembly的两个新的API
新的 WebAssembly.compileStreaming/WebAssembly.instantiateStreaming 方法更加高效——它们直接在来自网络的原始字节流上执行操作,省去了 ArrayBuffer 步骤。
老的 WebAssembly.compile/WebAssembly.instantiate 方法要求你在获取原始字节之后创建一个包含了你的 WebAssembly 模块二进制的 ArrayBuffer,然后编译/实例化它。这类似于 new Function(string),只不过我们用字节数组缓冲区(WebAssembly 源码)替换了字符串(JavaScript 源码)。
调用时候的报错
环境是vite启动的服务
axios({url: '/test.wasm', // 拷贝文件到publicmethod: 'get',responseType: 'stream' // 响应返回stream的类型
}).then(async (res) => {
// WebAssembly.instantiateStreaming() 介绍
// 函数直接从流式底层源编译并实例化 WebAssembly 模块。这是加载 Wasm 代码的最有效、最优化的方式。 const module = await WebAssembly.instantiateStreaming(res.data,// importObject // 需要这个对象但mdn 没有给出来)console.log(module.instance.exports)
})
在胶水代码中找到的
var HEAP,
/** @type {!Int8Array} */HEAP8,
/** @type {!Uint8Array} */HEAPU8,
/** @type {!Int16Array} */HEAP16,
/** @type {!Uint16Array} */HEAPU16,
/** @type {!Int32Array} */HEAP32,
/** @type {!Uint32Array} */HEAPU32,
/** @type {!Float32Array} */HEAPF32,
/** @type {!Float64Array} */HEAPF64;
function _emscripten_memcpy_big(dest, src, num) {HEAPU8.copyWithin(dest, src, src + num);
}function _fd_write(fd, iov, iovcnt, pnum) {// hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0var num = 0;for (var i = 0; i < iovcnt; i++) {var ptr = HEAPU32[((iov)>>2)];var len = HEAPU32[(((iov)+(4))>>2)];iov += 8;for (var j = 0; j < len; j++) {printChar(fd, HEAPU8[ptr+j]);}num += len;}HEAPU32[((pnum)>>2)] = num;return 0;}var wasmImports = {"emscripten_memcpy_big": _emscripten_memcpy_big,"fd_write": _fd_write
};
var info = {'env': wasmImports,'wasi_snapshot_preview1': wasmImports,};const module = WebAssembly.instantiateStreaming(fetch('/test.wasm'),info).then(res=>{console.log(res)
})
_fd_write函数某个工具给出来的解释参考 感觉就是提取wasm里的被导出来的函数吧
这段代码是一个低级函数,其目的是模拟文件描述符(fd)上的写操作。这是通过遍历输入的iov(即输入的“I/O向量”)数组,并将其内容写入文件描述符fd来实现的。
让我们详细地分析一下这段代码:
iov 是一个指针,指向一个包含多个iovec结构的数组。每个iovec结构包含两个成员:一个指向数据的指针和该数据的长度。
iovcnt 是iov数组中的元素数量。
_fd_write 函数遍历iov数组,处理每个iovec,并将其内容写入文件描述符fd。
对于每个iovec,它首先获取数据的指针(即内存地址)和长度。然后,它使用这些信息从内存中读取数据,并将其逐个字符地写入文件描述符。
函数最后将写入的字符数存储在pnum指向的位置。
函数返回0,表示写操作成功完成。
注意:这个代码片段是用JavaScript写的,并且可能是模拟或模拟器的一部分,特别是针对系统级编程或低级编程。
另外,这段代码似乎是从更大的上下文中提取出来的,因为它引用了几个变量(如 HEAPU8 和 HEAPU32),这些变量在给定的代码片段中没有定义。这些变量可能是指向特定类型数组的指针,这些数组用于模拟系统级别的数据结构或内存布局。
控制台成功打印出对象包含了我导出的int_sqrt、main
较完整的代码
<script setup>
// import axios from 'axios'; // 用axios 请求的方式也可以
import { onMounted } from 'vue';onMounted(async ()=>{var HEAP,
/** @type {!Int8Array} */HEAP8,
/** @type {!Uint8Array} */HEAPU8,
/** @type {!Int16Array} */HEAP16,
/** @type {!Uint16Array} */HEAPU16,
/** @type {!Int32Array} */HEAP32,
/** @type {!Uint32Array} */HEAPU32,
/** @type {!Float32Array} */HEAPF32,
/** @type {!Float64Array} */HEAPF64;
function _emscripten_memcpy_big(dest, src, num) {HEAPU8.copyWithin(dest, src, src + num);
}function _fd_write(fd, iov, iovcnt, pnum) {// hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0var num = 0;for (var i = 0; i < iovcnt; i++) {var ptr = HEAPU32[((iov)>>2)];var len = HEAPU32[(((iov)+(4))>>2)];iov += 8;for (var j = 0; j < len; j++) {printChar(fd, HEAPU8[ptr+j]);}num += len;}HEAPU32[((pnum)>>2)] = num;return 0;}var wasmImports = {"emscripten_memcpy_big": _emscripten_memcpy_big,"fd_write": _fd_write
};
var info = {'env': wasmImports,'wasi_snapshot_preview1': wasmImports,};const module = await WebAssembly.instantiateStreaming(fetch('/test.wasm'),info).then(res=>{console.log(res)// console.log(res.instance.exports.int_sqrt(33)) 可以调用// res.instance.exports.main() // 不知道为什么main 函数调用不了})})
</script><template></template>
Emscripten胶水代码初探
// 别人代码给的一点启发 https://blog.csdn.net/wopelo/article/details/121597551// const importObject = {// env: {// // 需要提供一个中止函数,如果断言失败就会调用这个中止函数// abort(_msg, _file, line, column) {// console.error('abort called at index.ts:' + line + ':' + column)// }// },// wasi_snapshot_preview1: wasmImports// }