From 20d5bffc7ff70c21f8584982c2790c008505bda1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jun 2026 09:38:38 -0700 Subject: [PATCH 1/7] test/ tests --- src/tools/wasm-merge.cpp | 56 ++++++++++++++++--- test/lit/merge/rename-internal-conflict.wat | 22 ++++++++ .../merge/rename-internal-conflict.wat.second | 6 ++ 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 test/lit/merge/rename-internal-conflict.wat create mode 100644 test/lit/merge/rename-internal-conflict.wat.second diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp index 66800ed08ab..69a729cd252 100644 --- a/src/tools/wasm-merge.cpp +++ b/src/tools/wasm-merge.cpp @@ -304,35 +304,77 @@ void renameInputItems(Module& input) { } }; + auto getValidNameHelper = [&](Name root, + auto getOrNullMerged, + auto getOrNullInput, + Index hint) { + return Names::getValidName( + root, + [&](Name test) { + return !getOrNullMerged(test) && + (!getOrNullInput(test) || test == root); + }, + hint); + }; + for (auto& curr : input.functions) { - auto name = Names::getValidFunctionName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getFunctionOrNull(test); }, + [&](Name test) { return input.getFunctionOrNull(test); }, + merged.functions.size()); maybeAdd(ModuleItemKind::Function, curr->name, name); } for (auto& curr : input.globals) { - auto name = Names::getValidGlobalName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getGlobalOrNull(test); }, + [&](Name test) { return input.getGlobalOrNull(test); }, + merged.globals.size()); maybeAdd(ModuleItemKind::Global, curr->name, name); } for (auto& curr : input.tags) { - auto name = Names::getValidTagName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getTagOrNull(test); }, + [&](Name test) { return input.getTagOrNull(test); }, + merged.tags.size()); maybeAdd(ModuleItemKind::Tag, curr->name, name); } for (auto& curr : input.elementSegments) { - auto name = Names::getValidElementSegmentName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getElementSegmentOrNull(test); }, + [&](Name test) { return input.getElementSegmentOrNull(test); }, + merged.elementSegments.size()); maybeAdd(ModuleItemKind::ElementSegment, curr->name, name); } for (auto& curr : input.memories) { - auto name = Names::getValidMemoryName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getMemoryOrNull(test); }, + [&](Name test) { return input.getMemoryOrNull(test); }, + merged.memories.size()); maybeAdd(ModuleItemKind::Memory, curr->name, name); } for (auto& curr : input.dataSegments) { - auto name = Names::getValidDataSegmentName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getDataSegmentOrNull(test); }, + [&](Name test) { return input.getDataSegmentOrNull(test); }, + merged.dataSegments.size()); maybeAdd(ModuleItemKind::DataSegment, curr->name, name); } for (auto& curr : input.tables) { - auto name = Names::getValidTableName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getTableOrNull(test); }, + [&](Name test) { return input.getTableOrNull(test); }, + merged.tables.size()); maybeAdd(ModuleItemKind::Table, curr->name, name); } + // Apply the names to their uses. updateNames(input, kindNameUpdates); } diff --git a/test/lit/merge/rename-internal-conflict.wat b/test/lit/merge/rename-internal-conflict.wat new file mode 100644 index 00000000000..0fa4a9e3ce9 --- /dev/null +++ b/test/lit/merge/rename-internal-conflict.wat @@ -0,0 +1,22 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: wasm-merge %s first %s.second second -all -S -o - | filecheck %s + +;; The global and export have name collisions with the side module, but even +;; worse, the alternative names we initially pick (adding _1) are themselves +;; also existing names. + +(module + ;; CHECK: (global $classVTable (mut i32) (i32.const 1)) + (global $classVTable (mut i32) (i32.const 1)) + + ;; CHECK: (global $classVTable_2 (mut i32) (i32.const 2)) + + ;; CHECK: (global $classVTable_1 (mut i32) (i32.const 3)) + + ;; CHECK: (export "classVTable" (global $classVTable)) + (export "classVTable" (global $classVTable)) +) + +;; CHECK: (export "classVTable_b" (global $classVTable_2)) + +;; CHECK: (export "classVTable_1" (global $classVTable_1)) diff --git a/test/lit/merge/rename-internal-conflict.wat.second b/test/lit/merge/rename-internal-conflict.wat.second new file mode 100644 index 00000000000..c6246b57d6d --- /dev/null +++ b/test/lit/merge/rename-internal-conflict.wat.second @@ -0,0 +1,6 @@ +(module + (global $classVTable (mut i32) (i32.const 2)) + (global $classVTable_1 (mut i32) (i32.const 3)) + (export "classVTable_b" (global $classVTable)) + (export "classVTable_1" (global $classVTable_1)) +) From bd2a9af2bc338268be40e7604f27ecfe9f7ff65e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jun 2026 09:39:16 -0700 Subject: [PATCH 2/7] undo --- src/tools/wasm-merge.cpp | 56 +++++----------------------------------- 1 file changed, 7 insertions(+), 49 deletions(-) diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp index 69a729cd252..66800ed08ab 100644 --- a/src/tools/wasm-merge.cpp +++ b/src/tools/wasm-merge.cpp @@ -304,77 +304,35 @@ void renameInputItems(Module& input) { } }; - auto getValidNameHelper = [&](Name root, - auto getOrNullMerged, - auto getOrNullInput, - Index hint) { - return Names::getValidName( - root, - [&](Name test) { - return !getOrNullMerged(test) && - (!getOrNullInput(test) || test == root); - }, - hint); - }; - for (auto& curr : input.functions) { - auto name = getValidNameHelper( - curr->name, - [&](Name test) { return merged.getFunctionOrNull(test); }, - [&](Name test) { return input.getFunctionOrNull(test); }, - merged.functions.size()); + auto name = Names::getValidFunctionName(merged, curr->name); maybeAdd(ModuleItemKind::Function, curr->name, name); } for (auto& curr : input.globals) { - auto name = getValidNameHelper( - curr->name, - [&](Name test) { return merged.getGlobalOrNull(test); }, - [&](Name test) { return input.getGlobalOrNull(test); }, - merged.globals.size()); + auto name = Names::getValidGlobalName(merged, curr->name); maybeAdd(ModuleItemKind::Global, curr->name, name); } for (auto& curr : input.tags) { - auto name = getValidNameHelper( - curr->name, - [&](Name test) { return merged.getTagOrNull(test); }, - [&](Name test) { return input.getTagOrNull(test); }, - merged.tags.size()); + auto name = Names::getValidTagName(merged, curr->name); maybeAdd(ModuleItemKind::Tag, curr->name, name); } for (auto& curr : input.elementSegments) { - auto name = getValidNameHelper( - curr->name, - [&](Name test) { return merged.getElementSegmentOrNull(test); }, - [&](Name test) { return input.getElementSegmentOrNull(test); }, - merged.elementSegments.size()); + auto name = Names::getValidElementSegmentName(merged, curr->name); maybeAdd(ModuleItemKind::ElementSegment, curr->name, name); } for (auto& curr : input.memories) { - auto name = getValidNameHelper( - curr->name, - [&](Name test) { return merged.getMemoryOrNull(test); }, - [&](Name test) { return input.getMemoryOrNull(test); }, - merged.memories.size()); + auto name = Names::getValidMemoryName(merged, curr->name); maybeAdd(ModuleItemKind::Memory, curr->name, name); } for (auto& curr : input.dataSegments) { - auto name = getValidNameHelper( - curr->name, - [&](Name test) { return merged.getDataSegmentOrNull(test); }, - [&](Name test) { return input.getDataSegmentOrNull(test); }, - merged.dataSegments.size()); + auto name = Names::getValidDataSegmentName(merged, curr->name); maybeAdd(ModuleItemKind::DataSegment, curr->name, name); } for (auto& curr : input.tables) { - auto name = getValidNameHelper( - curr->name, - [&](Name test) { return merged.getTableOrNull(test); }, - [&](Name test) { return input.getTableOrNull(test); }, - merged.tables.size()); + auto name = Names::getValidTableName(merged, curr->name); maybeAdd(ModuleItemKind::Table, curr->name, name); } - // Apply the names to their uses. updateNames(input, kindNameUpdates); } From bd311587ee9d8595fc7d017ff8ebb45aabff65e0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jun 2026 09:46:56 -0700 Subject: [PATCH 3/7] simpl --- src/tools/wasm-merge.cpp | 67 +++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp index 66800ed08ab..5e5ceac10c0 100644 --- a/src/tools/wasm-merge.cpp +++ b/src/tools/wasm-merge.cpp @@ -304,32 +304,85 @@ void renameInputItems(Module& input) { } }; + // Given a name in the input module, and lamdbdas that query for that name in + // both the merged and input module, return a valid name. We want a new name + // that is not in the merged module - we cannot collide with anything already + // there - but we must also be careful to not fix such collisions with names + // in the input module. That is, if we have $a and $a already exists in the + // merged module, $a_1 might be valid - but it is not valid if $a_1 is in the + // input module, as that means it is a valid name there, with things referring + // to it, which we would need to map. For simplicity, when fixing a collision, + // pick a totally novel name. + auto getValidNameHelper = [&](Name name, + auto getMerged, + auto getInput, + Index hint) { + return Names::getValidName( + name, + [&](Name test) { + // As explained above, a name is valid if it is not in the merged + // module, and also it is either the original name in the input module + // (no collision) or it does not appear there. + return !getMerged(test) && + (test == name || !getInput(test)); + }, + hint); + }; + for (auto& curr : input.functions) { - auto name = Names::getValidFunctionName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getFunctionOrNull(test); }, + [&](Name test) { return input.getFunctionOrNull(test); }, + merged.functions.size()); maybeAdd(ModuleItemKind::Function, curr->name, name); } for (auto& curr : input.globals) { - auto name = Names::getValidGlobalName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getGlobalOrNull(test); }, + [&](Name test) { return input.getGlobalOrNull(test); }, + merged.globals.size()); maybeAdd(ModuleItemKind::Global, curr->name, name); } for (auto& curr : input.tags) { - auto name = Names::getValidTagName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getTagOrNull(test); }, + [&](Name test) { return input.getTagOrNull(test); }, + merged.tags.size()); maybeAdd(ModuleItemKind::Tag, curr->name, name); } for (auto& curr : input.elementSegments) { - auto name = Names::getValidElementSegmentName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getElementSegmentOrNull(test); }, + [&](Name test) { return input.getElementSegmentOrNull(test); }, + merged.elementSegments.size()); maybeAdd(ModuleItemKind::ElementSegment, curr->name, name); } for (auto& curr : input.memories) { - auto name = Names::getValidMemoryName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getMemoryOrNull(test); }, + [&](Name test) { return input.getMemoryOrNull(test); }, + merged.memories.size()); maybeAdd(ModuleItemKind::Memory, curr->name, name); } for (auto& curr : input.dataSegments) { - auto name = Names::getValidDataSegmentName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getDataSegmentOrNull(test); }, + [&](Name test) { return input.getDataSegmentOrNull(test); }, + merged.dataSegments.size()); maybeAdd(ModuleItemKind::DataSegment, curr->name, name); } for (auto& curr : input.tables) { - auto name = Names::getValidTableName(merged, curr->name); + auto name = getValidNameHelper( + curr->name, + [&](Name test) { return merged.getTableOrNull(test); }, + [&](Name test) { return input.getTableOrNull(test); }, + merged.tables.size()); maybeAdd(ModuleItemKind::Table, curr->name, name); } From 8cf44bb2a7138eb57211838ee938703602f111f8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jun 2026 09:47:47 -0700 Subject: [PATCH 4/7] simpl --- src/tools/wasm-merge.cpp | 41 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp index 5e5ceac10c0..fd231d576b5 100644 --- a/src/tools/wasm-merge.cpp +++ b/src/tools/wasm-merge.cpp @@ -313,24 +313,21 @@ void renameInputItems(Module& input) { // input module, as that means it is a valid name there, with things referring // to it, which we would need to map. For simplicity, when fixing a collision, // pick a totally novel name. - auto getValidNameHelper = [&](Name name, - auto getMerged, - auto getInput, - Index hint) { - return Names::getValidName( - name, - [&](Name test) { - // As explained above, a name is valid if it is not in the merged - // module, and also it is either the original name in the input module - // (no collision) or it does not appear there. - return !getMerged(test) && - (test == name || !getInput(test)); - }, - hint); - }; + auto getValidName = + [&](Name name, auto getMerged, auto getInput, Index hint) { + return Names::getValidName( + name, + [&](Name test) { + // As explained above, a name is valid if it is not in the merged + // module, and also it is either the original name in the input module + // (no collision) or it does not appear there. + return !getMerged(test) && (test == name || !getInput(test)); + }, + hint); + }; for (auto& curr : input.functions) { - auto name = getValidNameHelper( + auto name = getValidName( curr->name, [&](Name test) { return merged.getFunctionOrNull(test); }, [&](Name test) { return input.getFunctionOrNull(test); }, @@ -338,7 +335,7 @@ void renameInputItems(Module& input) { maybeAdd(ModuleItemKind::Function, curr->name, name); } for (auto& curr : input.globals) { - auto name = getValidNameHelper( + auto name = getValidName( curr->name, [&](Name test) { return merged.getGlobalOrNull(test); }, [&](Name test) { return input.getGlobalOrNull(test); }, @@ -346,7 +343,7 @@ void renameInputItems(Module& input) { maybeAdd(ModuleItemKind::Global, curr->name, name); } for (auto& curr : input.tags) { - auto name = getValidNameHelper( + auto name = getValidName( curr->name, [&](Name test) { return merged.getTagOrNull(test); }, [&](Name test) { return input.getTagOrNull(test); }, @@ -354,7 +351,7 @@ void renameInputItems(Module& input) { maybeAdd(ModuleItemKind::Tag, curr->name, name); } for (auto& curr : input.elementSegments) { - auto name = getValidNameHelper( + auto name = getValidName( curr->name, [&](Name test) { return merged.getElementSegmentOrNull(test); }, [&](Name test) { return input.getElementSegmentOrNull(test); }, @@ -362,7 +359,7 @@ void renameInputItems(Module& input) { maybeAdd(ModuleItemKind::ElementSegment, curr->name, name); } for (auto& curr : input.memories) { - auto name = getValidNameHelper( + auto name = getValidName( curr->name, [&](Name test) { return merged.getMemoryOrNull(test); }, [&](Name test) { return input.getMemoryOrNull(test); }, @@ -370,7 +367,7 @@ void renameInputItems(Module& input) { maybeAdd(ModuleItemKind::Memory, curr->name, name); } for (auto& curr : input.dataSegments) { - auto name = getValidNameHelper( + auto name = getValidName( curr->name, [&](Name test) { return merged.getDataSegmentOrNull(test); }, [&](Name test) { return input.getDataSegmentOrNull(test); }, @@ -378,7 +375,7 @@ void renameInputItems(Module& input) { maybeAdd(ModuleItemKind::DataSegment, curr->name, name); } for (auto& curr : input.tables) { - auto name = getValidNameHelper( + auto name = getValidName( curr->name, [&](Name test) { return merged.getTableOrNull(test); }, [&](Name test) { return input.getTableOrNull(test); }, From 9deebf037c39991173ea2efe74f3da33e994cd2d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jun 2026 09:53:20 -0700 Subject: [PATCH 5/7] test --- test/lit/merge/rename-internal-conflict.wat.second | 1 + 1 file changed, 1 insertion(+) diff --git a/test/lit/merge/rename-internal-conflict.wat.second b/test/lit/merge/rename-internal-conflict.wat.second index c6246b57d6d..a2097a230c3 100644 --- a/test/lit/merge/rename-internal-conflict.wat.second +++ b/test/lit/merge/rename-internal-conflict.wat.second @@ -1,6 +1,7 @@ (module (global $classVTable (mut i32) (i32.const 2)) (global $classVTable_1 (mut i32) (i32.const 3)) + (export "classVTable_b" (global $classVTable)) (export "classVTable_1" (global $classVTable_1)) ) From 1cd128429d64006b9fb3a9232a1608945c2564cb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jun 2026 10:11:47 -0700 Subject: [PATCH 6/7] feedback --- src/tools/wasm-merge.cpp | 57 ++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp index fd231d576b5..d68372d6eb2 100644 --- a/src/tools/wasm-merge.cpp +++ b/src/tools/wasm-merge.cpp @@ -313,73 +313,54 @@ void renameInputItems(Module& input) { // input module, as that means it is a valid name there, with things referring // to it, which we would need to map. For simplicity, when fixing a collision, // pick a totally novel name. - auto getValidName = - [&](Name name, auto getMerged, auto getInput, Index hint) { - return Names::getValidName( - name, - [&](Name test) { - // As explained above, a name is valid if it is not in the merged - // module, and also it is either the original name in the input module - // (no collision) or it does not appear there. - return !getMerged(test) && (test == name || !getInput(test)); - }, - hint); - }; + auto getValidName = [&](Name name, auto method, Index hint) { + return Names::getValidName( + name, + [&](Name test) { + // As explained above, a name is valid if it is not in the merged + // module, and also it is either the original name in the input module + // (no collision) or it does not appear there. + return !(merged.*method)(test) && + (test == name || !(input.*method)(test)); + }, + hint); + }; for (auto& curr : input.functions) { auto name = getValidName( - curr->name, - [&](Name test) { return merged.getFunctionOrNull(test); }, - [&](Name test) { return input.getFunctionOrNull(test); }, - merged.functions.size()); + curr->name, &Module::getFunctionOrNull, merged.functions.size()); maybeAdd(ModuleItemKind::Function, curr->name, name); } for (auto& curr : input.globals) { auto name = getValidName( - curr->name, - [&](Name test) { return merged.getGlobalOrNull(test); }, - [&](Name test) { return input.getGlobalOrNull(test); }, - merged.globals.size()); + curr->name, &Module::getGlobalOrNull, merged.globals.size()); maybeAdd(ModuleItemKind::Global, curr->name, name); } for (auto& curr : input.tags) { auto name = getValidName( - curr->name, - [&](Name test) { return merged.getTagOrNull(test); }, - [&](Name test) { return input.getTagOrNull(test); }, - merged.tags.size()); + curr->name, &Module::getTagOrNull, merged.tags.size()); maybeAdd(ModuleItemKind::Tag, curr->name, name); } for (auto& curr : input.elementSegments) { auto name = getValidName( curr->name, - [&](Name test) { return merged.getElementSegmentOrNull(test); }, - [&](Name test) { return input.getElementSegmentOrNull(test); }, + &Module::getElementSegmentOrNull, merged.elementSegments.size()); maybeAdd(ModuleItemKind::ElementSegment, curr->name, name); } for (auto& curr : input.memories) { auto name = getValidName( - curr->name, - [&](Name test) { return merged.getMemoryOrNull(test); }, - [&](Name test) { return input.getMemoryOrNull(test); }, - merged.memories.size()); + curr->name, &Module::getMemoryOrNull, merged.memories.size()); maybeAdd(ModuleItemKind::Memory, curr->name, name); } for (auto& curr : input.dataSegments) { auto name = getValidName( - curr->name, - [&](Name test) { return merged.getDataSegmentOrNull(test); }, - [&](Name test) { return input.getDataSegmentOrNull(test); }, - merged.dataSegments.size()); + curr->name, &Module::getDataSegmentOrNull, merged.dataSegments.size()); maybeAdd(ModuleItemKind::DataSegment, curr->name, name); } for (auto& curr : input.tables) { auto name = getValidName( - curr->name, - [&](Name test) { return merged.getTableOrNull(test); }, - [&](Name test) { return input.getTableOrNull(test); }, - merged.tables.size()); + curr->name, &Module::getTableOrNull, merged.tables.size()); maybeAdd(ModuleItemKind::Table, curr->name, name); } From 377b718e7013ff63a4e580dfca839a6fc5b625ae Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jun 2026 10:11:53 -0700 Subject: [PATCH 7/7] format --- src/tools/wasm-merge.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp index d68372d6eb2..31ebd9485b9 100644 --- a/src/tools/wasm-merge.cpp +++ b/src/tools/wasm-merge.cpp @@ -332,20 +332,19 @@ void renameInputItems(Module& input) { maybeAdd(ModuleItemKind::Function, curr->name, name); } for (auto& curr : input.globals) { - auto name = getValidName( - curr->name, &Module::getGlobalOrNull, merged.globals.size()); + auto name = + getValidName(curr->name, &Module::getGlobalOrNull, merged.globals.size()); maybeAdd(ModuleItemKind::Global, curr->name, name); } for (auto& curr : input.tags) { - auto name = getValidName( - curr->name, &Module::getTagOrNull, merged.tags.size()); + auto name = + getValidName(curr->name, &Module::getTagOrNull, merged.tags.size()); maybeAdd(ModuleItemKind::Tag, curr->name, name); } for (auto& curr : input.elementSegments) { - auto name = getValidName( - curr->name, - &Module::getElementSegmentOrNull, - merged.elementSegments.size()); + auto name = getValidName(curr->name, + &Module::getElementSegmentOrNull, + merged.elementSegments.size()); maybeAdd(ModuleItemKind::ElementSegment, curr->name, name); } for (auto& curr : input.memories) { @@ -359,8 +358,8 @@ void renameInputItems(Module& input) { maybeAdd(ModuleItemKind::DataSegment, curr->name, name); } for (auto& curr : input.tables) { - auto name = getValidName( - curr->name, &Module::getTableOrNull, merged.tables.size()); + auto name = + getValidName(curr->name, &Module::getTableOrNull, merged.tables.size()); maybeAdd(ModuleItemKind::Table, curr->name, name); }