diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index cf08205191b..cc13101b717 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -93,9 +93,9 @@ copyFunctionWithoutAdd(Function* func, (*symbolNameIndexMap)[*(iter.second->symbolNameIndex)]; } } - updateSymbol(ret->prologLocation, *symbolNameIndexMap); - updateSymbol(ret->epilogLocation, *symbolNameIndexMap); } + updateSymbol(ret->prologLocation, *symbolNameIndexMap); + updateSymbol(ret->epilogLocation, *symbolNameIndexMap); } ret->module = func->module; ret->base = func->base; diff --git a/test/gtest/source-map.cpp b/test/gtest/source-map.cpp index a01d064eda6..2e60075fdf1 100644 --- a/test/gtest/source-map.cpp +++ b/test/gtest/source-map.cpp @@ -15,7 +15,9 @@ */ #include "source-map.h" +#include "ir/module-utils.h" #include "print-test.h" +#include "wasm-builder.h" #include "gmock/gmock-matchers.h" #include "gtest/gtest.h" @@ -232,3 +234,69 @@ TEST_F(SourceMapTest, SourcesContent) { "#include int main()\\n{ printf(\\\"Gr\\u00fc\\u00df " "Gott, Welt!\\\"); return 0;}"); } + +// Regression test: updateSymbol calls for prologLocation/epilogLocation were +// inside the debugLocations loop instead of outside. When debugLocations is +// empty, the loop never executes and the locations are not updated. +TEST(SourceMapCopyTest, UpdateSymbolOutsideLoop) { + Module srcModule; + Module dstModule; + Builder builder(srcModule); + + auto func = builder.makeFunction( + "test", {}, Signature(Type::none, Type::none), {}, builder.makeNop()); + + // Set prologLocation and epilogLocation with symbolNameIndex values, + // but leave debugLocations empty. + func->prologLocation = + Function::DebugLocation{0, 1, 1, std::optional(0)}; + func->epilogLocation = + Function::DebugLocation{0, 2, 1, std::optional(1)}; + + // Symbol name index map: 0->10, 1->11. + std::vector symbolNameIndexMap = {10, 11}; + + auto copied = ModuleUtils::copyFunctionWithoutAdd( + func.get(), dstModule, Name(), std::nullopt, symbolNameIndexMap); + + ASSERT_TRUE(copied->prologLocation.has_value()); + ASSERT_TRUE(copied->prologLocation->symbolNameIndex.has_value()); + EXPECT_EQ(*copied->prologLocation->symbolNameIndex, 10u); + + ASSERT_TRUE(copied->epilogLocation.has_value()); + ASSERT_TRUE(copied->epilogLocation->symbolNameIndex.has_value()); + EXPECT_EQ(*copied->epilogLocation->symbolNameIndex, 11u); +} + +// When debugLocations has multiple entries, updateSymbol should only run once +// per location, not once per loop iteration (which would double-remap). +TEST(SourceMapCopyTest, UpdateSymbolNotDoubleRemapped) { + Module srcModule; + Module dstModule; + Builder builder(srcModule); + + auto func = builder.makeFunction( + "test", {}, Signature(Type::none, Type::none), {}, builder.makeNop()); + + func->prologLocation = + Function::DebugLocation{0, 1, 1, std::optional(0)}; + + // Add multiple debug locations so the loop runs multiple times. + auto* nop1 = srcModule.allocator.alloc(); + auto* nop2 = srcModule.allocator.alloc(); + func->debugLocations[nop1] = + Function::DebugLocation{0, 10, 1, std::optional(0)}; + func->debugLocations[nop2] = + Function::DebugLocation{0, 11, 1, std::optional(1)}; + + // Map: 0->5, 1->6. + std::vector symbolNameIndexMap = {5, 6}; + + auto copied = ModuleUtils::copyFunctionWithoutAdd( + func.get(), dstModule, Name(), std::nullopt, symbolNameIndexMap); + + // Should be remapped exactly once: 0 -> 5. + ASSERT_TRUE(copied->prologLocation.has_value()); + ASSERT_TRUE(copied->prologLocation->symbolNameIndex.has_value()); + EXPECT_EQ(*copied->prologLocation->symbolNameIndex, 5u); +}