Reputation: 57
From imported function ("Evaluator"), how do I evaluate strings that is stored in WASM memory? String tells to "Evaluator" what to do in browser.
Trivial answer is to import function that takes pointer to memory and calls eval
Trivial "Evaluator" implementation :
Evaluator: function(ptr) {
eval(UTF8ToString(ptr));
},
It requires only 2 methods:
Evaluator()
UTF8ToString()
Is there any better method that doesn't use eval
?
EDIT: "Evaluator" function should :
eval
String stored in Wasm module memory can be anything.
Upvotes: 2
Views: 1737
Reputation:
I don't think this is the answer you want but it is the answer to the question you asked. So if this is not the answer you wanted then ask a new question
Here's some WebAssembly in WebAssembly text format
(module
(func $i (import "imports" "imported_func") (param i32))
(func (export "exported_func")
i32.const 42
call $i
)
)
It imports a JavaScript function called "imported_func".
It exports a wasm function called "exported_func".
"exported_func" calls "imported_func" with 42
To use that it needs to be converted to web assembly binary format. I used the wat2wasm
tool. It gave me this data
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
To use it normally we'd store the binary version of that data then fetch
it but to keep it simple I'll we'll just put it in the JavaScript directly, load it as a wasm module, pass it a function for "imported_func" then call it's "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();
That is WebAssembly. There are compilers that compile other languages that can generate WebAssembly. Emscripten takes C++ in and generates WebAssembly. Rust with some extra tooling can generate WebAssembly. How to call JavaScript from C++ via escripten or how to call JavaScript from Rust would be a different questions. Each of those languages and compilers define their own ways to call JavaScript. That's not how to call JavaScript from WebAssembly though, that' show to call JavaScript from those compilers. The answer above is how to call JavaScript from WebAssembly.
wasm has no knowledge of JavaScript. Nor even its host environment (could be Go, could be Python, etc ...). All it does is you can call functions in a wasm module and you can pass in functions to be called from the wasm module.
Normally if you wanted to have wasm call into the host language you'd write functions in the host language separately so they can be compiled (at load time or compile time)
For languages that can parse and compile at runtime you can embed strings in wasm and then call out to some function you write to take that string and do something with it. One example
function helperForWasm(str) {
return eval(str);
}
Now if you connect the code like the example above you'd get he result of evaluating str
Another example
const idToJavaScript = {};
function helperForPreEvaluatingJavaScript(id, js) {
idToJavaScript[id] = eval(js);
}
function helperForCallingFuncById(id, arg1, arg2, arg3) {
idToJavaScript[id](arg1, arg2, arg);
}
Now you have 2 functions you can call from wasm. The first eval
s a js string and assigns the result. If that string is something like
'(function(v) { return v * 2; })' // outer parens required
Then after being evaluated using the first function you could call it using the second
You could also do something like (pseudo code)
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
});
}
Now call that with full source to JavaScript modules as strings. How you communicate the entries points into the module back to wasm is up to you.
Upvotes: 4