#include <unordered_map>
#include "asm_v_wasm.h"
#include "ir/table-utils.h"
#include "ir/utils.h"
#include "pass.h"
#include "wasm-builder.h"
#include "wasm-traversal.h"
#include "wasm.h"
namespace wasm {
namespace {
struct FunctionDirectizer : public WalkerPass<PostWalker<FunctionDirectizer>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new FunctionDirectizer(flatTable); }
FunctionDirectizer(TableUtils::FlatTable* flatTable) : flatTable(flatTable) {}
void visitCallIndirect(CallIndirect* curr) {
if (auto* c = curr->target->dynCast<Const>()) {
Index index = c->value.geti32();
if (index >= flatTable->names.size()) {
replaceWithUnreachable(curr);
return;
}
auto name = flatTable->names[index];
if (!name.is()) {
replaceWithUnreachable(curr);
return;
}
auto* func = getModule()->getFunction(name);
if (curr->sig != func->sig) {
replaceWithUnreachable(curr);
return;
}
replaceCurrent(
Builder(*getModule())
.makeCall(name, curr->operands, curr->type, curr->isReturn));
}
}
void doWalkFunction(Function* func) {
WalkerPass<PostWalker<FunctionDirectizer>>::doWalkFunction(func);
if (changedTypes) {
ReFinalize().walkFunctionInModule(func, getModule());
}
}
private:
TableUtils::FlatTable* flatTable;
bool changedTypes = false;
void replaceWithUnreachable(CallIndirect* call) {
Builder builder(*getModule());
for (auto*& operand : call->operands) {
operand = builder.makeDrop(operand);
}
replaceCurrent(builder.makeSequence(builder.makeBlock(call->operands),
builder.makeUnreachable()));
changedTypes = true;
}
};
struct Directize : public Pass {
void run(PassRunner* runner, Module* module) override {
if (!module->table.exists) {
return;
}
if (module->table.imported()) {
return;
}
for (auto& ex : module->exports) {
if (ex->kind == ExternalKind::Table) {
return;
}
}
TableUtils::FlatTable flatTable(module->table);
if (!flatTable.valid) {
return;
}
FunctionDirectizer(&flatTable).run(runner, module);
}
};
}
Pass* createDirectizePass() { return new Directize(); }
}