Skip to content

Commit

Permalink
Implement table.init (#6827)
Browse files Browse the repository at this point in the history
Also use TableInit in the interpreter to initialize module's table
state, which will now handle traps properly, fixing #6431
  • Loading branch information
kripken authored Aug 16, 2024
1 parent 7209629 commit 958ff41
Show file tree
Hide file tree
Showing 37 changed files with 700 additions and 95 deletions.
4 changes: 1 addition & 3 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,9 +560,7 @@
("table.grow", "makeTableGrow()"),
("table.fill", "makeTableFill()"),
("table.copy", "makeTableCopy()"),
# TODO:
# table.init
#
("table.init", "makeTableInit()"),
# exception handling instructions
("try", "makeTry()"),
("try_table", "makeTryTable()"),
Expand Down
6 changes: 6 additions & 0 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -4936,6 +4936,12 @@ switch (buf[0]) {
default: goto parse_error;
}
}
case 'i':
if (op == "table.init"sv) {
CHECK_ERR(makeTableInit(ctx, pos, annotations));
return Ok{};
}
goto parse_error;
case 's': {
switch (buf[7]) {
case 'e':
Expand Down
1 change: 1 addition & 0 deletions src/ir/ReFinalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ void ReFinalize::visitTableSize(TableSize* curr) { curr->finalize(); }
void ReFinalize::visitTableGrow(TableGrow* curr) { curr->finalize(); }
void ReFinalize::visitTableFill(TableFill* curr) { curr->finalize(); }
void ReFinalize::visitTableCopy(TableCopy* curr) { curr->finalize(); }
void ReFinalize::visitTableInit(TableInit* curr) { curr->finalize(); }
void ReFinalize::visitTry(Try* curr) { curr->finalize(); }
void ReFinalize::visitTryTable(TryTable* curr) { curr->finalize(); }
void ReFinalize::visitThrow(Throw* curr) { curr->finalize(); }
Expand Down
6 changes: 6 additions & 0 deletions src/ir/child-typer.h
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,12 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
note(&curr->size, Type::i32);
}

void visitTableInit(TableInit* curr) {
note(&curr->dest, wasm.getTable(curr->table)->indexType);
note(&curr->offset, Type::i32);
note(&curr->size, Type::i32);
}

void visitTry(Try* curr) {
note(&curr->body, curr->type);
for (auto& expr : curr->catchBodies) {
Expand Down
3 changes: 3 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,9 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
CostType visitTableCopy(TableCopy* curr) {
return 6 + visit(curr->dest) + visit(curr->source) + visit(curr->size);
}
CostType visitTableInit(TableInit* curr) {
return 6 + visit(curr->dest) + visit(curr->offset) + visit(curr->size);
}
CostType visitTry(Try* curr) {
// We assume no exception will be thrown in most cases
return visit(curr->body);
Expand Down
4 changes: 4 additions & 0 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,10 @@ class EffectAnalyzer {
parent.writesTable = true;
parent.implicitTrap = true;
}
void visitTableInit(TableInit* curr) {
parent.writesTable = true;
parent.implicitTrap = true;
}
void visitTry(Try* curr) {
if (curr->delegateTarget.is()) {
parent.delegateTargets.insert(curr->delegateTarget);
Expand Down
1 change: 1 addition & 0 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ struct InfoCollector
void visitTableGrow(TableGrow* curr) { addRoot(curr); }
void visitTableFill(TableFill* curr) { addRoot(curr); }
void visitTableCopy(TableCopy* curr) { addRoot(curr); }
void visitTableInit(TableInit* curr) {}

void visitNop(Nop* curr) {}
void visitUnreachable(Unreachable* curr) {}
Expand Down
5 changes: 5 additions & 0 deletions src/ir/subtype-exprs.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
self()->noteSubtype(self()->getModule()->getTable(curr->sourceTable)->type,
self()->getModule()->getTable(curr->destTable)->type);
}
void visitTableInit(TableInit* curr) {
auto* seg = self()->getModule()->getElementSegment(curr->segment);
self()->noteSubtype(seg->type,
self()->getModule()->getTable(curr->table)->type);
}
void visitTry(Try* curr) {
self()->noteSubtype(curr->body, curr);
for (auto* body : curr->catchBodies) {
Expand Down
13 changes: 13 additions & 0 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,10 @@ struct NullInstrParserCtx {
makeTableCopy(Index, const std::vector<Annotation>&, TableIdxT*, TableIdxT*) {
return Ok{};
}
Result<>
makeTableInit(Index, const std::vector<Annotation>&, TableIdxT*, ElemIdxT) {
return Ok{};
}
Result<> makeThrow(Index, const std::vector<Annotation>&, TagIdxT) {
return Ok{};
}
Expand Down Expand Up @@ -2325,6 +2329,15 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
return withLoc(pos, irBuilder.makeTableCopy(*dest, *src));
}

Result<> makeTableInit(Index pos,
const std::vector<Annotation>& annotations,
Name* table,
Name elem) {
auto t = getTable(pos, table);
CHECK_ERR(t);
return withLoc(pos, irBuilder.makeTableInit(elem, *t));
}

Result<>
makeThrow(Index pos, const std::vector<Annotation>& annotations, Name tag) {
return withLoc(pos, irBuilder.makeThrow(tag));
Expand Down
12 changes: 12 additions & 0 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ Result<> makeTableFill(Ctx&, Index, const std::vector<Annotation>&);
template<typename Ctx>
Result<> makeTableCopy(Ctx&, Index, const std::vector<Annotation>&);
template<typename Ctx>
Result<> makeTableInit(Ctx&, Index, const std::vector<Annotation>&);
template<typename Ctx>
Result<> makeThrow(Ctx&, Index, const std::vector<Annotation>&);
template<typename Ctx>
Result<> makeRethrow(Ctx&, Index, const std::vector<Annotation>&);
Expand Down Expand Up @@ -2067,6 +2069,16 @@ makeTableCopy(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) {
pos, annotations, destTable.getPtr(), srcTable.getPtr());
}

template<typename Ctx>
Result<>
makeTableInit(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) {
auto table = maybeTableidx(ctx);
CHECK_ERR(table);
auto elem = elemidx(ctx);
CHECK_ERR(elem);
return ctx.makeTableInit(pos, annotations, table.getPtr(), *elem);
}

template<typename Ctx>
Result<>
makeThrow(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) {
Expand Down
3 changes: 3 additions & 0 deletions src/passes/Directize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ struct Directize : public Pass {
void visitTableCopy(TableCopy* curr) {
tablesWithSet.insert(curr->destTable);
}
void visitTableInit(TableInit* curr) {
tablesWithSet.insert(curr->table);
}
};

Finder(tablesWithSet).walkFunction(func);
Expand Down
6 changes: 6 additions & 0 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,12 @@ struct PrintExpressionContents
o << ' ';
curr->sourceTable.print(o);
}
void visitTableInit(TableInit* curr) {
printMedium(o, "table.init ");
curr->table.print(o);
o << ' ';
curr->segment.print(o);
}
void visitTry(Try* curr) {
printMedium(o, "try");
if (curr->name.is()) {
Expand Down
4 changes: 4 additions & 0 deletions src/passes/Table64Lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ struct Table64Lowering : public WalkerPass<PostWalker<Table64Lowering>> {
wrapAddress64(curr->size, curr->destTable);
}

void visitTableInit(TableInit* curr) {
wrapAddress64(curr->dest, curr->table);
}

void visitCallIndirect(CallIndirect* curr) {
wrapAddress64(curr->target, curr->table);
}
Expand Down
2 changes: 2 additions & 0 deletions src/passes/TypeGeneralizing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,8 @@ struct TransferFn : OverriddenVisitor<TransferFn> {
// Cannot generalize table types yet.
}

void visitTableInit(TableInit* curr) {}

void visitTry(Try* curr) { WASM_UNREACHABLE("TODO"); }
void visitTryTable(TryTable* curr) { WASM_UNREACHABLE("TODO"); }
void visitThrow(Throw* curr) { WASM_UNREACHABLE("TODO"); }
Expand Down
24 changes: 15 additions & 9 deletions src/tools/wasm-ctor-eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,6 @@ class EvallingModuleRunner : public ModuleRunnerBase<EvallingModuleRunner> {

return ModuleRunnerBase<EvallingModuleRunner>::visitGlobalGet(curr);
}

Flow visitTableSet(TableSet* curr) {
// TODO: Full dynamic table support. For now we stop evalling when we see a
// table.set. (To support this we need to track sets and add code to
// serialize them.)
throw FailToEvalException("table.set: TODO");
}
};

// Build an artificial `env` module based on a module's imports, so that the
Expand Down Expand Up @@ -174,6 +167,9 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
// not yet been re-added are a blind spot for it).
std::unordered_set<Name> usedGlobalNames;

// Set to true after we create the instance.
bool instanceInitialized = false;

CtorEvalExternalInterface(
std::map<Name, std::shared_ptr<EvallingModuleRunner>> linkedInstances_ =
{}) {
Expand Down Expand Up @@ -363,15 +359,24 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
}

Index tableSize(Name tableName) override {
throw FailToEvalException("table size");
// See callTable above, we assume the table is not modified FIXME
return wasm->getTableOrNull(tableName)->initial;
}

Literal tableLoad(Name tableName, Index index) override {
throw FailToEvalException("table.get: TODO");
}

// called during initialization
void tableStore(Name tableName, Index index, const Literal& value) override {}
void tableStore(Name tableName, Index index, const Literal& value) override {
// We allow stores to the table during initialization, but not after, as we
// assume the table does not change at runtime.
// TODO: Allow table changes by updating the table later like we do with the
// memory, by tracking and serializing them.
if (instanceInitialized) {
throw FailToEvalException("tableStore after init: TODO");
}
}

int8_t load8s(Address addr, Name memoryName) override {
return doLoad<int8_t>(addr, memoryName);
Expand Down Expand Up @@ -1294,6 +1299,7 @@ void evalCtors(Module& wasm,
try {
// create an instance for evalling
EvallingModuleRunner instance(wasm, &interface, linkedInstances);
interface.instanceInitialized = true;
// go one by one, in order, until we fail
// TODO: if we knew priorities, we could reorder?
for (auto& ctor : ctors) {
Expand Down
2 changes: 2 additions & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,7 @@ enum ASTNodes {
TableSize = 0x10,
TableFill = 0x11,
TableCopy = 0x0e,
TableInit = 0x0c,
RefNull = 0xd0,
RefIsNull = 0xd1,
RefFunc = 0xd2,
Expand Down Expand Up @@ -1752,6 +1753,7 @@ class WasmBinaryReader {
bool maybeVisitTableGrow(Expression*& out, uint32_t code);
bool maybeVisitTableFill(Expression*& out, uint32_t code);
bool maybeVisitTableCopy(Expression*& out, uint32_t code);
bool maybeVisitTableInit(Expression*& out, uint32_t code);
bool maybeVisitRefI31(Expression*& out, uint32_t code);
bool maybeVisitI31Get(Expression*& out, uint32_t code);
bool maybeVisitRefTest(Expression*& out, uint32_t code);
Expand Down
14 changes: 14 additions & 0 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,20 @@ class Builder {
ret->finalize();
return ret;
}
TableInit* makeTableInit(Name segment,
Expression* dest,
Expression* offset,
Expression* size,
Name table) {
auto* ret = wasm.allocator.alloc<TableInit>();
ret->segment = segment;
ret->dest = dest;
ret->offset = offset;
ret->size = size;
ret->table = table;
ret->finalize();
return ret;
}

private:
Try* makeTry(Name name,
Expand Down
8 changes: 8 additions & 0 deletions src/wasm-delegations-fields.def
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,14 @@ DELEGATE_FIELD_NAME_KIND(TableCopy, sourceTable, ModuleItemKind::Table)
DELEGATE_FIELD_NAME_KIND(TableCopy, destTable, ModuleItemKind::Table)
DELEGATE_FIELD_CASE_END(TableCopy)

DELEGATE_FIELD_CASE_START(TableInit)
DELEGATE_FIELD_CHILD(TableInit, size)
DELEGATE_FIELD_CHILD(TableInit, offset)
DELEGATE_FIELD_CHILD(TableInit, dest)
DELEGATE_FIELD_NAME_KIND(TableInit, segment, ModuleItemKind::ElementSegment)
DELEGATE_FIELD_NAME_KIND(TableInit, table, ModuleItemKind::Table)
DELEGATE_FIELD_CASE_END(TableInit)

DELEGATE_FIELD_CASE_START(Try)
DELEGATE_FIELD_SCOPE_NAME_USE(Try, delegateTarget)
DELEGATE_FIELD_CHILD_VECTOR(Try, catchBodies)
Expand Down
1 change: 1 addition & 0 deletions src/wasm-delegations.def
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ DELEGATE(TableSize);
DELEGATE(TableGrow);
DELEGATE(TableFill);
DELEGATE(TableCopy);
DELEGATE(TableInit);
DELEGATE(Try);
DELEGATE(TryTable);
DELEGATE(Throw);
Expand Down
Loading

0 comments on commit 958ff41

Please sign in to comment.