[wasm-split] Remove module elements in bulk (NFC) (#8990)

Previously we removed module elements one by one within a loop. But
because `Module` stores a module element in both a map and a vector,
removing a single module element using `removeModuleElement` is O(N),
because it needs to shift all vector elements after it:
https://github.com/WebAssembly/binaryen/blob/302396a676433152a32375a81d71e74687c97a1b/src/wasm/wasm.cpp#L1970-L1979

This removes module elements in bulk using `removeModuleElements`, which
does the shifting only once.

https://github.com/WebAssembly/binaryen/blob/302396a676433152a32375a81d71e74687c97a1b/src/wasm/wasm.cpp#L2004-L2018

Combined with #8986 and #9007, acx_gallery's running time improved by
55.2% (30.6s -> 13.7s), and essentials by 65% (225.1s -> 78.8s). (for
Jul 2026 version)

I guess the main reason for the running time increase in #8441 was this
O(N) `removeModuleElement` called within a loop after all.
diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp
index 2227094..c76f77e 100644
--- a/src/ir/module-splitting.cpp
+++ b/src/ir/module-splitting.cpp
@@ -1065,15 +1065,15 @@
   //    the primary and secondary modules), export the item from the primary and
   //    import it from the using secondary modules.
 
-  std::vector<Name> memoriesToRemove;
+  std::unordered_set<Name> memoriesToRemove;
   for (auto& memory : primary.memories) {
     if (tracker.isUnused(memory->name, tracker.memories)) {
-      memoriesToRemove.push_back(memory->name);
+      memoriesToRemove.insert(memory->name);
     } else if (tracker.usedBySingleSecondary(memory->name, tracker.memories)) {
       auto* secondary =
         tracker.getUsingSecondaries(memory->name, tracker.memories)[0];
       ModuleUtils::copyMemory(memory.get(), *secondary);
-      memoriesToRemove.push_back(memory->name);
+      memoriesToRemove.insert(memory->name);
     } else {
       for (auto* secondary :
            tracker.getUsingSecondaries(memory->name, tracker.memories)) {
@@ -1084,20 +1084,19 @@
       }
     }
   }
-  for (auto& name : memoriesToRemove) {
-    primary.removeMemory(name);
-  }
+  primary.removeMemories(
+    [&](Memory* memory) { return memoriesToRemove.contains(memory->name); });
 
-  std::vector<Name> tablesToRemove;
+  std::unordered_set<Name> tablesToRemove;
   for (auto& table : primary.tables) {
     if (tracker.isUnused(table->name, tracker.tables)) {
-      tablesToRemove.push_back(table->name);
+      tablesToRemove.insert(table->name);
     } else if (tracker.usedBySingleSecondary(table->name, tracker.tables)) {
       auto* secondary =
         tracker.getUsingSecondaries(table->name, tracker.tables)[0];
       assert(!secondary->getTableOrNull(table->name));
       ModuleUtils::copyTable(table.get(), *secondary);
-      tablesToRemove.push_back(table->name);
+      tablesToRemove.insert(table->name);
     } else {
       for (auto* secondary :
            tracker.getUsingSecondaries(table->name, tracker.tables)) {
@@ -1106,11 +1105,10 @@
       }
     }
   }
-  for (auto& name : tablesToRemove) {
-    primary.removeTable(name);
-  }
+  primary.removeTables(
+    [&](Table* table) { return tablesToRemove.count(table->name); });
 
-  std::vector<Name> globalsToRemove;
+  std::unordered_set<Name> globalsToRemove;
   for (auto& global : primary.globals) {
     if (global->mutable_) {
       assert(primary.features.hasMutableGlobals() &&
@@ -1118,12 +1116,12 @@
     }
 
     if (tracker.isUnused(global->name, tracker.globals)) {
-      globalsToRemove.push_back(global->name);
+      globalsToRemove.insert(global->name);
     } else if (tracker.usedBySingleSecondary(global->name, tracker.globals)) {
       auto* secondary =
         tracker.getUsingSecondaries(global->name, tracker.globals)[0];
       ModuleUtils::copyGlobal(global.get(), *secondary);
-      globalsToRemove.push_back(global->name);
+      globalsToRemove.insert(global->name);
     } else {
       for (auto* secondary :
            tracker.getUsingSecondaries(global->name, tracker.globals)) {
@@ -1134,18 +1132,17 @@
       }
     }
   }
-  for (auto& name : globalsToRemove) {
-    primary.removeGlobal(name);
-  }
+  primary.removeGlobals(
+    [&](Global* global) { return globalsToRemove.count(global->name); });
 
-  std::vector<Name> tagsToRemove;
+  std::unordered_set<Name> tagsToRemove;
   for (auto& tag : primary.tags) {
     if (tracker.isUnused(tag->name, tracker.tags)) {
-      tagsToRemove.push_back(tag->name);
+      tagsToRemove.insert(tag->name);
     } else if (tracker.usedBySingleSecondary(tag->name, tracker.tags)) {
       auto* secondary = tracker.getUsingSecondaries(tag->name, tracker.tags)[0];
       ModuleUtils::copyTag(tag.get(), *secondary);
-      tagsToRemove.push_back(tag->name);
+      tagsToRemove.insert(tag->name);
     } else {
       for (auto* secondary :
            tracker.getUsingSecondaries(tag->name, tracker.tags)) {
@@ -1154,45 +1151,43 @@
       }
     }
   }
-  for (auto& name : tagsToRemove) {
-    primary.removeTag(name);
-  }
+  primary.removeTags([&](Tag* tag) { return tagsToRemove.count(tag->name); });
 
   // Move segments that are exclusively used in a secondary module. If not, do
   // nothing. (Segments cannot be imported / exported. They will be handled in
   // indirectReferencesToSecondaryFunctions.)
 
-  std::vector<Name> dataSegmentsToRemove;
+  std::unordered_set<Name> dataSegmentsToRemove;
   for (auto& dataSegment : primary.dataSegments) {
     if (tracker.isUnused(dataSegment->name, tracker.dataSegments)) {
-      dataSegmentsToRemove.push_back(dataSegment->name);
+      dataSegmentsToRemove.insert(dataSegment->name);
     } else if (tracker.usedBySingleSecondary(dataSegment->name,
                                              tracker.dataSegments)) {
       auto* secondary =
         tracker.getUsingSecondaries(dataSegment->name, tracker.dataSegments)[0];
       ModuleUtils::copyDataSegment(dataSegment.get(), *secondary);
-      dataSegmentsToRemove.push_back(dataSegment->name);
+      dataSegmentsToRemove.insert(dataSegment->name);
     }
   }
-  for (auto& name : dataSegmentsToRemove) {
-    primary.removeDataSegment(name);
-  }
+  primary.removeDataSegments([&](DataSegment* dataSegment) {
+    return dataSegmentsToRemove.count(dataSegment->name);
+  });
 
-  std::vector<Name> elementSegmentsToRemove;
+  std::unordered_set<Name> elementSegmentsToRemove;
   for (auto& elementSegment : primary.elementSegments) {
     if (tracker.isUnused(elementSegment->name, tracker.elementSegments)) {
-      elementSegmentsToRemove.push_back(elementSegment->name);
+      elementSegmentsToRemove.insert(elementSegment->name);
     } else if (tracker.usedBySingleSecondary(elementSegment->name,
                                              tracker.elementSegments)) {
       auto* secondary = tracker.getUsingSecondaries(elementSegment->name,
                                                     tracker.elementSegments)[0];
       ModuleUtils::copyElementSegment(elementSegment.get(), *secondary);
-      elementSegmentsToRemove.push_back(elementSegment->name);
+      elementSegmentsToRemove.insert(elementSegment->name);
     }
   }
-  for (auto& name : elementSegmentsToRemove) {
-    primary.removeElementSegment(name);
-  }
+  primary.removeElementSegments([&](ElementSegment* elementSegment) {
+    return elementSegmentsToRemove.count(elementSegment->name);
+  });
 }
 
 void ModuleSplitter::indirectReferencesToSecondaryFunctions() {