Skip to content

Commit b96fee8

Browse files
committed
[memory64] Add table64 to existing memory64 support
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
1 parent 006181b commit b96fee8

File tree

7 files changed

+92
-32
lines changed

7 files changed

+92
-32
lines changed

src/parser/context-decls.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,11 @@ Result<> ParseDeclsCtx::addFunc(Name name,
8282
Result<Table*> ParseDeclsCtx::addTableDecl(Index pos,
8383
Name name,
8484
ImportNames* importNames,
85-
Limits limits) {
85+
TableType type) {
8686
auto t = std::make_unique<Table>();
87-
t->initial = limits.initial;
88-
t->max = limits.max ? *limits.max : Table::kUnlimitedSize;
87+
t->indexType = type.type;
88+
t->initial = type.limits.initial;
89+
t->max = type.limits.max ? *type.limits.max : Table::kUnlimitedSize;
8990
if (name.is()) {
9091
if (wasm.getTableOrNull(name)) {
9192
// TODO: if the existing table is not explicitly named, fix its name and
@@ -105,10 +106,10 @@ Result<Table*> ParseDeclsCtx::addTableDecl(Index pos,
105106
Result<> ParseDeclsCtx::addTable(Name name,
106107
const std::vector<Name>& exports,
107108
ImportNames* import,
108-
Limits limits,
109+
TableType type,
109110
Index pos) {
110111
CHECK_ERR(checkImport(pos, import));
111-
auto t = addTableDecl(pos, name, import, limits);
112+
auto t = addTableDecl(pos, name, import, type);
112113
CHECK_ERR(t);
113114
CHECK_ERR(addExports(in, wasm, *t, exports, ExternalKind::Table));
114115
// TODO: table annotations

src/parser/contexts.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ struct Memarg {
5656
uint32_t align;
5757
};
5858

59+
struct TableType {
60+
Type type;
61+
Limits limits;
62+
};
63+
5964
// The location, possible name, and index in the respective module index space
6065
// of a module-level definition in the input.
6166
struct DefPos {
@@ -853,7 +858,7 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
853858
using LimitsT = Limits;
854859
using ElemListT = Index;
855860
using DataStringT = std::vector<char>;
856-
using TableTypeT = Limits;
861+
using TableTypeT = TableType;
857862
using MemTypeT = MemType;
858863

859864
Lexer in;
@@ -942,7 +947,7 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
942947

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

945-
Limits makeTableType(Limits limits, TypeT) { return limits; }
950+
TableType makeTableType(Type type, Limits limits, TypeT) { return {type, limits}; }
946951

947952
std::vector<char> makeDataString() { return {}; }
948953
void appendDataString(std::vector<char>& data, std::string_view str) {
@@ -976,9 +981,9 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
976981
Index pos);
977982

978983
Result<Table*>
979-
addTableDecl(Index pos, Name name, ImportNames* importNames, Limits limits);
984+
addTableDecl(Index pos, Name name, ImportNames* importNames, TableType limits);
980985
Result<>
981-
addTable(Name, const std::vector<Name>&, ImportNames*, Limits, Index);
986+
addTable(Name, const std::vector<Name>&, ImportNames*, TableType, Index);
982987

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

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

1255-
Type makeTableType(LimitsT, Type type) { return type; }
1260+
Type makeTableType(Type indexType, LimitsT, Type type) { return type; }
12561261

12571262
LimitsT getLimitsFromData(DataStringT) { return Ok{}; }
12581263
MemTypeT makeMemType(Type, LimitsT, bool) { return Ok{}; }
@@ -1441,7 +1446,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
14411446

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

1444-
TableTypeT makeTableType(LimitsT, Type) { return Ok{}; }
1449+
TableTypeT makeTableType(Type, LimitsT, Type) { return Ok{}; }
14451450

14461451
struct CatchInfo {
14471452
Name tag;

src/parser/parsers.h

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ template<typename Ctx> Result<typename Ctx::MemTypeT> memtype(Ctx&);
4444
template<typename Ctx>
4545
Result<typename Ctx::MemTypeT> memtypeContinued(Ctx&, Type indexType);
4646
template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx&);
47+
template<typename Ctx>
48+
Result<typename Ctx::TableTypeT> tabletypeContinued(Ctx&, Type indexType);
4749
template<typename Ctx> Result<typename Ctx::GlobalTypeT> globaltype(Ctx&);
4850
template<typename Ctx> Result<uint32_t> tupleArity(Ctx&);
4951

@@ -817,14 +819,27 @@ Result<typename Ctx::MemTypeT> memtypeContinued(Ctx& ctx, Type indexType) {
817819

818820
// tabletype ::= limits32 reftype
819821
template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx& ctx) {
820-
auto limits = limits32(ctx);
822+
Type indexType = Type::i32;
823+
if (ctx.in.takeKeyword("i64"sv)) {
824+
indexType = Type::i64;
825+
} else {
826+
ctx.in.takeKeyword("i32"sv);
827+
}
828+
return tabletypeContinued(ctx, indexType);
829+
}
830+
831+
// tabletype ::= limits32 reftype
832+
template<typename Ctx>
833+
Result<typename Ctx::TableTypeT> tabletypeContinued(Ctx& ctx, Type indexType) {
834+
auto limits = indexType == Type::i32 ? limits32(ctx) : limits64(ctx);
821835
CHECK_ERR(limits);
822836
auto type = reftype(ctx);
823837
CHECK_ERR(type);
838+
824839
if (!type) {
825840
return ctx.in.err("expected reftype");
826841
}
827-
return ctx.makeTableType(*limits, *type);
842+
return ctx.makeTableType(indexType, *limits, *type);
828843
}
829844

830845
// globaltype ::= t:valtype => const t
@@ -3069,6 +3084,13 @@ template<typename Ctx> MaybeResult<> table(Ctx& ctx) {
30693084
auto import = inlineImport(ctx.in);
30703085
CHECK_ERR(import);
30713086

3087+
auto indexType = Type::i32;
3088+
if (ctx.in.takeKeyword("i64"sv)) {
3089+
indexType = Type::i64;
3090+
} else {
3091+
ctx.in.takeKeyword("i32"sv);
3092+
}
3093+
30723094
// Reftype if we have inline elements.
30733095
auto type = reftype(ctx);
30743096
CHECK_ERR(type);
@@ -3103,10 +3125,10 @@ template<typename Ctx> MaybeResult<> table(Ctx& ctx) {
31033125
if (!ctx.in.takeRParen()) {
31043126
return ctx.in.err("expected end of inline elems");
31053127
}
3106-
ttype = ctx.makeTableType(ctx.getLimitsFromElems(list), *type);
3128+
ttype = ctx.makeTableType(indexType, ctx.getLimitsFromElems(list), *type);
31073129
elems = std::move(list);
31083130
} else {
3109-
auto tabtype = tabletype(ctx);
3131+
auto tabtype = tabletypeContinued(ctx, indexType);
31103132
CHECK_ERR(tabtype);
31113133
ttype = *tabtype;
31123134
}

src/wasm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,9 +2294,11 @@ class Table : public Importable {
22942294

22952295
Address initial = 0;
22962296
Address max = kMaxSize;
2297+
Type indexType = Type::i32;
22972298
Type type = Type(HeapType::func, Nullable);
22982299

22992300
bool hasMax() { return max != kUnlimitedSize; }
2301+
bool is64() { return indexType == Type::i64; }
23002302
void clear() {
23012303
name = "";
23022304
initial = 0;

src/wasm/wasm-binary.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ void WasmBinaryWriter::writeTableDeclarations() {
736736
table->max,
737737
table->hasMax(),
738738
/*shared=*/false,
739-
/*is64*/ false);
739+
table->is64());
740740
});
741741
finishSection(start);
742742
}
@@ -2545,18 +2545,14 @@ void WasmBinaryReader::readImports() {
25452545
table->type = getType();
25462546

25472547
bool is_shared;
2548-
Type indexType;
25492548
getResizableLimits(table->initial,
25502549
table->max,
25512550
is_shared,
2552-
indexType,
2551+
table->indexType,
25532552
Table::kUnlimitedSize);
25542553
if (is_shared) {
25552554
throwError("Tables may not be shared");
25562555
}
2557-
if (indexType == Type::i64) {
2558-
throwError("Tables may not be 64-bit");
2559-
}
25602556

25612557
wasm.addTable(std::move(table));
25622558
break;
@@ -3345,16 +3341,14 @@ void WasmBinaryReader::readTableDeclarations() {
33453341
}
33463342
auto table = Builder::makeTable(Name::fromInt(i), elemType);
33473343
bool is_shared;
3348-
Type indexType;
3349-
getResizableLimits(
3350-
table->initial, table->max, is_shared, indexType, Table::kUnlimitedSize);
3344+
getResizableLimits(table->initial,
3345+
table->max,
3346+
is_shared,
3347+
table->indexType,
3348+
Table::kUnlimitedSize);
33513349
if (is_shared) {
33523350
throwError("Tables may not be shared");
33533351
}
3354-
if (indexType == Type::i64) {
3355-
throwError("Tables may not be 64-bit");
3356-
}
3357-
33583352
wasm.addTable(std::move(table));
33593353
}
33603354
}

src/wasm/wasm-validator.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -947,10 +947,14 @@ void FunctionValidator::visitCall(Call* curr) {
947947

948948
void FunctionValidator::visitCallIndirect(CallIndirect* curr) {
949949
validateReturnCall(curr);
950-
shouldBeEqualOrFirstIsUnreachable(curr->target->type,
951-
Type(Type::i32),
952-
curr,
953-
"indirect call target must be an i32");
950+
951+
auto* table = getModule()->getTableOrNull(curr->table);
952+
953+
shouldBeEqualOrFirstIsUnreachable(
954+
curr->target->type,
955+
table->indexType,
956+
curr,
957+
"indirect call target must match the table index type");
954958

955959
if (curr->target->type != Type::unreachable) {
956960
auto* table = getModule()->getTableOrNull(curr->table);
@@ -3841,6 +3845,11 @@ static void validateTables(Module& module, ValidationInfo& info) {
38413845
"Only funcref and externref are valid for table type "
38423846
"(when gc is disabled)");
38433847
}
3848+
if (table->is64()) {
3849+
info.shouldBeTrue(module.features.hasMemory64(),
3850+
"memory",
3851+
"64-bit tables require memory64 [--enable-memory64]");
3852+
}
38443853
}
38453854

38463855
for (auto& segment : module.elementSegments) {

test/lit/table64-limits.wast

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
;; RUN: wasm-opt %s --enable-memory64 --roundtrip -S -o - | filecheck %s
3+
4+
(module
5+
;; CHECK: (type $0 (func))
6+
7+
;; CHECK: (table $0 1 4294967296 funcref)
8+
(table $0 i64 1 4294967296 funcref)
9+
10+
;; CHECK: (func $call_i64
11+
;; CHECK-NEXT: (call_indirect (type $0)
12+
;; CHECK-NEXT: (i64.const 8589934592)
13+
;; CHECK-NEXT: )
14+
;; CHECK-NEXT: )
15+
(func $call_i64
16+
(call_indirect (i64.const 8589934592))
17+
)
18+
19+
;; CHECK: (func $call_i64_explicit
20+
;; CHECK-NEXT: (call_indirect (type $0)
21+
;; CHECK-NEXT: (i64.const 8589934592)
22+
;; CHECK-NEXT: )
23+
;; CHECK-NEXT: )
24+
(func $call_i64_explicit
25+
(call_indirect $0 (i64.const 8589934592))
26+
)
27+
)

0 commit comments

Comments
 (0)