instantiate_wasm is a function that instantiates a TB's Wasm binary, importing the functions as specified by its arguments. Following the header definition in wasm/tcg-target.c.inc, QEMU's memory is imported into the module as "env.memory", and helper functions are imported as "helper.<idx>".
The instantiated Wasm module is imported to QEMU using Emscripten's "addFunction" feature[1] which returns a function pointer. This allows QEMU to call this module directly from C code via that pointer. Since the subarray() method doesn't accept a BigInt value which is used for the 64bit pointer value, it is converted to a Number (i53) using bigintToI53Checked method of Emscripten. Although this conversion (64bit to 53bit) drops higher bits, the maximum memory size of the engine implementations is currently limited to 16GiB[2] so we can assume that the pointers are within the Number's range. Note that since FireFox 138, WebAssembly.Module no longer accepts a SharedArrayBuffer as input [3] as reported by Nicolas Vandeginste in my fork[4]. This commit ensures that WebAssembly.Module() is passed a Uint8Array created from the binary data on a SharedArrayBuffer. [1] https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#calling-javascript-functions-as-function-pointers-from-c [2] https://webassembly.github.io/memory64/js-api/#limits [3] https://bugzilla.mozilla.org/show_bug.cgi?id=1965217 [4] https://github.com/ktock/qemu-wasm/pull/25 Signed-off-by: Kohei Tokunaga <ktokunaga.m...@gmail.com> --- tcg/wasm.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tcg/wasm.c b/tcg/wasm.c index 4bc53d76d0..835167f769 100644 --- a/tcg/wasm.c +++ b/tcg/wasm.c @@ -25,6 +25,7 @@ #include "disas/dis-asm.h" #include "tcg-has.h" #include <ffi.h> +#include <emscripten.h> #define ctpop_tr glue(ctpop, TCG_TARGET_REG_BITS) @@ -44,6 +45,42 @@ __thread uintptr_t tci_tb_ptr; +#define EM_JS_PRE(ret, name, args, body...) EM_JS(ret, name, args, body) + +#define DEC_PTR(p) bigintToI53Checked(p) +#define ENC_PTR(p) BigInt(p) +#if defined(WASM64_MEMORY64_2) +#define ENC_WASM_TABLE_IDX(i) Number(i) +#else +#define ENC_WASM_TABLE_IDX(i) i +#endif + +EM_JS_PRE(void*, instantiate_wasm, (void *wasm_begin, + int wasm_size, + void *import_vec_begin, + int import_vec_size), +{ + const memory_v = new DataView(HEAP8.buffer); + const wasm = HEAP8.subarray(DEC_PTR(wasm_begin), + DEC_PTR(wasm_begin) + wasm_size); + var helper = {}; + const entsize = TCG_TARGET_REG_BITS / 8; + for (var i = 0; i < import_vec_size / entsize; i++) { + const idx = memory_v.getBigInt64( + DEC_PTR(import_vec_begin) + i * entsize, true); + helper[i] = wasmTable.get(ENC_WASM_TABLE_IDX(idx)); + } + const mod = new WebAssembly.Module(new Uint8Array(wasm)); + const inst = new WebAssembly.Instance(mod, { + "env" : { + "memory" : wasmMemory, + }, + "helper" : helper, + }); + + return ENC_PTR(addFunction(inst.exports.start, 'ii')); +}); + static void tci_write_reg64(tcg_target_ulong *regs, uint32_t high_index, uint32_t low_index, uint64_t value) { -- 2.43.0