Skip to content

Commit 7f4bc4c

Browse files
committed
[RT] Add type to tables and elem segments
This will add support for other reference types to tables and elems.
1 parent c59df4c commit 7f4bc4c

20 files changed

+498
-81
lines changed

src/binaryen-c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3378,7 +3378,7 @@ BinaryenTableRef BinaryenAddTable(BinaryenModuleRef module,
33783378
const char* name,
33793379
BinaryenIndex initial,
33803380
BinaryenIndex maximum) {
3381-
auto table = Builder::makeTable(name, initial, maximum);
3381+
auto table = Builder::makeTable(name, Type::funcref, initial, maximum);
33823382
table->hasExplicitName = true;
33833383
return ((Module*)module)->addTable(std::move(table));
33843384
}

src/ir/element-utils.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ namespace ElementUtils {
2828
template<typename T>
2929
inline void iterElementSegmentFunctionNames(ElementSegment* segment,
3030
T visitor) {
31-
// TODO(reference-types): return early if segment type is non-funcref
31+
if (!segment->type.isFunction()) {
32+
return;
33+
}
34+
3235
for (Index i = 0; i < segment->data.size(); i++) {
3336
if (auto* get = segment->data[i]->dynCast<RefFunc>()) {
3437
visitor(get->func, i);

src/ir/module-splitting.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,16 @@ void TableSlotManager::addSlot(Name func, Slot slot) {
157157
TableSlotManager::TableSlotManager(Module& module) : module(module) {
158158
// TODO: Reject or handle passive element segments
159159

160-
if (module.tables.empty()) {
160+
auto it = std::find_if(module.tables.begin(),
161+
module.tables.end(),
162+
[&](std::unique_ptr<Table>& table) {
163+
return table->type == Type::funcref;
164+
});
165+
if (it == module.tables.end()) {
161166
return;
162167
}
163168

164-
activeTable = module.tables.front().get();
169+
activeTable = it->get();
165170
ModuleUtils::iterTableSegments(
166171
module, activeTable->name, [&](ElementSegment* segment) {
167172
activeTableSegments.push_back(segment);
@@ -172,6 +177,7 @@ TableSlotManager::TableSlotManager(Module& module) : module(module) {
172177
// append new items at constant offsets after all existing items at constant
173178
// offsets.
174179
if (activeTableSegments.size() == 1 &&
180+
activeTableSegments[0]->type == Type::funcref &&
175181
!activeTableSegments[0]->offset->is<Const>()) {
176182
assert(activeTableSegments[0]->offset->is<GlobalGet>() &&
177183
"Unexpected initializer instruction");
@@ -204,7 +210,8 @@ TableSlotManager::TableSlotManager(Module& module) : module(module) {
204210
}
205211

206212
Table* TableSlotManager::makeTable() {
207-
return module.addTable(Builder::makeTable(Name::fromInt(0)));
213+
return module.addTable(
214+
Builder::makeTable(Names::getValidTableName(module, Name::fromInt(0))));
208215
}
209216

210217
TableSlotManager::Slot TableSlotManager::getSlot(RefFunc* entry) {
@@ -533,7 +540,7 @@ void ModuleSplitter::setupTablePatching() {
533540

534541
auto offset = ExpressionManipulator::copy(primarySeg->offset, secondary);
535542
auto secondarySeg = std::make_unique<ElementSegment>(
536-
secondaryTable->name, offset, secondaryElems);
543+
secondaryTable->name, offset, secondaryTable->type, secondaryElems);
537544
secondarySeg->setName(primarySeg->name, primarySeg->hasExplicitName);
538545
secondary.addElementSegment(std::move(secondarySeg));
539546
return;
@@ -545,8 +552,8 @@ void ModuleSplitter::setupTablePatching() {
545552
std::vector<Expression*> currData;
546553
auto finishSegment = [&]() {
547554
auto* offset = Builder(secondary).makeConst(int32_t(currBase));
548-
auto secondarySeg =
549-
std::make_unique<ElementSegment>(secondaryTable->name, offset, currData);
555+
auto secondarySeg = std::make_unique<ElementSegment>(
556+
secondaryTable->name, offset, secondaryTable->type, currData);
550557
secondarySeg->setName(Name::fromInt(secondary.elementSegments.size()),
551558
false);
552559
secondary.addElementSegment(std::move(secondarySeg));

src/ir/module-utils.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ inline ElementSegment* copyElementSegment(const ElementSegment* segment,
7676
auto copy = [&](std::unique_ptr<ElementSegment>&& ret) {
7777
ret->name = segment->name;
7878
ret->hasExplicitName = segment->hasExplicitName;
79+
ret->type = segment->type;
7980
ret->data.reserve(segment->data.size());
8081
for (auto* item : segment->data) {
8182
ret->data.push_back(ExpressionManipulator::copy(item, out));
@@ -92,9 +93,11 @@ inline ElementSegment* copyElementSegment(const ElementSegment* segment,
9293
}
9394
}
9495

95-
inline Table* copyTable(Table* table, Module& out) {
96+
inline Table* copyTable(const Table* table, Module& out) {
9697
auto ret = std::make_unique<Table>();
9798
ret->name = table->name;
99+
ret->hasExplicitName = table->hasExplicitName;
100+
ret->type = table->type;
98101
ret->module = table->module;
99102
ret->base = table->base;
100103

@@ -510,6 +513,12 @@ inline void collectHeapTypes(Module& wasm,
510513
for (auto& curr : wasm.events) {
511514
counts.note(curr->sig);
512515
}
516+
for (auto& curr : wasm.tables) {
517+
counts.maybeNote(curr->type);
518+
}
519+
for (auto& curr : wasm.elementSegments) {
520+
counts.maybeNote(curr->type);
521+
}
513522

514523
// Collect info from functions in parallel.
515524
ModuleUtils::ParallelFunctionAnalysis<Counts> analysis(

src/passes/Print.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2674,7 +2674,8 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
26742674
if (curr->hasMax()) {
26752675
o << ' ' << curr->max;
26762676
}
2677-
o << " funcref)";
2677+
o << ' ';
2678+
printType(o, curr->type, currModule) << ')';
26782679
}
26792680
void visitTable(Table* curr) {
26802681
if (curr->imported()) {
@@ -2711,9 +2712,9 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
27112712
});
27122713
auto printElemType = [&]() {
27132714
if (allElementsRefFunc) {
2714-
TypeNamePrinter(o, currModule).print(HeapType::func);
2715+
o << "func";
27152716
} else {
2716-
TypeNamePrinter(o, currModule).print(Type::funcref);
2717+
printType(o, curr->type, currModule);
27172718
}
27182719
};
27192720

src/shell-interface.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
143143
wasm.memory.initial = 1;
144144
wasm.memory.max = 2;
145145
}
146+
147+
ModuleUtils::iterImportedTables(wasm, [&](Table* table) {
148+
if (table->module == SPECTEST && table->base == TABLE) {
149+
table->initial = 10;
150+
table->max = 20;
151+
}
152+
});
146153
}
147154

148155
Literals callImport(Function* import, LiteralList& arguments) override {
@@ -234,8 +241,13 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
234241
memory.set<std::array<uint8_t, 16>>(addr, value);
235242
}
236243

237-
void tableStore(Name tableName, Address addr, Literal entry) override {
238-
tables[tableName][addr] = entry;
244+
void tableStore(Name tableName, Address addr, const Literal& entry) override {
245+
auto& table = tables[tableName];
246+
if (addr >= table.size()) {
247+
trap("out of bounds table access");
248+
} else {
249+
table.emplace(table.begin() + addr, entry);
250+
}
239251
}
240252

241253
bool growMemory(Address /*oldSize*/, Address newSize) override {

src/tools/fuzzing.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ class TranslateToFuzzReader {
430430
// needed.
431431
if (wasm.tables.empty()) {
432432
auto table = builder.makeTable(
433-
Names::getValidTableName(wasm, "fuzzing_table"), 0, 0);
433+
Names::getValidTableName(wasm, "fuzzing_table"), Type::funcref, 0, 0);
434434
table->hasExplicitName = true;
435435
wasm.addTable(std::move(table));
436436
}

src/tools/wasm-ctor-eval.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
301301
}
302302

303303
// called during initialization, but we don't keep track of a table
304-
void tableStore(Name tableName, Address addr, Literal value) override {}
304+
void tableStore(Name tableName, Address addr, const Literal& value) override {
305+
}
305306

306307
bool growMemory(Address /*oldSize*/, Address newSize) override {
307308
throw FailToEvalException("grow memory");

src/wasm-builder.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,13 @@ class Builder {
7979
return func;
8080
}
8181

82-
static std::unique_ptr<Table>
83-
makeTable(Name name, Address initial = 0, Address max = Table::kMaxSize) {
82+
static std::unique_ptr<Table> makeTable(Name name,
83+
Type type = Type::funcref,
84+
Address initial = 0,
85+
Address max = Table::kMaxSize) {
8486
auto table = std::make_unique<Table>();
8587
table->name = name;
88+
table->type = type;
8689
table->initial = initial;
8790
table->max = max;
8891

src/wasm-interpreter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2222,7 +2222,8 @@ template<typename GlobalManager, typename SubType> class ModuleInstanceBase {
22222222
WASM_UNREACHABLE("unimp");
22232223
}
22242224

2225-
virtual void tableStore(Name tableName, Address addr, Literal entry) {
2225+
virtual void
2226+
tableStore(Name tableName, Address addr, const Literal& entry) {
22262227
WASM_UNREACHABLE("unimp");
22272228
}
22282229
};

src/wasm.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,13 +1722,17 @@ class ElementSegment : public Named {
17221722
public:
17231723
Name table;
17241724
Expression* offset;
1725+
Type type = Type::funcref;
17251726
std::vector<Expression*> data;
17261727

17271728
ElementSegment() = default;
1728-
ElementSegment(Name table, Expression* offset)
1729-
: table(table), offset(offset) {}
1730-
ElementSegment(Name table, Expression* offset, std::vector<Expression*>& init)
1731-
: table(table), offset(offset) {
1729+
ElementSegment(Name table, Expression* offset, Type type = Type::funcref)
1730+
: table(table), offset(offset), type(type) {}
1731+
ElementSegment(Name table,
1732+
Expression* offset,
1733+
Type type,
1734+
std::vector<Expression*>& init)
1735+
: table(table), offset(offset), type(type) {
17321736
data.swap(init);
17331737
}
17341738
};
@@ -1742,6 +1746,7 @@ class Table : public Importable {
17421746

17431747
Address initial = 0;
17441748
Address max = kMaxSize;
1749+
Type type = Type::funcref;
17451750

17461751
bool hasMax() { return max != kUnlimitedSize; }
17471752
void clear() {

src/wasm/wasm-binary.cpp

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ void WasmBinaryWriter::writeImports() {
291291
BYN_TRACE("write one table\n");
292292
writeImportHeader(table);
293293
o << U32LEB(int32_t(ExternalKind::Table));
294-
o << S32LEB(BinaryConsts::EncodedType::funcref);
294+
writeType(table->type);
295295
writeResizableLimits(table->initial,
296296
table->max,
297297
table->hasMax(),
@@ -543,7 +543,7 @@ void WasmBinaryWriter::writeTableDeclarations() {
543543
auto num = importInfo->getNumDefinedTables();
544544
o << U32LEB(num);
545545
ModuleUtils::iterDefinedTables(*wasm, [&](Table* table) {
546-
o << S32LEB(BinaryConsts::EncodedType::funcref);
546+
writeType(table->type);
547547
writeResizableLimits(table->initial,
548548
table->max,
549549
table->hasMax(),
@@ -604,8 +604,8 @@ void WasmBinaryWriter::writeElementSegments() {
604604

605605
if (isPassive || hasTableIndex) {
606606
if (usesExpressions) {
607-
// elemType funcref
608-
writeType(Type::funcref);
607+
// elemType
608+
writeType(segment->type);
609609
} else {
610610
// elemKind funcref
611611
o << U32LEB(0);
@@ -1994,11 +1994,7 @@ void WasmBinaryBuilder::readImports() {
19941994
auto table = builder.makeTable(name);
19951995
table->module = module;
19961996
table->base = base;
1997-
auto elementType = getS32LEB();
1998-
WASM_UNUSED(elementType);
1999-
if (elementType != BinaryConsts::EncodedType::funcref) {
2000-
throwError("Imported table type is not funcref");
2001-
}
1997+
table->type = getType();
20021998

20031999
bool is_shared;
20042000
Type indexType;
@@ -2765,11 +2761,11 @@ void WasmBinaryBuilder::readTableDeclarations() {
27652761
auto numTables = getU32LEB();
27662762

27672763
for (size_t i = 0; i < numTables; i++) {
2768-
auto elemType = getS32LEB();
2769-
if (elemType != BinaryConsts::EncodedType::funcref) {
2770-
throwError("Non-funcref tables not yet supported");
2764+
auto elemType = getType();
2765+
if (!elemType.isRef()) {
2766+
throwError("Table type must be a reference type");
27712767
}
2772-
auto table = Builder::makeTable(Name::fromInt(i));
2768+
auto table = Builder::makeTable(Name::fromInt(i), elemType);
27732769
bool is_shared;
27742770
Type indexType;
27752771
getResizableLimits(
@@ -2811,38 +2807,35 @@ void WasmBinaryBuilder::readElementSegments() {
28112807
continue;
28122808
}
28132809

2810+
auto segment = std::make_unique<ElementSegment>();
2811+
segment->setName(Name::fromInt(i), false);
2812+
28142813
if (!isPassive) {
28152814
Index tableIdx = 0;
28162815
if (hasTableIdx) {
28172816
tableIdx = getU32LEB();
28182817
}
28192818

2820-
auto makeActiveElem = [&](Table* table) {
2821-
auto segment =
2822-
std::make_unique<ElementSegment>(table->name, readExpression());
2823-
segment->setName(Name::fromInt(i), false);
2824-
elementSegments.push_back(std::move(segment));
2825-
};
2826-
2819+
Table* table = nullptr;
28272820
auto numTableImports = tableImports.size();
28282821
if (tableIdx < numTableImports) {
2829-
makeActiveElem(tableImports[tableIdx]);
2822+
table = tableImports[tableIdx];
28302823
} else if (tableIdx - numTableImports < tables.size()) {
2831-
makeActiveElem(tables[tableIdx - numTableImports].get());
2832-
} else {
2824+
table = tables[tableIdx - numTableImports].get();
2825+
}
2826+
if (!table) {
28332827
throwError("Table index out of range.");
28342828
}
2835-
} else {
2836-
auto segment = std::make_unique<ElementSegment>();
2837-
segment->setName(Name::fromInt(i), false);
2838-
elementSegments.push_back(std::move(segment));
2829+
2830+
segment->table = table->name;
2831+
segment->offset = readExpression();
28392832
}
28402833

28412834
if (isPassive || hasTableIdx) {
28422835
if (usesExpressions) {
2843-
auto type = getType();
2844-
if (type != Type::funcref) {
2845-
throwError("Only funcref elem kinds are valid.");
2836+
segment->type = getType();
2837+
if (segment->type == Type::externref) {
2838+
throwError("externref is not a valid type for element segments");
28462839
}
28472840
} else {
28482841
auto elemKind = getU32LEB();
@@ -2852,7 +2845,7 @@ void WasmBinaryBuilder::readElementSegments() {
28522845
}
28532846
}
28542847

2855-
auto& segmentData = elementSegments.back()->data;
2848+
auto& segmentData = segment->data;
28562849
auto size = getU32LEB();
28572850
if (usesExpressions) {
28582851
for (Index j = 0; j < size; j++) {
@@ -2869,6 +2862,8 @@ void WasmBinaryBuilder::readElementSegments() {
28692862
segmentData.push_back(refFunc);
28702863
}
28712864
}
2865+
2866+
elementSegments.push_back(std::move(segment));
28722867
}
28732868
}
28742869

0 commit comments

Comments
 (0)