Skip to content

Commit

Permalink
[memory64] Add table64 to existing memory64 support (WebAssembly#6577)
Browse files Browse the repository at this point in the history
Tests is still very limited.  Hopefully we can use the upstream spec
tests soon and avoid having to write our own tests for
`.set/.set/.fill/etc`.

See WebAssembly/memory64#51
  • Loading branch information
sbc100 authored May 10, 2024
1 parent 9975b56 commit abc430b
Show file tree
Hide file tree
Showing 16 changed files with 375 additions and 179 deletions.
13 changes: 7 additions & 6 deletions src/parser/context-decls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ Result<> ParseDeclsCtx::addFunc(Name name,
Result<Table*> ParseDeclsCtx::addTableDecl(Index pos,
Name name,
ImportNames* importNames,
Limits limits) {
TableType type) {
auto t = std::make_unique<Table>();
t->initial = limits.initial;
t->max = limits.max ? *limits.max : Table::kUnlimitedSize;
t->indexType = type.indexType;
t->initial = type.limits.initial;
t->max = type.limits.max ? *type.limits.max : Table::kUnlimitedSize;
if (name.is()) {
if (wasm.getTableOrNull(name)) {
// TODO: if the existing table is not explicitly named, fix its name and
Expand All @@ -105,10 +106,10 @@ Result<Table*> ParseDeclsCtx::addTableDecl(Index pos,
Result<> ParseDeclsCtx::addTable(Name name,
const std::vector<Name>& exports,
ImportNames* import,
Limits limits,
TableType type,
Index pos) {
CHECK_ERR(checkImport(pos, import));
auto t = addTableDecl(pos, name, import, limits);
auto t = addTableDecl(pos, name, import, type);
CHECK_ERR(t);
CHECK_ERR(addExports(in, wasm, *t, exports, ExternalKind::Table));
// TODO: table annotations
Expand Down Expand Up @@ -138,7 +139,7 @@ Result<Memory*> ParseDeclsCtx::addMemoryDecl(Index pos,
ImportNames* importNames,
MemType type) {
auto m = std::make_unique<Memory>();
m->indexType = type.type;
m->indexType = type.indexType;
m->initial = type.limits.initial;
m->max = type.limits.max ? *type.limits.max : Memory::kUnlimitedSize;
m->shared = type.shared;
Expand Down
29 changes: 19 additions & 10 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ struct Limits {
};

struct MemType {
Type type;
Type indexType;
Limits limits;
bool shared;
};
Expand All @@ -56,6 +56,11 @@ struct Memarg {
uint32_t align;
};

struct TableType {
Type indexType;
Limits limits;
};

// The location, possible name, and index in the respective module index space
// of a module-level definition in the input.
struct DefPos {
Expand Down Expand Up @@ -853,7 +858,7 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
using LimitsT = Limits;
using ElemListT = Index;
using DataStringT = std::vector<char>;
using TableTypeT = Limits;
using TableTypeT = TableType;
using MemTypeT = MemType;

Lexer in;
Expand Down Expand Up @@ -942,7 +947,9 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {

Limits getLimitsFromElems(Index elems) { return {elems, elems}; }

Limits makeTableType(Limits limits, TypeT) { return limits; }
TableType makeTableType(Type indexType, Limits limits, TypeT) {
return {indexType, limits};
}

std::vector<char> makeDataString() { return {}; }
void appendDataString(std::vector<char>& data, std::string_view str) {
Expand All @@ -954,8 +961,8 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
return {size, size};
}

MemType makeMemType(Type type, Limits limits, bool shared) {
return {type, limits, shared};
MemType makeMemType(Type indexType, Limits limits, bool shared) {
return {indexType, limits, shared};
}

Result<TypeUseT>
Expand All @@ -975,10 +982,12 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
std::vector<Annotation>&&,
Index pos);

Result<Table*>
addTableDecl(Index pos, Name name, ImportNames* importNames, Limits limits);
Result<Table*> addTableDecl(Index pos,
Name name,
ImportNames* importNames,
TableType limits);
Result<>
addTable(Name, const std::vector<Name>&, ImportNames*, Limits, Index);
addTable(Name, const std::vector<Name>&, ImportNames*, TableType, Index);

// TODO: Record index of implicit elem for use when parsing types and instrs.
Result<> addImplicitElems(TypeT, ElemListT&& elems);
Expand Down Expand Up @@ -1252,7 +1261,7 @@ struct ParseModuleTypesCtx : TypeParserCtx<ParseModuleTypesCtx>,

LimitsT getLimitsFromElems(ElemListT) { return Ok{}; }

Type makeTableType(LimitsT, Type type) { return type; }
Type makeTableType(Type indexType, LimitsT, Type type) { return type; }

LimitsT getLimitsFromData(DataStringT) { return Ok{}; }
MemTypeT makeMemType(Type, LimitsT, bool) { return Ok{}; }
Expand Down Expand Up @@ -1441,7 +1450,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {

LimitsT getLimitsFromElems(std::vector<Expression*>& elems) { return Ok{}; }

TableTypeT makeTableType(LimitsT, Type) { return Ok{}; }
TableTypeT makeTableType(Type, LimitsT, Type) { return Ok{}; }

struct CatchInfo {
Name tag;
Expand Down
43 changes: 32 additions & 11 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ template<typename Ctx> Result<typename Ctx::MemTypeT> memtype(Ctx&);
template<typename Ctx>
Result<typename Ctx::MemTypeT> memtypeContinued(Ctx&, Type indexType);
template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx&);
template<typename Ctx>
Result<typename Ctx::TableTypeT> tabletypeContinued(Ctx&, Type indexType);
template<typename Ctx> Result<typename Ctx::GlobalTypeT> globaltype(Ctx&);
template<typename Ctx> Result<uint32_t> tupleArity(Ctx&);

Expand Down Expand Up @@ -815,16 +817,28 @@ Result<typename Ctx::MemTypeT> memtypeContinued(Ctx& ctx, Type indexType) {
return ctx.makeMemType(indexType, *limits, shared);
}

// tabletype ::= limits32 reftype
// tabletype ::= (limits32 | 'i32' limits32 | 'i64' limit64) reftype
template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx& ctx) {
auto limits = limits32(ctx);
Type indexType = Type::i32;
if (ctx.in.takeKeyword("i64"sv)) {
indexType = Type::i64;
} else {
ctx.in.takeKeyword("i32"sv);
}
return tabletypeContinued(ctx, indexType);
}

template<typename Ctx>
Result<typename Ctx::TableTypeT> tabletypeContinued(Ctx& ctx, Type indexType) {
auto limits = indexType == Type::i32 ? limits32(ctx) : limits64(ctx);
CHECK_ERR(limits);
auto type = reftype(ctx);
CHECK_ERR(type);

if (!type) {
return ctx.in.err("expected reftype");
}
return ctx.makeTableType(*limits, *type);
return ctx.makeTableType(indexType, *limits, *type);
}

// globaltype ::= t:valtype => const t
Expand Down Expand Up @@ -3049,8 +3063,8 @@ template<typename Ctx> MaybeResult<> func(Ctx& ctx) {
}

// table ::= '(' 'table' id? ('(' 'export' name ')')*
// '(' 'import' mod:name nm:name ')'? tabletype ')'
// | '(' 'table' id? ('(' 'export' name ')')*
// '(' 'import' mod:name nm:name ')'? index_type? tabletype ')'
// | '(' 'table' id? ('(' 'export' name ')')* index_type?
// reftype '(' 'elem' (elemexpr* | funcidx*) ')' ')'
template<typename Ctx> MaybeResult<> table(Ctx& ctx) {
auto pos = ctx.in.getPos();
Expand All @@ -3069,6 +3083,13 @@ template<typename Ctx> MaybeResult<> table(Ctx& ctx) {
auto import = inlineImport(ctx.in);
CHECK_ERR(import);

auto indexType = Type::i32;
if (ctx.in.takeKeyword("i64"sv)) {
indexType = Type::i64;
} else {
ctx.in.takeKeyword("i32"sv);
}

// Reftype if we have inline elements.
auto type = reftype(ctx);
CHECK_ERR(type);
Expand Down Expand Up @@ -3103,10 +3124,10 @@ template<typename Ctx> MaybeResult<> table(Ctx& ctx) {
if (!ctx.in.takeRParen()) {
return ctx.in.err("expected end of inline elems");
}
ttype = ctx.makeTableType(ctx.getLimitsFromElems(list), *type);
ttype = ctx.makeTableType(indexType, ctx.getLimitsFromElems(list), *type);
elems = std::move(list);
} else {
auto tabtype = tabletype(ctx);
auto tabtype = tabletypeContinued(ctx, indexType);
CHECK_ERR(tabtype);
ttype = *tabtype;
}
Expand All @@ -3124,10 +3145,10 @@ template<typename Ctx> MaybeResult<> table(Ctx& ctx) {
return Ok{};
}

// mem ::= '(' 'memory' id? ('(' 'export' name ')')* index_type?
// ('(' 'data' b:datastring ')' | memtype) ')'
// | '(' 'memory' id? ('(' 'export' name ')')*
// '(' 'import' mod:name nm:name ')' memtype ')'
// memory ::= '(' 'memory' id? ('(' 'export' name ')')* index_type?
// ('(' 'data' b:datastring ')' | memtype) ')'
// | '(' 'memory' id? ('(' 'export' name ')')*
// '(' 'import' mod:name nm:name ')' index_type? memtype ')'
template<typename Ctx> MaybeResult<> memory(Ctx& ctx) {
auto pos = ctx.in.getPos();
if (!ctx.in.takeSExprStart("memory"sv)) {
Expand Down
3 changes: 3 additions & 0 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3088,6 +3088,9 @@ void PrintSExpression::printTableHeader(Table* curr) {
o << '(';
printMedium(o, "table") << ' ';
curr->name.print(o) << ' ';
if (curr->is64()) {
o << "i64 ";
}
o << curr->initial;
if (curr->hasMax()) {
o << ' ' << curr->max;
Expand Down
5 changes: 5 additions & 0 deletions src/tools/wasm-shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,11 @@ class Shell {
spectest->addExport(
builder.makeExport("table", Name::fromInt(0), ExternalKind::Table));

spectest->addTable(builder.makeTable(
Name::fromInt(1), Type(HeapType::func, Nullable), 10, 20, Type::i64));
spectest->addExport(
builder.makeExport("table64", Name::fromInt(1), ExternalKind::Table));

Memory* memory =
spectest->addMemory(builder.makeMemory(Name::fromInt(0), 1, 2));
spectest->addExport(
Expand Down
2 changes: 2 additions & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,8 @@ class WasmBinaryReader {

// gets a memory in the combined import+defined space
Memory* getMemory(Index index);
// gets a table in the combined import+defined space
Table* getTable(Index index);

void getResizableLimits(Address& initial,
Address& max,
Expand Down
12 changes: 11 additions & 1 deletion src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,12 @@ class Builder {
Type type = Type(HeapType::func,
Nullable),
Address initial = 0,
Address max = Table::kMaxSize) {
Address max = Table::kMaxSize,
Type indexType = Type::i32) {
auto table = std::make_unique<Table>();
table->name = name;
table->type = type;
table->indexType = indexType;
table->initial = initial;
table->max = max;
return table;
Expand Down Expand Up @@ -658,6 +660,8 @@ class Builder {
wasm.getMemory(memoryName)->is64());
}

bool isTable64(Name tableName) { return wasm.getTable(tableName)->is64(); }

MemorySize* makeMemorySize(Name memoryName,
MemoryInfo info = MemoryInfo::Unspecified) {
auto* ret = wasm.allocator.alloc<MemorySize>();
Expand Down Expand Up @@ -729,6 +733,9 @@ class Builder {
TableSize* makeTableSize(Name table) {
auto* ret = wasm.allocator.alloc<TableSize>();
ret->table = table;
if (isTable64(table)) {
ret->type = Type::i64;
}
ret->finalize();
return ret;
}
Expand All @@ -737,6 +744,9 @@ class Builder {
ret->table = table;
ret->value = value;
ret->delta = delta;
if (isTable64(table)) {
ret->type = Type::i64;
}
ret->finalize();
return ret;
}
Expand Down
37 changes: 24 additions & 13 deletions src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -3086,8 +3086,11 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
return index;
}
auto info = getTableInterfaceInfo(curr->table);
return info.interface->tableLoad(info.name,
index.getSingleValue().geti32());
auto* table = wasm.getTable(info.name);
auto address = table->indexType == Type::i64
? index.getSingleValue().geti64()
: index.getSingleValue().geti32();
return info.interface->tableLoad(info.name, address);
}
Flow visitTableSet(TableSet* curr) {
NOTE_ENTER("TableSet");
Expand All @@ -3100,17 +3103,20 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
return valueFlow;
}
auto info = getTableInterfaceInfo(curr->table);
info.interface->tableStore(info.name,
indexFlow.getSingleValue().geti32(),
valueFlow.getSingleValue());
auto* table = wasm.getTable(info.name);
auto address = table->indexType == Type::i64
? indexFlow.getSingleValue().geti64()
: indexFlow.getSingleValue().geti32();
info.interface->tableStore(info.name, address, valueFlow.getSingleValue());
return Flow();
}

Flow visitTableSize(TableSize* curr) {
NOTE_ENTER("TableSize");
auto info = getTableInterfaceInfo(curr->table);
auto* table = wasm.getTable(info.name);
Index tableSize = info.interface->tableSize(curr->table);
return Literal::makeFromInt32(tableSize, Type::i32);
return Literal::makeFromInt64(tableSize, table->indexType);
}

Flow visitTableGrow(TableGrow* curr) {
Expand All @@ -3126,16 +3132,16 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
Name tableName = curr->table;
auto info = getTableInterfaceInfo(tableName);

Index tableSize = info.interface->tableSize(tableName);
Flow ret = Literal::makeFromInt32(tableSize, Type::i32);
Flow fail = Literal::makeFromInt32(-1, Type::i32);
Index tableSize = info.interface->tableSize(info.name);
auto* table = self()->wasm.getTable(info.name);
Flow ret = Literal::makeFromInt64(tableSize, table->indexType);
Flow fail = Literal::makeFromInt64(-1, table->indexType);
Index delta = deltaFlow.getSingleValue().geti32();

if (tableSize >= uint32_t(-1) - delta) {
return fail;
}
auto maxTableSize = self()->wasm.getTable(tableName)->max;
if (uint64_t(tableSize) + uint64_t(delta) > uint64_t(maxTableSize)) {
if (uint64_t(tableSize) + uint64_t(delta) > uint64_t(table->max)) {
return fail;
}
Index newSize = tableSize + delta;
Expand Down Expand Up @@ -3168,9 +3174,14 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
Name tableName = curr->table;
auto info = getTableInterfaceInfo(tableName);

Index dest = destFlow.getSingleValue().geti32();
auto* table = self()->wasm.getTable(info.name);
Index dest = table->indexType == Type::i64
? destFlow.getSingleValue().geti64()
: destFlow.getSingleValue().geti32();
Literal value = valueFlow.getSingleValue();
Index size = sizeFlow.getSingleValue().geti32();
Index size = table->indexType == Type::i64
? sizeFlow.getSingleValue().geti64()
: sizeFlow.getSingleValue().geti32();

Index tableSize = info.interface->tableSize(tableName);
if (dest + size > tableSize) {
Expand Down
2 changes: 2 additions & 0 deletions src/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -2276,9 +2276,11 @@ class Table : public Importable {

Address initial = 0;
Address max = kMaxSize;
Type indexType = Type::i32;
Type type = Type(HeapType::func, Nullable);

bool hasMax() { return max != kUnlimitedSize; }
bool is64() { return indexType == Type::i64; }
void clear() {
name = "";
initial = 0;
Expand Down
Loading

0 comments on commit abc430b

Please sign in to comment.