summaryrefslogtreecommitdiff
path: root/src/ir
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir')
-rw-r--r--src/ir/ReFinalize.cpp3
-rw-r--r--src/ir/module-splitting.cpp109
-rw-r--r--src/ir/module-utils.h65
-rw-r--r--src/ir/table-utils.cpp8
-rw-r--r--src/ir/table-utils.h61
-rw-r--r--src/ir/utils.h2
6 files changed, 152 insertions, 96 deletions
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index de4184596..a0166381b 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -178,6 +178,9 @@ void ReFinalize::visitFunction(Function* curr) {
void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); }
void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); }
void ReFinalize::visitTable(Table* curr) { WASM_UNREACHABLE("unimp"); }
+void ReFinalize::visitElementSegment(ElementSegment* curr) {
+ WASM_UNREACHABLE("unimp");
+}
void ReFinalize::visitMemory(Memory* curr) { WASM_UNREACHABLE("unimp"); }
void ReFinalize::visitEvent(Event* curr) { WASM_UNREACHABLE("unimp"); }
void ReFinalize::visitModule(Module* curr) { WASM_UNREACHABLE("unimp"); }
diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp
index 7215629e4..d4d03991e 100644
--- a/src/ir/module-splitting.cpp
+++ b/src/ir/module-splitting.cpp
@@ -87,20 +87,18 @@ namespace ModuleSplitting {
namespace {
template<class F> void forEachElement(Module& module, F f) {
- for (auto& table : module.tables) {
- for (auto& segment : table->segments) {
- Name base = "";
- Index offset = 0;
- if (auto* c = segment.offset->dynCast<Const>()) {
- offset = c->value.geti32();
- } else if (auto* g = segment.offset->dynCast<GlobalGet>()) {
- base = g->name;
- }
- for (size_t i = 0; i < segment.data.size(); ++i) {
- f(table->name, base, offset + i, segment.data[i]);
- }
+ ModuleUtils::iterActiveElementSegments(module, [&](ElementSegment* segment) {
+ Name base = "";
+ Index offset = 0;
+ if (auto* c = segment->offset->dynCast<Const>()) {
+ offset = c->value.geti32();
+ } else if (auto* g = segment->offset->dynCast<GlobalGet>()) {
+ base = g->name;
}
- }
+ for (size_t i = 0; i < segment->data.size(); ++i) {
+ f(segment->table, base, offset + i, segment->data[i]);
+ }
+ });
}
struct TableSlotManager {
@@ -116,9 +114,10 @@ struct TableSlotManager {
};
Module& module;
Table* activeTable = nullptr;
- Table::Segment* activeSegment = nullptr;
+ ElementSegment* activeSegment = nullptr;
Slot activeBase;
std::map<Name, Slot> funcIndices;
+ std::vector<ElementSegment*> activeTableSegments;
TableSlotManager(Module& module);
@@ -148,22 +147,29 @@ void TableSlotManager::addSlot(Name func, Slot slot) {
}
TableSlotManager::TableSlotManager(Module& module) : module(module) {
+ // TODO: Reject or handle passive element segments
+
if (module.tables.empty()) {
return;
}
activeTable = module.tables.front().get();
+ ModuleUtils::iterTableSegments(
+ module, activeTable->name, [&](ElementSegment* segment) {
+ activeTableSegments.push_back(segment);
+ });
+
// If there is exactly one table segment and that segment has a non-constant
// offset, append new items to the end of that segment. In all other cases,
// append new items at constant offsets after all existing items at constant
// offsets.
- if (activeTable->segments.size() == 1 &&
- !activeTable->segments[0].offset->is<Const>()) {
- assert(activeTable->segments[0].offset->is<GlobalGet>() &&
+ if (activeTableSegments.size() == 1 &&
+ !activeTableSegments[0]->offset->is<Const>()) {
+ assert(activeTableSegments[0]->offset->is<GlobalGet>() &&
"Unexpected initializer instruction");
- activeSegment = &activeTable->segments[0];
+ activeSegment = activeTableSegments[0];
activeBase = {activeTable->name,
- activeTable->segments[0].offset->cast<GlobalGet>()->name,
+ activeTableSegments[0]->offset->cast<GlobalGet>()->name,
0};
} else {
// Finds the segment with the highest occupied table slot so that new items
@@ -171,13 +177,13 @@ TableSlotManager::TableSlotManager(Module& module) : module(module) {
// overwriting any other items. TODO: be more clever about filling gaps in
// the table, if that is ever useful.
Index maxIndex = 0;
- for (auto& segment : activeTable->segments) {
- assert(segment.offset->is<Const>() &&
+ for (auto& segment : activeTableSegments) {
+ assert(segment->offset->is<Const>() &&
"Unexpected non-const segment offset with multiple segments");
- Index segmentBase = segment.offset->cast<Const>()->value.geti32();
- if (segmentBase + segment.data.size() >= maxIndex) {
- maxIndex = segmentBase + segment.data.size();
- activeSegment = &segment;
+ Index segmentBase = segment->offset->cast<Const>()->value.geti32();
+ if (segmentBase + segment->data.size() >= maxIndex) {
+ maxIndex = segmentBase + segment->data.size();
+ activeSegment = segment;
activeBase = {activeTable->name, "", segmentBase};
}
}
@@ -190,9 +196,7 @@ TableSlotManager::TableSlotManager(Module& module) : module(module) {
}
Table* TableSlotManager::makeTable() {
- module.addTable(Builder::makeTable(Name::fromInt(0)));
-
- return module.tables.front().get();
+ return module.addTable(Builder::makeTable(Name::fromInt(0)));
}
TableSlotManager::Slot TableSlotManager::getSlot(Name func) {
@@ -208,9 +212,16 @@ TableSlotManager::Slot TableSlotManager::getSlot(Name func) {
activeBase = {activeTable->name, "", 0};
}
- assert(activeTable->segments.size() == 0);
- activeTable->segments.emplace_back(Builder(module).makeConst(int32_t(0)));
- activeSegment = &activeTable->segments.back();
+ assert(std::all_of(module.elementSegments.begin(),
+ module.elementSegments.end(),
+ [&](std::unique_ptr<ElementSegment>& segment) {
+ return segment->table != activeTable->name;
+ }));
+ auto segment = std::make_unique<ElementSegment>(
+ activeTable->name, Builder(module).makeConst(int32_t(0)));
+ segment->setName(Name::fromInt(0), false);
+ activeSegment = segment.get();
+ module.addElementSegment(std::move(segment));
}
Slot newSlot = {activeBase.tableName,
@@ -470,13 +481,12 @@ void ModuleSplitter::setupTablePatching() {
}
auto secondaryTable =
- ModuleUtils::copyTableWithoutSegments(tableManager.activeTable, secondary);
+ ModuleUtils::copyTable(tableManager.activeTable, secondary);
if (tableManager.activeBase.global.size()) {
- assert(tableManager.activeTable->segments.size() == 1 &&
+ assert(tableManager.activeTableSegments.size() == 1 &&
"Unexpected number of segments with non-const base");
- assert(secondary.tables.size() == 1 &&
- secondary.tables.front()->segments.empty());
+ assert(secondary.tables.size() == 1 && secondary.elementSegments.empty());
// Since addition is not currently allowed in initializer expressions, we
// need to start the new secondary segment where the primary segment starts.
// The secondary segment will contain the same primary functions as the
@@ -485,29 +495,31 @@ void ModuleSplitter::setupTablePatching() {
// to be imported into the second module. TODO: use better strategies here,
// such as using ref.func in the start function or standardizing addition in
// initializer expressions.
- const Table::Segment& primarySeg =
- tableManager.activeTable->segments.front();
+ const ElementSegment* primarySeg = tableManager.activeTableSegments.front();
std::vector<Name> secondaryElems;
- secondaryElems.reserve(primarySeg.data.size());
+ secondaryElems.reserve(primarySeg->data.size());
// Copy functions from the primary segment to the secondary segment,
// replacing placeholders and creating new exports and imports as necessary.
auto replacement = replacedElems.begin();
for (Index i = 0;
- i < primarySeg.data.size() && replacement != replacedElems.end();
+ i < primarySeg->data.size() && replacement != replacedElems.end();
++i) {
if (replacement->first == i) {
- // primarySeg.data[i] is a placeholder, so use the secondary function.
+ // primarySeg->data[i] is a placeholder, so use the secondary function.
secondaryElems.push_back(replacement->second);
++replacement;
} else {
- exportImportFunction(primarySeg.data[i]);
- secondaryElems.push_back(primarySeg.data[i]);
+ exportImportFunction(primarySeg->data[i]);
+ secondaryElems.push_back(primarySeg->data[i]);
}
}
- auto offset = ExpressionManipulator::copy(primarySeg.offset, secondary);
- secondaryTable->segments.emplace_back(offset, secondaryElems);
+ auto offset = ExpressionManipulator::copy(primarySeg->offset, secondary);
+ auto secondaryElem = std::make_unique<ElementSegment>(
+ secondaryTable->name, offset, secondaryElems);
+ secondaryElem->setName(primarySeg->name, primarySeg->hasExplicitName);
+ secondary.addElementSegment(std::move(secondaryElem));
return;
}
@@ -517,7 +529,11 @@ void ModuleSplitter::setupTablePatching() {
std::vector<Name> currData;
auto finishSegment = [&]() {
auto* offset = Builder(secondary).makeConst(int32_t(currBase));
- secondaryTable->segments.emplace_back(offset, currData);
+ auto secondaryElem =
+ std::make_unique<ElementSegment>(secondaryTable->name, offset, currData);
+ secondaryElem->setName(Name::fromInt(secondary.elementSegments.size()),
+ false);
+ secondary.addElementSegment(std::move(secondaryElem));
};
for (auto curr = replacedElems.begin(); curr != replacedElems.end(); ++curr) {
if (curr->first != currBase + currData.size()) {
@@ -577,8 +593,7 @@ void ModuleSplitter::shareImportableItems() {
for (auto& table : primary.tables) {
auto secondaryTable = secondary.getTableOrNull(table->name);
if (!secondaryTable) {
- secondaryTable =
- ModuleUtils::copyTableWithoutSegments(table.get(), secondary);
+ secondaryTable = ModuleUtils::copyTable(table.get(), secondary);
}
makeImportExport(*table, *secondaryTable, "table", ExternalKind::Table);
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h
index 371239e19..22ed89b37 100644
--- a/src/ir/module-utils.h
+++ b/src/ir/module-utils.h
@@ -70,7 +70,25 @@ inline Event* copyEvent(Event* event, Module& out) {
return ret;
}
-inline Table* copyTableWithoutSegments(Table* table, Module& out) {
+inline ElementSegment* copyElementSegment(const ElementSegment* segment,
+ Module& out) {
+ auto copy = [&](std::unique_ptr<ElementSegment>&& ret) {
+ ret->name = segment->name;
+ ret->hasExplicitName = segment->hasExplicitName;
+ ret->data = segment->data;
+
+ return out.addElementSegment(std::move(ret));
+ };
+
+ if (segment->table.isNull()) {
+ return copy(std::make_unique<ElementSegment>());
+ } else {
+ auto offset = ExpressionManipulator::copy(segment->offset, out);
+ return copy(std::make_unique<ElementSegment>(segment->table, offset));
+ }
+}
+
+inline Table* copyTable(Table* table, Module& out) {
auto ret = std::make_unique<Table>();
ret->name = table->name;
ret->module = table->module;
@@ -82,17 +100,6 @@ inline Table* copyTableWithoutSegments(Table* table, Module& out) {
return out.addTable(std::move(ret));
}
-inline Table* copyTable(Table* table, Module& out) {
- auto ret = copyTableWithoutSegments(table, out);
-
- for (auto segment : table->segments) {
- segment.offset = ExpressionManipulator::copy(segment.offset, out);
- ret->segments.push_back(segment);
- }
-
- return ret;
-}
-
inline void copyModule(const Module& in, Module& out) {
// we use names throughout, not raw pointers, so simple copying is fine
// for everything *but* expressions
@@ -108,9 +115,13 @@ inline void copyModule(const Module& in, Module& out) {
for (auto& curr : in.events) {
copyEvent(curr.get(), out);
}
+ for (auto& curr : in.elementSegments) {
+ copyElementSegment(curr.get(), out);
+ }
for (auto& curr : in.tables) {
copyTable(curr.get(), out);
}
+
out.memory = in.memory;
for (auto& segment : out.memory.segments) {
segment.offset = ExpressionManipulator::copy(segment.offset, out);
@@ -148,11 +159,9 @@ template<typename T> inline void renameFunctions(Module& wasm, T& map) {
}
};
maybeUpdate(wasm.start);
- for (auto& table : wasm.tables) {
- for (auto& segment : table->segments) {
- for (auto& name : segment.data) {
- maybeUpdate(name);
- }
+ for (auto& segment : wasm.elementSegments) {
+ for (auto& name : segment->data) {
+ maybeUpdate(name);
}
}
for (auto& exp : wasm.exports) {
@@ -208,6 +217,28 @@ template<typename T> inline void iterDefinedTables(Module& wasm, T visitor) {
}
}
+template<typename T>
+inline void iterTableSegments(Module& wasm, Name table, T visitor) {
+ // Just a precaution so that we don't iterate over passive elem segments by
+ // accident
+ assert(table.is() && "Table name must not be null");
+
+ for (auto& segment : wasm.elementSegments) {
+ if (segment->table == table) {
+ visitor(segment.get());
+ }
+ }
+}
+
+template<typename T>
+inline void iterActiveElementSegments(Module& wasm, T visitor) {
+ for (auto& segment : wasm.elementSegments) {
+ if (segment->table.is()) {
+ visitor(segment.get());
+ }
+ }
+}
+
template<typename T> inline void iterImportedGlobals(Module& wasm, T visitor) {
for (auto& import : wasm.globals) {
if (import->imported()) {
diff --git a/src/ir/table-utils.cpp b/src/ir/table-utils.cpp
index ef89e50f3..639f8fbe6 100644
--- a/src/ir/table-utils.cpp
+++ b/src/ir/table-utils.cpp
@@ -31,11 +31,9 @@ std::set<Name> getFunctionsNeedingElemDeclare(Module& wasm) {
// Find all the names in the tables.
std::unordered_set<Name> tableNames;
- for (auto& table : wasm.tables) {
- for (auto& segment : table->segments) {
- for (auto name : segment.data) {
- tableNames.insert(name);
- }
+ for (auto& segment : wasm.elementSegments) {
+ for (auto name : segment->data) {
+ tableNames.insert(name);
}
}
diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h
index 80ffc0c06..e90b0ca72 100644
--- a/src/ir/table-utils.h
+++ b/src/ir/table-utils.h
@@ -18,6 +18,7 @@
#define wasm_ir_table_h
#include "ir/literal-utils.h"
+#include "ir/module-utils.h"
#include "wasm-traversal.h"
#include "wasm.h"
@@ -29,32 +30,38 @@ struct FlatTable {
std::vector<Name> names;
bool valid;
- FlatTable(Table& table) {
+ FlatTable(Module& wasm, Table& table) {
valid = true;
- for (auto& segment : table.segments) {
- auto offset = segment.offset;
- if (!offset->is<Const>()) {
- // TODO: handle some non-constant segments
- valid = false;
- return;
- }
- Index start = offset->cast<Const>()->value.geti32();
- Index end = start + segment.data.size();
- if (end > names.size()) {
- names.resize(end);
- }
- for (Index i = 0; i < segment.data.size(); i++) {
- names[start + i] = segment.data[i];
- }
- }
+ ModuleUtils::iterTableSegments(
+ wasm, table.name, [&](ElementSegment* segment) {
+ auto offset = segment->offset;
+ if (!offset->is<Const>()) {
+ // TODO: handle some non-constant segments
+ valid = false;
+ return;
+ }
+ Index start = offset->cast<Const>()->value.geti32();
+ Index end = start + segment->data.size();
+ if (end > names.size()) {
+ names.resize(end);
+ }
+ for (Index i = 0; i < segment->data.size(); i++) {
+ names[start + i] = segment->data[i];
+ }
+ });
}
};
-inline Table::Segment& getSingletonSegment(Table& table, Module& wasm) {
- if (table.segments.size() != 1) {
+inline ElementSegment* getSingletonSegment(Table& table, Module& wasm) {
+ std::vector<ElementSegment*> tableSegments;
+ ModuleUtils::iterTableSegments(
+ wasm, table.name, [&](ElementSegment* segment) {
+ tableSegments.push_back(segment);
+ });
+ if (tableSegments.size() != 1) {
Fatal() << "Table doesn't have a singleton segment.";
}
- return table.segments[0];
+ return tableSegments[0];
}
// Appends a name to the table. This assumes the table has 0 or 1 segments,
@@ -65,10 +72,10 @@ inline Table::Segment& getSingletonSegment(Table& table, Module& wasm) {
// module has a single table segment, and that the dylink section indicates
// we can validly append to that segment, see the check below.
inline Index append(Table& table, Name name, Module& wasm) {
- auto& segment = getSingletonSegment(table, wasm);
- auto tableIndex = segment.data.size();
+ auto* segment = getSingletonSegment(table, wasm);
+ auto tableIndex = segment->data.size();
if (wasm.dylinkSection) {
- if (segment.data.size() != wasm.dylinkSection->tableSize) {
+ if (segment->data.size() != wasm.dylinkSection->tableSize) {
Fatal() << "Appending to the table in a module with a dylink section "
"that has tableSize which indicates it wants to reserve more "
"table space than the actual table elements in the module. "
@@ -77,7 +84,7 @@ inline Index append(Table& table, Name name, Module& wasm) {
}
wasm.dylinkSection->tableSize++;
}
- segment.data.push_back(name);
+ segment->data.push_back(name);
table.initial = table.initial + 1;
return tableIndex;
}
@@ -85,9 +92,9 @@ inline Index append(Table& table, Name name, Module& wasm) {
// Checks if a function is already in the table. Returns that index if so,
// otherwise appends it.
inline Index getOrAppend(Table& table, Name name, Module& wasm) {
- auto& segment = getSingletonSegment(table, wasm);
- for (Index i = 0; i < segment.data.size(); i++) {
- if (segment.data[i] == name) {
+ auto segment = getSingletonSegment(table, wasm);
+ for (Index i = 0; i < segment->data.size(); i++) {
+ if (segment->data[i] == name) {
return i;
}
}
diff --git a/src/ir/utils.h b/src/ir/utils.h
index 424298bb3..f06a68fff 100644
--- a/src/ir/utils.h
+++ b/src/ir/utils.h
@@ -121,6 +121,7 @@ struct ReFinalize
void visitExport(Export* curr);
void visitGlobal(Global* curr);
void visitTable(Table* curr);
+ void visitElementSegment(ElementSegment* curr);
void visitMemory(Memory* curr);
void visitEvent(Event* curr);
void visitModule(Module* curr);
@@ -144,6 +145,7 @@ struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> {
void visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); }
void visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); }
void visitTable(Table* curr) { WASM_UNREACHABLE("unimp"); }
+ void visitElementSegment(ElementSegment* curr) { WASM_UNREACHABLE("unimp"); }
void visitMemory(Memory* curr) { WASM_UNREACHABLE("unimp"); }
void visitEvent(Event* curr) { WASM_UNREACHABLE("unimp"); }
void visitModule(Module* curr) { WASM_UNREACHABLE("unimp"); }