Не понимаю, как правильно использовать call_indirect.
При поиске в Интернете я обнаружил, что заставить указатели функций работать в веб-сборке нелегко. Адреса функций хранятся в таблице и в основном являются идентификаторами i32. Хорошо ... давайте кодировать!
Определить семантику в промежуточном представлении (файл call -irect.ll):
define i32 @call_indirect_method(i32 (i32, i32)* %callee, i32 %arg, i32 %arg2) {
%t = call i32 %callee(i32 %arg, i32 %arg2)
ret i32 %t
}
Написать программу (файл program.c):
#include <emscripten.h>
int EMSCRIPTEN_KEEPALIVE call_indirect_method();
int EMSCRIPTEN_KEEPALIVE sum(int a, int b)
{
return (a + b);
}
int EMSCRIPTEN_KEEPALIVE calc(int a, int b)
{
return call_indirect_method();
}
Связка js (index.js):
const fs = require("fs");
const raw_source = new Uint8Array(fs.readFileSync(`module.wasm`));
const wasm_module = new WebAssembly.Module(raw_source);
var table = new WebAssembly.Table({initial: 1, element: "anyfunc"});
var memory = new WebAssembly.Memory({initial: 1});
const _exp = new WebAssembly.Instance(wasm_module, {
"env": {
__memory_base: 0,
__table_base: 0,
memoryBase: 0,
tableBase: 0,
memory: memory,
table: table,
nullFunc_X: () => console.info("nullFunc_X()"),
jsCall_X: () => console.info("jsCall_X()"),
abort: err => {
throw new Error('abort ' + err);
},
abortOnCannotGrowMemory: err => {
throw new Error('abortOnCannotGrowMemory ' + err);
},
abortStackOverflow: err => {
throw new Error('abortStackOverflow ' + err); // Wellcome here if compile with -O0 level.
}
}
}).exports;
table.set(0, _exp._sum);
console.log(_exp._calc(1, 2)); // expect to be 3, got 0 instead
То, как я построил .wasm:
emcc -O1 -s WASM=1 -s SIDE_MODULE=1 -s ONLY_MY_CODE=1 -s FILESYSTEM=0 -s TOTAL_MEMORY=65536 -s TOTAL_STACK=1024 -s ENVIRONMENT='web' -s ALLOW_MEMORY_GROWTH=0 -s NO_EXIT_RUNTIME=1 -s STACK_OVERFLOW_CHECK=0 call-indirect.ll program.c -o module.wasm
И, наконец, вызов:
node index.js
Когда все "собрано" - у меня 0 в консоли. Но ожидая 3.
Также (незначительная вещь, но ..), если вы пытаетесь собрать код без оптимизации -O0, он будет прерван из-за ошибки переполнения стека. Не знаю почему. Любая идея? (Да, я уже пытаюсь увеличить память).
Так, может, кто-то знает, что не так с моей ситуацией?