Skip to content

Commit d58c546

Browse files
authored
Source map fixes (#6550)
* Keep debug locations at function start The `fn_prolog_epilog.debugInfo` test is failing otherwise, since there was debug information associated to the nop instruction at the beginning of the function. * Do not clear the debug information when reaching the end of the source map The last segment should extend to the end of the function. * Propagate debug location from the function prolog to its first instruction * Fix printing of epilogue location The text parser no longer propagates locations to the epilogue, so we should always print the location if there is one. * Fix debug location smearing The debug location of the last instruction should not smear into the function epilogue, and a debug location from a previous function should not smear into the prologue of the current function.
1 parent 58753f4 commit d58c546

File tree

10 files changed

+74
-27
lines changed

10 files changed

+74
-27
lines changed

src/passes/DebugLocationPropagation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ struct DebugLocationPropagation
6464
if (auto it = locs.find(previous); it != locs.end()) {
6565
locs[curr] = it->second;
6666
}
67+
} else if (self->getFunction()->prologLocation.size()) {
68+
// Instructions may inherit their locations from the function
69+
// prolog.
70+
locs[curr] = *self->getFunction()->prologLocation.begin();
6771
}
6872
}
6973
expressionStack.push_back(curr);

src/passes/Print.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3025,8 +3025,7 @@ void PrintSExpression::visitDefinedFunction(Function* curr) {
30253025
// Print the stack IR.
30263026
printStackIR(curr->stackIR.get(), *this);
30273027
}
3028-
if (currFunction->epilogLocation.size() &&
3029-
lastPrintedLocation != *currFunction->epilogLocation.begin()) {
3028+
if (currFunction->epilogLocation.size()) {
30303029
// Print last debug location: mix of decIndent and printDebugLocation
30313030
// logic.
30323031
doIndent(o, indent);

src/wasm-binary.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,7 @@ class WasmBinaryWriter {
13481348
void writeSourceMapProlog();
13491349
void writeSourceMapEpilog();
13501350
void writeDebugLocation(const Function::DebugLocation& loc);
1351+
void writeNoDebugLocation();
13511352
void writeDebugLocation(Expression* curr, Function* func);
13521353
void writeDebugLocationEnd(Expression* curr, Function* func);
13531354
void writeExtraDebugLocation(Expression* curr, Function* func, size_t id);

src/wasm-stack.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,13 @@ class BinaryenIRToBinaryWriter
443443
void emitDelegate(Try* curr) { writer.emitDelegate(curr); }
444444
void emitScopeEnd(Expression* curr) { writer.emitScopeEnd(curr); }
445445
void emitFunctionEnd() {
446+
// Indicate the debug location corresponding to the end opcode
447+
// that terminates the function code.
446448
if (func->epilogLocation.size()) {
447449
parent.writeDebugLocation(*func->epilogLocation.begin());
450+
} else {
451+
// The end opcode has no debug location.
452+
parent.writeNoDebugLocation();
448453
}
449454
writer.emitFunctionEnd();
450455
}

src/wasm/wasm-binary.cpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,10 @@ void WasmBinaryWriter::writeFunctions() {
398398
bool DWARF = Debug::hasDWARFSections(*getModule());
399399
ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
400400
assert(binaryLocationTrackedExpressionsForFunc.empty());
401-
size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size();
402401
BYN_TRACE("write one at" << o.size() << std::endl);
402+
// Do not smear any debug location from the previous function.
403+
writeNoDebugLocation();
404+
size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size();
403405
size_t sizePos = writeU32LEBPlaceholder();
404406
size_t start = o.size();
405407
BYN_TRACE("writing" << func->name << std::endl);
@@ -1373,6 +1375,28 @@ void WasmBinaryWriter::writeDebugLocation(const Function::DebugLocation& loc) {
13731375
lastDebugLocation = loc;
13741376
}
13751377

1378+
void WasmBinaryWriter::writeNoDebugLocation() {
1379+
// Emit an indication that there is no debug location there (so that
1380+
// we do not get "smeared" with debug info from anything before or
1381+
// after us).
1382+
//
1383+
// We don't need to write repeated "no debug info" indications, as a
1384+
// single one is enough to make it clear that the debug information
1385+
// before us is valid no longer. We also don't need to write one if
1386+
// there is nothing before us.
1387+
if (!sourceMapLocations.empty() &&
1388+
sourceMapLocations.back().second != nullptr) {
1389+
sourceMapLocations.emplace_back(o.size(), nullptr);
1390+
1391+
// Initialize the state of debug info to indicate there is no current
1392+
// debug info relevant. This sets |lastDebugLocation| to a dummy value,
1393+
// so that later places with debug info can see that they differ from
1394+
// it (without this, if we had some debug info, then a nullptr for none,
1395+
// and then the same debug info, we could get confused).
1396+
initializeDebugInfo();
1397+
}
1398+
}
1399+
13761400
void WasmBinaryWriter::writeDebugLocation(Expression* curr, Function* func) {
13771401
if (sourceMap) {
13781402
auto& debugLocations = func->debugLocations;
@@ -1381,25 +1405,8 @@ void WasmBinaryWriter::writeDebugLocation(Expression* curr, Function* func) {
13811405
// There is debug information here, write it out.
13821406
writeDebugLocation(iter->second);
13831407
} else {
1384-
// This expression has no debug location. We need to emit an indication
1385-
// of that (so that we do not get "smeared" with debug info from anything
1386-
// before or after us).
1387-
//
1388-
// We don't need to write repeated "no debug info" indications, as a
1389-
// single one is enough to make it clear that the debug information before
1390-
// us is valid no longer. We also don't need to write one if there is
1391-
// nothing before us.
1392-
if (!sourceMapLocations.empty() &&
1393-
sourceMapLocations.back().second != nullptr) {
1394-
sourceMapLocations.emplace_back(o.size(), nullptr);
1395-
1396-
// Initialize the state of debug info to indicate there is no current
1397-
// debug info relevant. This sets |lastDebugLocation| to a dummy value,
1398-
// so that later places with debug info can see that they differ from
1399-
// it (without this, if we had some debug info, then a nullptr for none,
1400-
// and then the same debug info, we could get confused).
1401-
initializeDebugInfo();
1402-
}
1408+
// This expression has no debug location.
1409+
writeNoDebugLocation();
14031410
}
14041411
}
14051412
// If this is an instruction in a function, and if the original wasm had
@@ -2687,12 +2694,11 @@ void WasmBinaryReader::readFunctions() {
26872694

26882695
readVars();
26892696

2690-
std::swap(func->prologLocation, debugLocation);
2697+
func->prologLocation = debugLocation;
26912698
{
26922699
// process the function body
26932700
BYN_TRACE("processing function: " << i << std::endl);
26942701
nextLabel = 0;
2695-
debugLocation.clear();
26962702
willBeIgnored = false;
26972703
// process body
26982704
assert(breakStack.empty());
@@ -2931,7 +2937,6 @@ void WasmBinaryReader::readNextDebugLocation() {
29312937

29322938
if (nextDebugPos == 0) {
29332939
// We reached the end of the source map; nothing left to read.
2934-
debugLocation.clear();
29352940
return;
29362941
}
29372942

src/wasm/wasm-stack.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2839,8 +2839,13 @@ void StackIRToBinaryWriter::write() {
28392839
WASM_UNREACHABLE("unexpected op");
28402840
}
28412841
}
2842+
// Indicate the debug location corresponding to the end opcode that
2843+
// terminates the function code.
28422844
if (func->epilogLocation.size()) {
28432845
parent.writeDebugLocation(*func->epilogLocation.begin());
2846+
} else {
2847+
// The end opcode has no debug location.
2848+
parent.writeNoDebugLocation();
28442849
}
28452850
writer.emitFunctionEnd();
28462851
}

test/binaryen.js/sourcemap.js.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ module.c
55
020: u r c e M a p p i n g U R L 0f m
66
030: o d u l e . w a s m . m a p
77

8-
{"version":3,"sources":["module.c"],"names":[],"mappings":"wBAAE"}
8+
{"version":3,"sources":["module.c"],"names":[],"mappings":"wBAAE,E"}

test/fib-dbg.wasm.fromBinary

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,12 @@
209209
(br $label$4)
210210
)
211211
)
212+
;;@ fib.c:8:0
212213
(return
213-
;;@ fib.c:8:0
214214
(local.get $4)
215215
)
216216
)
217+
;;@ fib.c:8:0
217218
)
218219
(func $runPostSets
219220
(local $0 i32)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
;; RUN: wasm-opt %s -g -o %t.wasm -osm %t.wasm.map
2+
;; RUN: echo >> %t.wasm.map
3+
;; RUN: cat %t.wasm.map | filecheck %s
4+
5+
;; Also test with StackIR, which should have identical results.
6+
;;
7+
;; RUN: wasm-opt %s --generate-stack-ir -o %t.wasm -osm %t.map -g -q
8+
;; RUN: echo >> %t.wasm.map
9+
;; RUN: cat %t.wasm.map | filecheck %s
10+
11+
;; Check that the debug locations do not smear beyond a function
12+
;; epilogue to the next function. The encoded segment 'C' means that
13+
;; the previous segment is indeed one-byte long.
14+
;; CHECK: {"version":3,"sources":["foo"],"names":[],"mappings":"yBAAC,C,GACC"}
15+
(module
16+
(func $0
17+
;;@ foo:1:1
18+
)
19+
(func $1
20+
;;@ foo:2:2
21+
)
22+
)

test/lit/debug/source-map-stop.wast

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
;; RUN: wasm-opt %s -g -o %t.wasm -osm %t.wasm.map
44
;; RUN: wasm-opt %t.wasm -ism %t.wasm.map -S -o - | filecheck %s
55

6+
;; Also test with StackIR, which should have identical results.
7+
;;
8+
;; RUN: wasm-opt %s --generate-stack-ir -o %t.wasm -osm %t.map -g -q
9+
;; RUN: wasm-opt %t.wasm -ism %t.map -q -o - -S | filecheck %s
10+
611
;; Verify that writing to a source map and reading it back does not "smear"
712
;; debug info across adjacent instructions. The debug info in the output should
813
;; be identical to the input.

0 commit comments

Comments
 (0)