加载和运行 WebAssembly 代码 我试过了没成功,代码裁剪有点严重
加载WebAssembly的两个新的API
新的 WebAssembly.compileStreaming/WebAssembly.instantiateStreaming 方法更加高效——它们直接在来自网络的原始字节流上执行操作,省去了 ArrayBuffer 步骤。
老的 WebAssembly.compile/WebAssembly.instantiate 方法要求你在获取原始字节之后创建一个包含了你的 WebAssembly 模块二进制的 ArrayBuffer,然后编译/实例化它。这类似于 new Function(string),只不过我们用字节数组缓冲区(WebAssembly 源码)替换了字符串(JavaScript 源码)。
调用时候的报错
环境是vite启动的服务
axios({
url: '/test.wasm', // 拷贝文件到public
method: '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=0
var 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=0
var 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>
// 别人代码给的一点启发 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
// }