diff options
author | Thomas Lively <tlively@google.com> | 2024-07-11 17:06:55 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-11 14:06:55 -0700 |
commit | c64ac5d5a676fdbb9b108e0ad16c293a32a9b611 (patch) | |
tree | 19d94b975bce4b7df8f52cf357d388e86dab2b84 /src | |
parent | 020e6cc7923419520f6fe825912f17b811770ce8 (diff) | |
download | binaryen-c64ac5d5a676fdbb9b108e0ad16c293a32a9b611.tar.gz binaryen-c64ac5d5a676fdbb9b108e0ad16c293a32a9b611.tar.bz2 binaryen-c64ac5d5a676fdbb9b108e0ad16c293a32a9b611.zip |
[wasm-split] Use a fresh table when reference types are enabled (#6726)
Rather than trying to trampoline primary-to-secondary calls through an
existing table, just create a fresh table for this purpose. This ensures
that modifications to the existing tables cannot interfere with
primary-to-secondary calls and conversely that loading the secondary
module cannot overwrite modifications to the tables.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/module-splitting.cpp | 31 |
1 files changed, 18 insertions, 13 deletions
diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp index 50809a9a4..22f8b301f 100644 --- a/src/ir/module-splitting.cpp +++ b/src/ir/module-splitting.cpp @@ -147,15 +147,23 @@ void TableSlotManager::addSlot(Name func, Slot slot) { } TableSlotManager::TableSlotManager(Module& module) : module(module) { + if (module.features.hasReferenceTypes()) { + // Just create a new table to manage all primary-to-secondary calls lazily. + // Do not re-use slots for functions that will already be in existing + // tables, since that is not correct in the face of table mutations. + // TODO: Reduce overhead by creating a separate table for each function type + // if WasmGC is enabled. + return; + } + // TODO: Reject or handle passive element segments - // TODO: If reference types are enabled, just create a fresh table to make bad - // interactions with user code impossible. auto funcref = Type(HeapType::func, Nullable); auto it = std::find_if( module.tables.begin(), module.tables.end(), [&](std::unique_ptr<Table>& table) { return table->type == funcref; }); if (it == module.tables.end()) { + // There is no indirect function table, so we will create one lazily. return; } @@ -560,18 +568,15 @@ void ModuleSplitter::indirectReferencesToSecondaryFunctions() { } gatherer(*this); gatherer.walkModule(&primary); - // Find all RefFuncs in active elementSegments, which we can ignore: tables - // are the means by which we connect the modules, and are handled directly. - // Passive segments, however, are like RefFuncs in code, and we need to not - // ignore them here. + // Ignore references to secondary functions that occur in the active segment + // that will contain the imported placeholders. Indirect calls to table slots + // initialized by that segment will already go to the right place once the + // secondary module has been loaded and the table has been patched. std::unordered_set<RefFunc*> ignore; - for (auto& seg : primary.elementSegments) { - if (!seg->table.is()) { - continue; - } - for (auto* curr : seg->data) { - if (auto* refFunc = curr->dynCast<RefFunc>()) { - ignore.insert(refFunc); + if (tableManager.activeSegment) { + for (auto* expr : tableManager.activeSegment->data) { + if (auto* ref = expr->dynCast<RefFunc>()) { + ignore.insert(ref); } } } |