From 3c636decdcaec93be3c4c1a77ea1292489a105f3 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 28 Aug 2025 01:17:35 +0000 Subject: [PATCH] Update 'names' field in source maps This scans the code after optimizations and removes unused function names from 'names' field in the source map, reducing its size. Emscripten has not been generating 'names' field so far, but after #???, it will generate the field in case `llvm-dwarfdump` supports a new option `--filter-child-tag`. --- src/wasm/wasm-binary.cpp | 45 ++++++++++++++++++++++++++++------ test/lit/source-map-names.wast | 24 ++++++++++++++++++ 2 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 test/lit/source-map-names.wast diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 3ebd5d8ecba..e9273bb6386 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -16,16 +16,13 @@ #include #include -#include -#include "ir/eh-utils.h" #include "ir/module-utils.h" #include "ir/names.h" #include "ir/table-utils.h" #include "ir/type-updating.h" #include "pass.h" #include "support/bits.h" -#include "support/debug.h" #include "support/stdckdint.h" #include "support/string.h" #include "wasm-annotations.h" @@ -1242,6 +1239,44 @@ void WasmBinaryWriter::writeSourceMapProlog() { } } + // Remove unused function names from 'names' field. + if (!wasm->debugInfoSymbolNames.empty()) { + std::vector newSymbolNames; + std::unordered_map oldToNewIndex; + + // Collect all used symbol name indexes. + for (auto& func : wasm->functions) { + for (auto& pair : func->debugLocations) { + if (pair.second && pair.second->symbolNameIndex) { + uint32_t oldIndex = *pair.second->symbolNameIndex; + assert(oldIndex < wasm->debugInfoSymbolNames.size()); + oldToNewIndex[oldIndex] = 0; // placeholder + } + } + } + + // Create the new list of names and the mapping from old to new indices. + uint32_t newIndex = 0; + for (auto& pair : oldToNewIndex) { + // pair.first is the oldIndex + newSymbolNames.push_back(wasm->debugInfoSymbolNames[pair.first]); + pair.second = newIndex++; // update placeholder to new index + } + + // Update all debug locations to point to the new indices. + for (auto& func : wasm->functions) { + for (auto& pair : func->debugLocations) { + if (pair.second && pair.second->symbolNameIndex) { + uint32_t oldIndex = *pair.second->symbolNameIndex; + pair.second->symbolNameIndex = oldToNewIndex[oldIndex]; + } + } + } + + // Replace the old symbol names with the new, pruned list. + wasm->debugInfoSymbolNames = std::move(newSymbolNames); + } + auto writeOptionalString = [&](const char* name, const std::string& str) { if (!str.empty()) { *sourceMap << "\"" << name << "\":\"" << str << "\","; @@ -1269,10 +1304,6 @@ void WasmBinaryWriter::writeSourceMapProlog() { writeStringVector("sourcesContent", wasm->debugInfoSourcesContent); } - // TODO: This field is optional; maybe we should omit if it's empty. - // TODO: Binaryen actually does not correctly preserve symbol names when it - // rewrites the mappings. We should maybe just drop them, or else handle - // them correctly. writeStringVector("names", wasm->debugInfoSymbolNames); *sourceMap << "\"mappings\":\""; diff --git a/test/lit/source-map-names.wast b/test/lit/source-map-names.wast new file mode 100644 index 00000000000..d24e2ce2383 --- /dev/null +++ b/test/lit/source-map-names.wast @@ -0,0 +1,24 @@ +;; RUN: wasm-opt %s --remove-unused-module-elements -o %t.wasm -osm %t.map +;; RUN: wasm-dis %t.wasm --source-map %t.map | filecheck %s --check-prefix OUT-WAST +;; RUN: cat %t.map | filecheck %s --check-prefix OUT-MAP + +;; After --remove-unused-module-elements, the output source map's 'names' field +;; should NOT contain 'unused' + +;; OUT-MAP: "names":["used"] + +(module + (export "used" (func $used)) + + (func $unused + ;;@ src.cpp:1:1:unused + (nop) + ) + + (func $used + ;; OUT-WAST: ;;@ src.cpp:2:1:used + ;; OUT-WAST-NEXT: (nop) + ;;@ src.cpp:2:1:used + (nop) + ) +)