运行存储在 Wasm 模块中的 JS 代码的简单方法



从导入的函数("计算器"(中,如何计算存储在WASM内存中的字符串?字符串告诉"评估器"在浏览器中做什么。

简单的答案是导入将指针指向内存并调用eval的函数

简单的"评估器"实现:

Evaluator: function(ptr) {
eval(UTF8ToString(ptr));
},

它只需要 2 种方法:

  • Evaluator()
  • UTF8ToString()

有没有更好的不使用eval的方法?

编辑:"评估器"功能应:

  • 尽可能瘦
  • 不使用eval

存储在Wasm模块内存中的字符串可以是任何东西。

我不认为这是你想要的答案,但它是你提出的问题的答案。因此,如果这不是您想要的答案,请问一个新问题

这是一些 WebAssembly 文本格式的 WebAssembly

(module
(func $i (import "imports" "imported_func") (param i32))
(func (export "exported_func")
i32.const 42
call $i
)
)
  • 它导入一个名为"imported_func"的JavaScript函数。

  • 它导出一个名为"exported_func"的wasm函数。

  • "exported_func"用42称"imported_func">

要使用它,需要将其转换为 Web 程序集二进制格式。我使用了wat2wasm工具。它给了我这些数据

0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60,
0x01, 0x7f, 0x00, 0x60, 0x00, 0x00, 0x02, 0x19, 0x01, 0x07, 0x69, 0x6d,
0x70, 0x6f, 0x72, 0x74, 0x73, 0x0d, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74,
0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x00, 0x00, 0x03, 0x02, 0x01,
0x01, 0x07, 0x11, 0x01, 0x0d, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65,
0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x00, 0x01, 0x0a, 0x08, 0x01, 0x06,
0x00, 0x41, 0x2a, 0x10, 0x00, 0x0b, 0x00, 0x14, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x01, 0x04, 0x01, 0x00, 0x01, 0x69, 0x02, 0x07, 0x02, 0x00, 0x01,
0x00, 0x00, 0x01, 0x00

为了正常使用它,我们会存储该数据的二进制版本,然后fetch它,但为了简单起见,我们将它直接放入 JavaScript 中,将其加载为 wasm 模块,为它传递一个函数"imported_func"然后调用它"exported_func"。

async function main() {
const wasmModule = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60,
0x01, 0x7f, 0x00, 0x60, 0x00, 0x00, 0x02, 0x19, 0x01, 0x07, 0x69, 0x6d,
0x70, 0x6f, 0x72, 0x74, 0x73, 0x0d, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74,
0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x00, 0x00, 0x03, 0x02, 0x01,
0x01, 0x07, 0x11, 0x01, 0x0d, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65,
0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x00, 0x01, 0x0a, 0x08, 0x01, 0x06,
0x00, 0x41, 0x2a, 0x10, 0x00, 0x0b, 0x00, 0x14, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x01, 0x04, 0x01, 0x00, 0x01, 0x69, 0x02, 0x07, 0x02, 0x00, 0x01,
0x00, 0x00, 0x01, 0x00,
]);
const importObject = {
imports: {
imported_func: (v) => {
console.log('js called from wasm:', v);
},
},
};
// create the webassembly
const {instance} = await WebAssembly.instantiate(wasmModule, importObject);
// get the web assembly function
const { exported_func } = instance.exports;
// call the wasm fucntion
exported_func();
}
main();

那就是WebAssembly。有一些编译器可以编译可以生成WebAssembly的其他语言。Emscripten 接收C++并生成 WebAssembly。Rust 用一些额外的工具可以生成 WebAssembly。如何通过 escripten 从C++调用 JavaScript 或如何从 Rust 调用 JavaScript 将是一个不同的问题。这些语言和编译器中的每一种都定义了自己调用 JavaScript 的方式。这不是如何从 WebAssembly 调用 JavaScript,而是从这些编译器调用 JavaScript。上面的答案是如何从 WebAssembly 调用 JavaScript。

更新

wasm 对 JavaScript 一无所知。甚至它的宿主环境(可能是Go,可能是Python等(。它所做的只是您可以在wasm模块中调用函数,并且可以传入要从wasm模块调用的函数。

通常,如果你想让wasm调用到宿主语言,你会单独用宿主语言编写函数,以便可以编译它们(在加载时或编译时(

对于可以在运行时解析和编译的语言,您可以在wasm中嵌入字符串,然后调用您编写的某个函数来获取该字符串并对其进行处理。一个例子

function helperForWasm(str) {
return eval(str);
}

现在,如果您像上面示例一样连接代码,您将获得评估结果str

另一个例子

const idToJavaScript = {};
function helperForPreEvaluatingJavaScript(id, js) {
idToJavaScript[id] = eval(js);
}
function helperForCallingFuncById(id, arg1, arg2, arg3) {
idToJavaScript[id](arg1, arg2, arg);
}

现在你有 2 个函数可以从 wasm 调用。第一个evaljs 字符串并分配结果。如果该字符串类似于

'(function(v) { return v * 2; })'  // outer parens required

然后,在使用第一个函数进行评估后,您可以使用第二个函数调用它

你也可以做一些类似的事情(伪代码(

function helperForLoadingJavaScriptFromString(js) {
const blob = new Blob([js], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
import(url).then((jsModule) => {
// communicate jsModule entry points to wasm
});
}

现在用完整的源代码来调用它 JavaScript 模块作为字符串。如何将模块中的入口点传达回wasm取决于您。

相关内容

  • 没有找到相关文章

最新更新