#ifndef wasm_ir_table_h
#define wasm_ir_table_h
#include "ir/element-utils.h"
#include "ir/literal-utils.h"
#include "ir/module-utils.h"
#include "support/stdckdint.h"
#include "wasm-traversal.h"
#include "wasm.h"
namespace wasm::TableUtils {
struct FlatTable {
std::vector<Name> names;
bool valid;
FlatTable(Module& wasm, Table& table) {
valid = true;
ModuleUtils::iterTableSegments(
wasm, table.name, [&](ElementSegment* segment) {
auto offset = segment->offset;
if (!offset->is<Const>() || !segment->type.isFunction()) {
valid = false;
return;
}
Index start = offset->cast<Const>()->value.geti32();
Index size = segment->data.size();
Index end;
if (std::ckd_add(&end, start, size) || end > table.initial) {
valid = false;
return;
}
if (end > names.size()) {
names.resize(end);
}
ElementUtils::iterElementSegmentFunctionNames(
segment, [&](Name entry, Index i) { names[start + i] = entry; });
});
}
};
inline ElementSegment* getSingletonSegment(Table& table, Module& wasm) {
std::vector<ElementSegment*> tableSegments;
ModuleUtils::iterTableSegments(
wasm, table.name, [&](ElementSegment* segment) {
tableSegments.push_back(segment);
});
if (tableSegments.size() != 1) {
Fatal() << "Table doesn't have a singleton segment.";
}
return tableSegments[0];
}
inline Index append(Table& table, Name name, Module& wasm) {
auto* segment = getSingletonSegment(table, wasm);
auto tableIndex = segment->data.size();
if (wasm.dylinkSection) {
if (segment->data.size() != wasm.dylinkSection->tableSize) {
Fatal() << "Appending to the table in a module with a dylink section "
"that has tableSize which indicates it wants to reserve more "
"table space than the actual table elements in the module. "
"We don't know how to correctly update the dylink section in "
"that case.";
}
wasm.dylinkSection->tableSize++;
}
auto* func = wasm.getFunctionOrNull(name);
assert(func != nullptr && "Cannot append non-existing function to a table.");
segment->data.push_back(Builder(wasm).makeRefFunc(name, func->type));
table.initial++;
return tableIndex;
}
inline Index getOrAppend(Table& table, Name name, Module& wasm) {
auto segment = getSingletonSegment(table, wasm);
for (Index i = 0; i < segment->data.size(); i++) {
if (auto* get = segment->data[i]->dynCast<RefFunc>()) {
if (get->func == name) {
return i;
}
}
}
return append(table, name, wasm);
}
std::set<Name> getFunctionsNeedingElemDeclare(Module& wasm);
bool usesExpressions(ElementSegment* curr, Module* module);
}
#endif