summaryrefslogtreecommitdiff
path: root/src/ir/module-splitting.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/module-splitting.cpp')
-rw-r--r--src/ir/module-splitting.cpp74
1 files changed, 35 insertions, 39 deletions
diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp
index 7f12269f8..5f9ba0aad 100644
--- a/src/ir/module-splitting.cpp
+++ b/src/ir/module-splitting.cpp
@@ -54,8 +54,8 @@
// ref.func instructions, they will have to be modified to use a similar layer
// of indirection.
//
-// The code as currently written makes a few assumptions about the module that
-// is being split:
+// The code as currently written makes a couple assumptions about the module
+// that is being split:
//
// 1. It assumes that mutable-globals is allowed. This could be worked around
// by introducing wrapper functions for globals and rewriting secondary
@@ -66,11 +66,6 @@
// is exactly one segment that may have a non-constant offset. It also
// assumes that all segments are active segments (although Binaryen does
// not yet support passive table segments anyway).
-//
-// 3. It assumes that each function appears in the table at most once. This
-// isn't necessarily true in general or even for LLVM output after function
-// deduplication. Relaxing this assumption would just require slightly more
-// complex code, so it is a good candidate for a follow up PR.
#include "ir/module-splitting.h"
#include "ir/element-utils.h"
@@ -103,11 +98,6 @@ template<class F> void forEachElement(Module& module, F f) {
});
}
-static RefFunc* makeRefFunc(Module& wasm, Function* func) {
- // FIXME: make the type NonNullable when we support it!
- return Builder(wasm).makeRefFunc(func->name, func->sig);
-}
-
struct TableSlotManager {
struct Slot {
Name tableName;
@@ -129,9 +119,10 @@ struct TableSlotManager {
TableSlotManager(Module& module);
Table* makeTable();
+ ElementSegment* makeElementSegment();
// Returns the table index for `func`, allocating a new index if necessary.
- Slot getSlot(RefFunc* entry);
+ Slot getSlot(Name func, Signature sig);
void addSlot(Name func, Slot slot);
};
@@ -148,14 +139,12 @@ Expression* TableSlotManager::Slot::makeExpr(Module& module) {
}
void TableSlotManager::addSlot(Name func, Slot slot) {
- auto it = funcIndices.insert(std::make_pair(func, slot));
- WASM_UNUSED(it);
- assert(it.second && "Function already has multiple table slots");
+ // Ignore functions that already have slots.
+ funcIndices.insert({func, slot});
}
TableSlotManager::TableSlotManager(Module& module) : module(module) {
// TODO: Reject or handle passive element segments
-
auto it = std::find_if(module.tables.begin(),
module.tables.end(),
[&](std::unique_ptr<Table>& table) {
@@ -213,8 +202,15 @@ Table* TableSlotManager::makeTable() {
Builder::makeTable(Names::getValidTableName(module, Name::fromInt(0))));
}
-TableSlotManager::Slot TableSlotManager::getSlot(RefFunc* entry) {
- auto slotIt = funcIndices.find(entry->func);
+ElementSegment* TableSlotManager::makeElementSegment() {
+ return module.addElementSegment(Builder::makeElementSegment(
+ Names::getValidElementSegmentName(module, Name::fromInt(0)),
+ activeTable->name,
+ Builder(module).makeConst(int32_t(0))));
+}
+
+TableSlotManager::Slot TableSlotManager::getSlot(Name func, Signature sig) {
+ auto slotIt = funcIndices.find(func);
if (slotIt != funcIndices.end()) {
return slotIt->second;
}
@@ -226,27 +222,27 @@ TableSlotManager::Slot TableSlotManager::getSlot(RefFunc* entry) {
activeBase = {activeTable->name, "", 0};
}
+ // None of the existing segments should refer to the active table
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));
+
+ activeSegment = makeElementSegment();
}
Slot newSlot = {activeBase.tableName,
activeBase.global,
activeBase.index + Index(activeSegment->data.size())};
- activeSegment->data.push_back(entry);
+ Builder builder(module);
+ activeSegment->data.push_back(builder.makeRefFunc(func, sig));
- addSlot(entry->func, newSlot);
+ addSlot(func, newSlot);
if (activeTable->initial <= newSlot.index) {
activeTable->initial = newSlot.index + 1;
+ // TODO: handle the active table not being the dylink table (#3823)
if (module.dylinkSection) {
module.dylinkSection->tableSize = activeTable->initial;
}
@@ -391,18 +387,15 @@ void ModuleSplitter::thunkExportedSecondaryFunctions() {
// We've already created a thunk for this function
continue;
}
- auto func = std::make_unique<Function>();
- func->name = secondaryFunc;
- func->sig = secondary.getFunction(secondaryFunc)->sig;
+ auto* func = primary.addFunction(Builder::makeFunction(
+ secondaryFunc, secondary.getFunction(secondaryFunc)->sig, {}));
std::vector<Expression*> args;
for (size_t i = 0, size = func->sig.params.size(); i < size; ++i) {
args.push_back(builder.makeLocalGet(i, func->sig.params[i]));
}
-
- auto tableSlot = tableManager.getSlot(makeRefFunc(primary, func.get()));
+ auto tableSlot = tableManager.getSlot(secondaryFunc, func->sig);
func->body = builder.makeCallIndirect(
tableSlot.tableName, tableSlot.makeExpr(primary), args, func->sig);
- primary.addFunction(std::move(func));
}
}
@@ -420,9 +413,8 @@ void ModuleSplitter::indirectCallsToSecondaryFunctions() {
if (!parent.secondaryFuncs.count(curr->target)) {
return;
}
- auto func = parent.secondary.getFunction(curr->target);
- auto tableSlot =
- parent.tableManager.getSlot(makeRefFunc(parent.primary, func));
+ auto* func = parent.secondary.getFunction(curr->target);
+ auto tableSlot = parent.tableManager.getSlot(curr->target, func->sig);
replaceCurrent(
builder.makeCallIndirect(tableSlot.tableName,
tableSlot.makeExpr(parent.primary),
@@ -530,7 +522,9 @@ void ModuleSplitter::setupTablePatching() {
++i) {
if (replacement->first == i) {
// primarySeg->data[i] is a placeholder, so use the secondary function.
- secondaryElems.push_back(makeRefFunc(secondary, replacement->second));
+ auto* func = replacement->second;
+ auto* ref = Builder(secondary).makeRefFunc(func->name, func->sig);
+ secondaryElems.push_back(ref);
++replacement;
} else if (auto* get = primarySeg->data[i]->dynCast<RefFunc>()) {
exportImportFunction(get->func);
@@ -556,8 +550,9 @@ void ModuleSplitter::setupTablePatching() {
auto* offset = Builder(secondary).makeConst(int32_t(currBase));
auto secondarySeg = std::make_unique<ElementSegment>(
secondaryTable->name, offset, secondaryTable->type, currData);
- secondarySeg->setName(Name::fromInt(secondary.elementSegments.size()),
- false);
+ Name name = Names::getValidElementSegmentName(
+ secondary, Name::fromInt(secondary.elementSegments.size()));
+ secondarySeg->setName(name, false);
secondary.addElementSegment(std::move(secondarySeg));
};
for (auto curr = replacedElems.begin(); curr != replacedElems.end(); ++curr) {
@@ -566,7 +561,8 @@ void ModuleSplitter::setupTablePatching() {
currBase = curr->first;
currData.clear();
}
- currData.push_back(makeRefFunc(secondary, curr->second));
+ auto* func = curr->second;
+ currData.push_back(Builder(secondary).makeRefFunc(func->name, func->sig));
}
if (currData.size()) {
finishSegment();