summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2024-07-11 17:06:55 -0400
committerGitHub <noreply@github.com>2024-07-11 14:06:55 -0700
commitc64ac5d5a676fdbb9b108e0ad16c293a32a9b611 (patch)
tree19d94b975bce4b7df8f52cf357d388e86dab2b84 /src
parent020e6cc7923419520f6fe825912f17b811770ce8 (diff)
downloadbinaryen-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.cpp31
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);
}
}
}