diff options
Diffstat (limited to 'src/ir/module-splitting.cpp')
-rw-r--r-- | src/ir/module-splitting.cpp | 74 |
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(); |