Skip to content

Commit

Permalink
Implement table.copy (WebAssembly#6078)
Browse files Browse the repository at this point in the history
  • Loading branch information
kripken authored and radekdoulik committed Jul 12, 2024
1 parent 9794963 commit c246150
Show file tree
Hide file tree
Showing 29 changed files with 2,545 additions and 42 deletions.
3 changes: 1 addition & 2 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,10 +548,9 @@
("table.size", "makeTableSize(s)"),
("table.grow", "makeTableGrow(s)"),
("table.fill", "makeTableFill(s)"),
("table.copy", "makeTableCopy(s)"),
# TODO:
# table.init
# table.fill
# table.copy
#
# exception handling instructions
("try", "makeTry(s)"),
Expand Down
9 changes: 9 additions & 0 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -3357,6 +3357,9 @@ switch (buf[0]) {
switch (buf[1]) {
case 'a': {
switch (buf[6]) {
case 'c':
if (op == "table.copy"sv) { return makeTableCopy(s); }
goto parse_error;
case 'f':
if (op == "table.fill"sv) { return makeTableFill(s); }
goto parse_error;
Expand Down Expand Up @@ -8619,6 +8622,12 @@ switch (buf[0]) {
switch (buf[1]) {
case 'a': {
switch (buf[6]) {
case 'c':
if (op == "table.copy"sv) {
CHECK_ERR(makeTableCopy(ctx, pos));
return Ok{};
}
goto parse_error;
case 'f':
if (op == "table.fill"sv) {
CHECK_ERR(makeTableFill(ctx, pos));
Expand Down
1 change: 1 addition & 0 deletions src/ir/ReFinalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ void ReFinalize::visitTableSet(TableSet* curr) { curr->finalize(); }
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::visitTry(Try* curr) { curr->finalize(); }
void ReFinalize::visitThrow(Throw* curr) { curr->finalize(); }
void ReFinalize::visitRethrow(Rethrow* curr) { curr->finalize(); }
Expand Down
3 changes: 3 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,9 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
CostType visitTableFill(TableFill* curr) {
return 6 + visit(curr->dest) + visit(curr->value) + visit(curr->size);
}
CostType visitTableCopy(TableCopy* curr) {
return 6 + visit(curr->dest) + visit(curr->source) + visit(curr->size);
}
CostType visitTry(Try* curr) {
// We assume no exception will be thrown in most cases
return visit(curr->body);
Expand Down
5 changes: 5 additions & 0 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,11 @@ class EffectAnalyzer {
parent.writesTable = true;
parent.implicitTrap = true;
}
void visitTableCopy(TableCopy* curr) {
parent.readsTable = true;
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 @@ -662,6 +662,7 @@ struct InfoCollector
void visitTableSize(TableSize* curr) { addRoot(curr); }
void visitTableGrow(TableGrow* curr) { addRoot(curr); }
void visitTableFill(TableFill* curr) { addRoot(curr); }
void visitTableCopy(TableCopy* curr) { addRoot(curr); }

void visitNop(Nop* curr) {}
void visitUnreachable(Unreachable* curr) {}
Expand Down
5 changes: 5 additions & 0 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ template<typename Ctx> Result<> makeTableSet(Ctx&, Index);
template<typename Ctx> Result<> makeTableSize(Ctx&, Index);
template<typename Ctx> Result<> makeTableGrow(Ctx&, Index);
template<typename Ctx> Result<> makeTableFill(Ctx&, Index);
template<typename Ctx> Result<> makeTableCopy(Ctx&, Index);
template<typename Ctx> Result<> makeTry(Ctx&, Index);
template<typename Ctx>
Result<> makeTryOrCatchBody(Ctx&, Index, Type type, bool isTry);
Expand Down Expand Up @@ -1264,6 +1265,10 @@ template<typename Ctx> Result<> makeTableFill(Ctx& ctx, Index pos) {
return ctx.in.err("unimplemented instruction");
}

template<typename Ctx> Result<> makeTableCopy(Ctx& ctx, Index pos) {
return ctx.in.err("unimplemented instruction");
}

template<typename Ctx> Result<> makeTry(Ctx& ctx, Index pos) {
return ctx.in.err("unimplemented instruction");
}
Expand Down
3 changes: 3 additions & 0 deletions src/passes/Directize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ struct Directize : public Pass {
void visitTableFill(TableFill* curr) {
tablesWithSet.insert(curr->table);
}
void visitTableCopy(TableCopy* curr) {
tablesWithSet.insert(curr->destTable);
}
};

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 @@ -1950,6 +1950,12 @@ struct PrintExpressionContents
printMedium(o, "table.fill ");
printName(curr->table, o);
}
void visitTableCopy(TableCopy* curr) {
printMedium(o, "table.copy ");
printName(curr->destTable, o);
o << ' ';
printName(curr->sourceTable, o);
}
void visitTry(Try* curr) {
printMedium(o, "try");
if (curr->name.is()) {
Expand Down
4 changes: 4 additions & 0 deletions src/passes/Unsubtyping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,10 @@ struct Unsubtyping
void visitTableFill(TableFill* curr) {
noteSubtype(curr->value->type, getModule()->getTable(curr->table)->type);
}
void visitTableCopy(TableCopy* curr) {
noteSubtype(getModule()->getTable(curr->sourceTable)->type,
getModule()->getTable(curr->destTable)->type);
}
void visitTry(Try* curr) {
noteSubtype(curr->body->type, curr->type);
for (auto* body : curr->catchBodies) {
Expand Down
2 changes: 2 additions & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,7 @@ enum ASTNodes {
TableGrow = 0x0f,
TableSize = 0x10,
TableFill = 0x11,
TableCopy = 0x0e,
RefNull = 0xd0,
RefIsNull = 0xd1,
RefFunc = 0xd2,
Expand Down Expand Up @@ -1844,6 +1845,7 @@ class WasmBinaryReader {
bool maybeVisitTableSize(Expression*& out, uint32_t code);
bool maybeVisitTableGrow(Expression*& out, uint32_t code);
bool maybeVisitTableFill(Expression*& out, uint32_t code);
bool maybeVisitTableCopy(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 @@ -771,6 +771,20 @@ class Builder {
ret->finalize();
return ret;
}
TableCopy* makeTableCopy(Expression* dest,
Expression* source,
Expression* size,
Name destTable,
Name sourceTable) {
auto* ret = wasm.allocator.alloc<TableCopy>();
ret->dest = dest;
ret->source = source;
ret->size = size;
ret->destTable = destTable;
ret->sourceTable = sourceTable;
ret->finalize();
return ret;
}

private:
Try* makeTry(Name name,
Expand Down
10 changes: 10 additions & 0 deletions src/wasm-delegations-fields.def
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,16 @@ switch (DELEGATE_ID) {
DELEGATE_END(TableFill);
break;
}
case Expression::Id::TableCopyId: {
DELEGATE_START(TableCopy);
DELEGATE_FIELD_CHILD(TableCopy, size);
DELEGATE_FIELD_CHILD(TableCopy, source);
DELEGATE_FIELD_CHILD(TableCopy, dest);
DELEGATE_FIELD_NAME_KIND(TableCopy, sourceTable, ModuleItemKind::Table);
DELEGATE_FIELD_NAME_KIND(TableCopy, destTable, ModuleItemKind::Table);
DELEGATE_END(TableCopy);
break;
}
case Expression::Id::TryId: {
DELEGATE_START(Try);
DELEGATE_FIELD_SCOPE_NAME_USE(Try, delegateTarget);
Expand Down
1 change: 1 addition & 0 deletions src/wasm-delegations.def
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ DELEGATE(TableSet);
DELEGATE(TableSize);
DELEGATE(TableGrow);
DELEGATE(TableFill);
DELEGATE(TableCopy);
DELEGATE(Try);
DELEGATE(Throw);
DELEGATE(Rethrow);
Expand Down
56 changes: 56 additions & 0 deletions src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,7 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
Flow visitTableSize(TableSize* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTableGrow(TableGrow* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTableFill(TableFill* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTableCopy(TableCopy* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTry(Try* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitThrow(Throw* curr) {
NOTE_ENTER("Throw");
Expand Down Expand Up @@ -2210,6 +2211,10 @@ class ConstantExpressionRunner : public ExpressionRunner<SubType> {
NOTE_ENTER("TableFill");
return Flow(NONCONSTANT_FLOW);
}
Flow visitTableCopy(TableCopy* curr) {
NOTE_ENTER("TableCopy");
return Flow(NONCONSTANT_FLOW);
}
Flow visitLoad(Load* curr) {
NOTE_ENTER("Load");
return Flow(NONCONSTANT_FLOW);
Expand Down Expand Up @@ -3027,6 +3032,57 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
return Flow();
}

Flow visitTableCopy(TableCopy* curr) {
NOTE_ENTER("TableCopy");
Flow dest = self()->visit(curr->dest);
if (dest.breaking()) {
return dest;
}
Flow source = self()->visit(curr->source);
if (source.breaking()) {
return source;
}
Flow size = self()->visit(curr->size);
if (size.breaking()) {
return size;
}
NOTE_EVAL1(dest);
NOTE_EVAL1(source);
NOTE_EVAL1(size);
Address destVal(dest.getSingleValue().getUnsigned());
Address sourceVal(source.getSingleValue().getUnsigned());
Address sizeVal(size.getSingleValue().getUnsigned());

auto destInfo = getTableInterfaceInfo(curr->destTable);
auto sourceInfo = getTableInterfaceInfo(curr->sourceTable);
auto destTableSize = destInfo.interface->tableSize(destInfo.name);
auto sourceTableSize = sourceInfo.interface->tableSize(sourceInfo.name);
if (sourceVal + sizeVal > sourceTableSize ||
destVal + sizeVal > destTableSize ||
// FIXME: better/cheaper way to detect wrapping?
sourceVal + sizeVal < sourceVal || sourceVal + sizeVal < sizeVal ||
destVal + sizeVal < destVal || destVal + sizeVal < sizeVal) {
trap("out of bounds segment access in table.copy");
}

int64_t start = 0;
int64_t end = sizeVal;
int step = 1;
// Reverse direction if source is below dest
if (sourceVal < destVal) {
start = int64_t(sizeVal) - 1;
end = -1;
step = -1;
}
for (int64_t i = start; i != end; i += step) {
destInfo.interface->tableStore(
destInfo.name,
destVal + i,
sourceInfo.interface->tableLoad(sourceInfo.name, sourceVal + i));
}
return {};
}

Flow visitLocalGet(LocalGet* curr) {
NOTE_ENTER("LocalGet");
auto index = curr->index;
Expand Down
1 change: 1 addition & 0 deletions src/wasm-ir-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
// [[nodiscard]] Result<> makeTableSize();
// [[nodiscard]] Result<> makeTableGrow();
// [[nodiscard]] Result<> makeTableFill();
// [[nodiscard]] Result<> makeTableCopy();
// [[nodiscard]] Result<> makeTry();
// [[nodiscard]] Result<> makeThrow();
// [[nodiscard]] Result<> makeRethrow();
Expand Down
1 change: 1 addition & 0 deletions src/wasm-s-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ class SExpressionWasmBuilder {
Expression* makeTableSize(Element& s);
Expression* makeTableGrow(Element& s);
Expression* makeTableFill(Element& s);
Expression* makeTableCopy(Element& s);
Expression* makeTry(Element& s);
Expression* makeTryOrCatchBody(Element& s, Type type, bool isTry);
Expression* makeThrow(Element& s);
Expand Down
15 changes: 15 additions & 0 deletions src/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ class Expression {
TableSizeId,
TableGrowId,
TableFillId,
TableCopyId,
TryId,
ThrowId,
RethrowId,
Expand Down Expand Up @@ -1435,6 +1436,20 @@ class TableFill : public SpecificExpression<Expression::TableFillId> {
void finalize();
};

class TableCopy : public SpecificExpression<Expression::TableCopyId> {
public:
TableCopy() = default;
TableCopy(MixedArena& allocator) : TableCopy() {}

Expression* dest;
Expression* source;
Expression* size;
Name destTable;
Name sourceTable;

void finalize();
};

class Try : public SpecificExpression<Expression::TryId> {
public:
Try(MixedArena& allocator) : catchTags(allocator), catchBodies(allocator) {}
Expand Down
25 changes: 25 additions & 0 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4062,6 +4062,9 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) {
if (maybeVisitTableFill(curr, opcode)) {
break;
}
if (maybeVisitTableCopy(curr, opcode)) {
break;
}
throwError("invalid code after misc prefix: " + std::to_string(opcode));
break;
}
Expand Down Expand Up @@ -5436,6 +5439,28 @@ bool WasmBinaryReader::maybeVisitTableFill(Expression*& out, uint32_t code) {
return true;
}

bool WasmBinaryReader::maybeVisitTableCopy(Expression*& out, uint32_t code) {
if (code != BinaryConsts::TableCopy) {
return false;
}
Index destTableIdx = getU32LEB();
if (destTableIdx >= wasm.tables.size()) {
throwError("bad table index");
}
Index sourceTableIdx = getU32LEB();
if (sourceTableIdx >= wasm.tables.size()) {
throwError("bad table index");
}
auto* size = popNonVoidExpression();
auto* source = popNonVoidExpression();
auto* dest = popNonVoidExpression();
auto* ret = Builder(wasm).makeTableCopy(dest, source, size, Name(), Name());
tableRefs[destTableIdx].push_back(&ret->destTable);
tableRefs[sourceTableIdx].push_back(&ret->sourceTable);
out = ret;
return true;
}

bool WasmBinaryReader::maybeVisitBinary(Expression*& out, uint8_t code) {
Binary* curr;
#define INT_TYPED_CODE(code) \
Expand Down
18 changes: 18 additions & 0 deletions src/wasm/wasm-s-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2706,6 +2706,24 @@ Expression* SExpressionWasmBuilder::makeTableFill(Element& s) {
return Builder(wasm).makeTableFill(tableName, dest, value, size);
}

Expression* SExpressionWasmBuilder::makeTableCopy(Element& s) {
auto destTableName = s[1]->str();
auto* destTable = wasm.getTableOrNull(destTableName);
if (!destTable) {
throw SParseException("invalid dest table name in table.copy", s);
}
auto sourceTableName = s[2]->str();
auto* sourceTable = wasm.getTableOrNull(sourceTableName);
if (!sourceTable) {
throw SParseException("invalid source table name in table.copy", s);
}
auto* dest = parseExpression(s[3]);
auto* source = parseExpression(s[4]);
auto* size = parseExpression(s[5]);
return Builder(wasm).makeTableCopy(
dest, source, size, destTableName, sourceTableName);
}

// try can be either in the form of try-catch or try-delegate.
// try-catch is written in the folded wast format as
// (try
Expand Down
6 changes: 6 additions & 0 deletions src/wasm/wasm-stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1941,6 +1941,12 @@ void BinaryInstWriter::visitTableFill(TableFill* curr) {
o << U32LEB(parent.getTableIndex(curr->table));
}

void BinaryInstWriter::visitTableCopy(TableCopy* curr) {
o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::TableCopy);
o << U32LEB(parent.getTableIndex(curr->destTable));
o << U32LEB(parent.getTableIndex(curr->sourceTable));
}

void BinaryInstWriter::visitTry(Try* curr) {
breakStack.push_back(curr->name);
o << int8_t(BinaryConsts::Try);
Expand Down
Loading

0 comments on commit c246150

Please sign in to comment.