Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add a test case for this in test/lit/passes/unsubtyping.wast.

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 ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to check for wrapping against both sourceVal and sizeVal. Even the most wrapping possible cannot wrap around to greater than the minimum of the two, so just one of them will serve to detect the wrapping.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is copied from the parallel logic in MemoryCopy. I agree that it looks unoptimal. I think the TODO covers improving them.

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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we support raw indices as well, or do we not support those in other places? The new wat parser will support them in either case (eventually).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we do in other places, as this is based on TableFill right above us. That actually might explain why some spec tests didn't pass...

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