diff options
-rw-r--r-- | src/passes/DebugLocationPropagation.cpp | 4 | ||||
-rw-r--r-- | src/passes/Print.cpp | 3 | ||||
-rw-r--r-- | src/wasm-binary.h | 1 | ||||
-rw-r--r-- | src/wasm-stack.h | 5 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 51 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 5 | ||||
-rw-r--r-- | test/binaryen.js/sourcemap.js.txt | 2 | ||||
-rw-r--r-- | test/fib-dbg.wasm.fromBinary | 3 | ||||
-rw-r--r-- | test/lit/debug/source-map-smearing.wast | 22 | ||||
-rw-r--r-- | test/lit/debug/source-map-stop.wast | 5 |
10 files changed, 74 insertions, 27 deletions
diff --git a/src/passes/DebugLocationPropagation.cpp b/src/passes/DebugLocationPropagation.cpp index 07ae53faa..e2d1ac50f 100644 --- a/src/passes/DebugLocationPropagation.cpp +++ b/src/passes/DebugLocationPropagation.cpp @@ -64,6 +64,10 @@ struct DebugLocationPropagation if (auto it = locs.find(previous); it != locs.end()) { locs[curr] = it->second; } + } else if (self->getFunction()->prologLocation.size()) { + // Instructions may inherit their locations from the function + // prolog. + locs[curr] = *self->getFunction()->prologLocation.begin(); } } expressionStack.push_back(curr); diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index b30a1180d..1ecf382d9 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -3025,8 +3025,7 @@ void PrintSExpression::visitDefinedFunction(Function* curr) { // Print the stack IR. printStackIR(curr->stackIR.get(), *this); } - if (currFunction->epilogLocation.size() && - lastPrintedLocation != *currFunction->epilogLocation.begin()) { + if (currFunction->epilogLocation.size()) { // Print last debug location: mix of decIndent and printDebugLocation // logic. doIndent(o, indent); diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 6fd082f79..6c1230b7b 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1348,6 +1348,7 @@ public: void writeSourceMapProlog(); void writeSourceMapEpilog(); void writeDebugLocation(const Function::DebugLocation& loc); + void writeNoDebugLocation(); void writeDebugLocation(Expression* curr, Function* func); void writeDebugLocationEnd(Expression* curr, Function* func); void writeExtraDebugLocation(Expression* curr, Function* func, size_t id); diff --git a/src/wasm-stack.h b/src/wasm-stack.h index 0b72774b6..5858d6f88 100644 --- a/src/wasm-stack.h +++ b/src/wasm-stack.h @@ -443,8 +443,13 @@ public: void emitDelegate(Try* curr) { writer.emitDelegate(curr); } void emitScopeEnd(Expression* curr) { writer.emitScopeEnd(curr); } void emitFunctionEnd() { + // Indicate the debug location corresponding to the end opcode + // that terminates the function code. if (func->epilogLocation.size()) { parent.writeDebugLocation(*func->epilogLocation.begin()); + } else { + // The end opcode has no debug location. + parent.writeNoDebugLocation(); } writer.emitFunctionEnd(); } diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index d7c052a9f..d4fda5915 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -398,8 +398,10 @@ void WasmBinaryWriter::writeFunctions() { bool DWARF = Debug::hasDWARFSections(*getModule()); ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) { assert(binaryLocationTrackedExpressionsForFunc.empty()); - size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size(); BYN_TRACE("write one at" << o.size() << std::endl); + // Do not smear any debug location from the previous function. + writeNoDebugLocation(); + size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size(); size_t sizePos = writeU32LEBPlaceholder(); size_t start = o.size(); BYN_TRACE("writing" << func->name << std::endl); @@ -1373,6 +1375,28 @@ void WasmBinaryWriter::writeDebugLocation(const Function::DebugLocation& loc) { lastDebugLocation = loc; } +void WasmBinaryWriter::writeNoDebugLocation() { + // Emit an indication that there is no debug location there (so that + // we do not get "smeared" with debug info from anything before or + // after us). + // + // We don't need to write repeated "no debug info" indications, as a + // single one is enough to make it clear that the debug information + // before us is valid no longer. We also don't need to write one if + // there is nothing before us. + if (!sourceMapLocations.empty() && + sourceMapLocations.back().second != nullptr) { + sourceMapLocations.emplace_back(o.size(), nullptr); + + // Initialize the state of debug info to indicate there is no current + // debug info relevant. This sets |lastDebugLocation| to a dummy value, + // so that later places with debug info can see that they differ from + // it (without this, if we had some debug info, then a nullptr for none, + // and then the same debug info, we could get confused). + initializeDebugInfo(); + } +} + void WasmBinaryWriter::writeDebugLocation(Expression* curr, Function* func) { if (sourceMap) { auto& debugLocations = func->debugLocations; @@ -1381,25 +1405,8 @@ void WasmBinaryWriter::writeDebugLocation(Expression* curr, Function* func) { // There is debug information here, write it out. writeDebugLocation(iter->second); } else { - // This expression has no debug location. We need to emit an indication - // of that (so that we do not get "smeared" with debug info from anything - // before or after us). - // - // We don't need to write repeated "no debug info" indications, as a - // single one is enough to make it clear that the debug information before - // us is valid no longer. We also don't need to write one if there is - // nothing before us. - if (!sourceMapLocations.empty() && - sourceMapLocations.back().second != nullptr) { - sourceMapLocations.emplace_back(o.size(), nullptr); - - // Initialize the state of debug info to indicate there is no current - // debug info relevant. This sets |lastDebugLocation| to a dummy value, - // so that later places with debug info can see that they differ from - // it (without this, if we had some debug info, then a nullptr for none, - // and then the same debug info, we could get confused). - initializeDebugInfo(); - } + // This expression has no debug location. + writeNoDebugLocation(); } } // If this is an instruction in a function, and if the original wasm had @@ -2687,12 +2694,11 @@ void WasmBinaryReader::readFunctions() { readVars(); - std::swap(func->prologLocation, debugLocation); + func->prologLocation = debugLocation; { // process the function body BYN_TRACE("processing function: " << i << std::endl); nextLabel = 0; - debugLocation.clear(); willBeIgnored = false; // process body assert(breakStack.empty()); @@ -2931,7 +2937,6 @@ void WasmBinaryReader::readNextDebugLocation() { if (nextDebugPos == 0) { // We reached the end of the source map; nothing left to read. - debugLocation.clear(); return; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 99aaf517e..dda47ffa6 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2839,8 +2839,13 @@ void StackIRToBinaryWriter::write() { WASM_UNREACHABLE("unexpected op"); } } + // Indicate the debug location corresponding to the end opcode that + // terminates the function code. if (func->epilogLocation.size()) { parent.writeDebugLocation(*func->epilogLocation.begin()); + } else { + // The end opcode has no debug location. + parent.writeNoDebugLocation(); } writer.emitFunctionEnd(); } diff --git a/test/binaryen.js/sourcemap.js.txt b/test/binaryen.js/sourcemap.js.txt index edb2d86a7..046ad029c 100644 --- a/test/binaryen.js/sourcemap.js.txt +++ b/test/binaryen.js/sourcemap.js.txt @@ -5,4 +5,4 @@ module.c 020: u r c e M a p p i n g U R L 0f m 030: o d u l e . w a s m . m a p -{"version":3,"sources":["module.c"],"names":[],"mappings":"wBAAE"} +{"version":3,"sources":["module.c"],"names":[],"mappings":"wBAAE,E"} diff --git a/test/fib-dbg.wasm.fromBinary b/test/fib-dbg.wasm.fromBinary index bc90702d3..f1b263234 100644 --- a/test/fib-dbg.wasm.fromBinary +++ b/test/fib-dbg.wasm.fromBinary @@ -209,11 +209,12 @@ (br $label$4) ) ) + ;;@ fib.c:8:0 (return - ;;@ fib.c:8:0 (local.get $4) ) ) + ;;@ fib.c:8:0 ) (func $runPostSets (local $0 i32) diff --git a/test/lit/debug/source-map-smearing.wast b/test/lit/debug/source-map-smearing.wast new file mode 100644 index 000000000..875bec9d3 --- /dev/null +++ b/test/lit/debug/source-map-smearing.wast @@ -0,0 +1,22 @@ +;; RUN: wasm-opt %s -g -o %t.wasm -osm %t.wasm.map +;; RUN: echo >> %t.wasm.map +;; RUN: cat %t.wasm.map | filecheck %s + +;; Also test with StackIR, which should have identical results. +;; +;; RUN: wasm-opt %s --generate-stack-ir -o %t.wasm -osm %t.map -g -q +;; RUN: echo >> %t.wasm.map +;; RUN: cat %t.wasm.map | filecheck %s + +;; Check that the debug locations do not smear beyond a function +;; epilogue to the next function. The encoded segment 'C' means that +;; the previous segment is indeed one-byte long. +;; CHECK: {"version":3,"sources":["foo"],"names":[],"mappings":"yBAAC,C,GACC"} +(module + (func $0 + ;;@ foo:1:1 + ) + (func $1 + ;;@ foo:2:2 + ) +) diff --git a/test/lit/debug/source-map-stop.wast b/test/lit/debug/source-map-stop.wast index d075d5686..cdc06505e 100644 --- a/test/lit/debug/source-map-stop.wast +++ b/test/lit/debug/source-map-stop.wast @@ -3,6 +3,11 @@ ;; RUN: wasm-opt %s -g -o %t.wasm -osm %t.wasm.map ;; RUN: wasm-opt %t.wasm -ism %t.wasm.map -S -o - | filecheck %s +;; Also test with StackIR, which should have identical results. +;; +;; RUN: wasm-opt %s --generate-stack-ir -o %t.wasm -osm %t.map -g -q +;; RUN: wasm-opt %t.wasm -ism %t.map -q -o - -S | filecheck %s + ;; Verify that writing to a source map and reading it back does not "smear" ;; debug info across adjacent instructions. The debug info in the output should ;; be identical to the input. |