Skip to content

Commit cefbbfa

Browse files
authored
Add debug information locations to the function prolog/epilog (#1674)
The current patch: * Preserves the debug locations from function prolog and epilog * Preserves the debug locations of the nested blocks
1 parent 403be53 commit cefbbfa

16 files changed

+233
-84
lines changed

src/passes/Print.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -437,20 +437,29 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
437437
if (!full) full = isFullForced();
438438
}
439439

440-
void visit(Expression* curr) {
440+
void printDebugLocation(const Function::DebugLocation &location) {
441+
if (lastPrintedLocation == location) {
442+
return;
443+
}
444+
lastPrintedLocation = location;
445+
auto fileName = currModule->debugInfoFileNames[location.fileIndex];
446+
o << ";;@ " << fileName << ":" << location.lineNumber << ":" << location.columnNumber << '\n';
447+
doIndent(o, indent);
448+
}
449+
450+
void printDebugLocation(Expression* curr) {
441451
if (currFunction) {
442452
// show an annotation, if there is one
443453
auto& debugLocations = currFunction->debugLocations;
444454
auto iter = debugLocations.find(curr);
445455
if (iter != debugLocations.end()) {
446-
auto fileName = currModule->debugInfoFileNames[iter->second.fileIndex];
447-
if (lastPrintedLocation != iter->second) {
448-
lastPrintedLocation = iter->second;
449-
o << ";;@ " << fileName << ":" << iter->second.lineNumber << ":" << iter->second.columnNumber << '\n';
450-
doIndent(o, indent);
451-
}
456+
printDebugLocation(iter->second);
452457
}
453458
}
459+
}
460+
461+
void visit(Expression* curr) {
462+
printDebugLocation(curr);
454463
Visitor<PrintSExpression>::visit(curr);
455464
}
456465

@@ -487,7 +496,10 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
487496
// special-case Block, because Block nesting (in their first element) can be incredibly deep
488497
std::vector<Block*> stack;
489498
while (1) {
490-
if (stack.size() > 0) doIndent(o, indent);
499+
if (stack.size() > 0) {
500+
doIndent(o, indent);
501+
printDebugLocation(curr);
502+
}
491503
stack.push_back(curr);
492504
if (full) {
493505
o << "[" << printType(curr->type) << "] ";
@@ -849,6 +861,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
849861
void visitFunction(Function* curr) {
850862
currFunction = curr;
851863
lastPrintedLocation = { 0, 0, 0 };
864+
if (currFunction->prologLocation.size()) {
865+
printDebugLocation(*currFunction->prologLocation.begin());
866+
}
852867
o << '(';
853868
printMajor(o, "func ");
854869
printName(curr->name, o);
@@ -901,7 +916,17 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
901916
// Print the stack IR.
902917
WasmPrinter::printStackIR(curr->stackIR.get(), o, curr);
903918
}
904-
decIndent();
919+
if (currFunction->epilogLocation.size() && lastPrintedLocation != *currFunction->epilogLocation.begin()) {
920+
// Print last debug location: mix of decIndent and printDebugLocation logic.
921+
doIndent(o, indent);
922+
if (!minify) {
923+
indent--;
924+
}
925+
printDebugLocation(*currFunction->epilogLocation.begin());
926+
o << ')';
927+
} else {
928+
decIndent();
929+
}
905930
}
906931
void printTableHeader(Table* curr) {
907932
o << '(';

src/wasm-binary.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ class WasmBinaryWriter {
722722

723723
void writeSourceMapProlog();
724724
void writeSourceMapEpilog();
725+
void writeDebugLocation(const Function::DebugLocation& loc);
725726
void writeDebugLocation(Expression* curr, Function* func);
726727

727728
// helpers
@@ -775,7 +776,7 @@ class WasmBinaryBuilder {
775776

776777
size_t pos = 0;
777778
Index startIndex = -1;
778-
bool useDebugLocation;
779+
std::set<Function::DebugLocation> debugLocation;
779780

780781
std::set<BinaryConsts::Section> seenSections;
781782

@@ -787,7 +788,7 @@ class WasmBinaryBuilder {
787788
debug(debug),
788789
sourceMap(nullptr),
789790
nextDebugLocation(0, { 0, 0, 0 }),
790-
useDebugLocation(false) {}
791+
debugLocation() {}
791792

792793
void read();
793794
void readUserSection(size_t payloadLen);
@@ -903,7 +904,6 @@ class WasmBinaryBuilder {
903904
void setDebugLocations(std::istream* sourceMap_) {
904905
sourceMap = sourceMap_;
905906
}
906-
Function::DebugLocation debugLocation;
907907
std::unordered_map<std::string, Index> debugInfoFileIndices;
908908
void readNextDebugLocation();
909909
void readSourceMapHeader();

src/wasm-s-parser.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,17 @@ class Element {
5151
bool quoted_;
5252

5353
public:
54-
Element(MixedArena& allocator) : isList_(true), list_(allocator), line(-1), col(-1), loc(nullptr) {}
54+
Element(MixedArena& allocator) : isList_(true), list_(allocator), line(-1), col(-1), startLoc(nullptr), endLoc(nullptr) {}
5555

5656
bool isList() const { return isList_; }
5757
bool isStr() const { return !isList_; }
5858
bool dollared() const { return isStr() && dollared_; }
5959
bool quoted() const { return isStr() && quoted_; }
6060

6161
size_t line, col;
62-
SourceLocation* loc;
62+
// original locations at the start/end of the S-Expression list
63+
SourceLocation* startLoc;
64+
SourceLocation* endLoc;
6365

6466
// list methods
6567
List& list();
@@ -72,7 +74,7 @@ class Element {
7274
cashew::IString str() const;
7375
const char* c_str() const;
7476
Element* setString(cashew::IString str__, bool dollared__, bool quoted__);
75-
Element* setMetadata(size_t line_, size_t col_, SourceLocation* loc_);
77+
Element* setMetadata(size_t line_, size_t col_, SourceLocation* startLoc_);
7678

7779
// printing
7880
friend std::ostream& operator<<(std::ostream& o, Element& e);
@@ -218,6 +220,8 @@ class SExpressionWasmBuilder {
218220
void parseElem(Element& s);
219221
void parseInnerElem(Element& s, Index i = 1, Expression* offset = nullptr);
220222
void parseType(Element& s);
223+
224+
Function::DebugLocation getDebugLocation(const SourceLocation& loc);
221225
};
222226

223227
} // namespace wasm

src/wasm-stack.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ class StackIRFunctionStackWriter : StackWriter<StackWriterMode::Stack2Binary, Pa
257257

258258
template<StackWriterMode Mode, typename Parent>
259259
void StackWriter<Mode, Parent>::mapLocalsAndEmitHeader() {
260+
if (func->prologLocation.size()) {
261+
parent.writeDebugLocation(*func->prologLocation.begin());
262+
}
260263
// Map them
261264
for (Index i = 0; i < func->getNumParams(); i++) {
262265
size_t curr = mappedLocals.size();
@@ -1166,6 +1169,9 @@ bool StackWriter<Mode, Parent>::justAddToStack(Expression* curr) {
11661169

11671170
template<StackWriterMode Mode, typename Parent>
11681171
void StackWriter<Mode, Parent>::finishFunctionBody() {
1172+
if (func->epilogLocation.size()) {
1173+
parent.writeDebugLocation(*func->epilogLocation.begin());
1174+
}
11691175
o << int8_t(BinaryConsts::End);
11701176
}
11711177

src/wasm.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,10 +618,16 @@ class Function {
618618
uint32_t fileIndex, lineNumber, columnNumber;
619619
bool operator==(const DebugLocation& other) const { return fileIndex == other.fileIndex && lineNumber == other.lineNumber && columnNumber == other.columnNumber; }
620620
bool operator!=(const DebugLocation& other) const { return !(*this == other); }
621+
bool operator<(const DebugLocation& other) const {
622+
return fileIndex != other.fileIndex ? fileIndex < other.fileIndex :
623+
lineNumber != other.lineNumber ? lineNumber < other.lineNumber : columnNumber < other.columnNumber;
624+
}
621625
};
622626
std::unordered_map<Expression*, DebugLocation> debugLocations;
627+
std::set<DebugLocation> prologLocation;
628+
std::set<DebugLocation> epilogLocation;
623629

624-
Function() : result(none) {}
630+
Function() : result(none), prologLocation(), epilogLocation() {}
625631

626632
size_t getNumParams();
627633
size_t getNumVars();

src/wasm/wasm-binary.cpp

Lines changed: 70 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -565,14 +565,20 @@ void WasmBinaryWriter::writeUserSection(const UserSection& section) {
565565
finishSection(start);
566566
}
567567

568+
void WasmBinaryWriter::writeDebugLocation(const Function::DebugLocation& loc) {
569+
if (loc == lastDebugLocation) {
570+
return;
571+
}
572+
auto offset = o.size();
573+
sourceMapLocations.emplace_back(offset, &loc);
574+
lastDebugLocation = loc;
575+
}
576+
568577
void WasmBinaryWriter::writeDebugLocation(Expression* curr, Function* func) {
569578
auto& debugLocations = func->debugLocations;
570579
auto iter = debugLocations.find(curr);
571-
if (iter != debugLocations.end() && iter->second != lastDebugLocation) {
572-
auto offset = o.size();
573-
auto& loc = iter->second;
574-
sourceMapLocations.emplace_back(offset, &loc);
575-
lastDebugLocation = loc;
580+
if (iter != debugLocations.end()) {
581+
writeDebugLocation(iter->second);
576582
}
577583
}
578584

@@ -1058,11 +1064,19 @@ void WasmBinaryBuilder::readFunctions() {
10581064
throwError("empty function size");
10591065
}
10601066
endOfFunction = pos + size;
1067+
1068+
Function *func = new Function;
1069+
func->name = Name::fromInt(i);
1070+
currFunction = func;
1071+
1072+
readNextDebugLocation();
1073+
10611074
auto type = functionTypes[i];
10621075
if (debug) std::cerr << "reading " << i << std::endl;
1063-
std::vector<Type> params, vars;
1076+
func->type = type->name;
1077+
func->result = type->result;
10641078
for (size_t j = 0; j < type->params.size(); j++) {
1065-
params.emplace_back(type->params[j]);
1079+
func->params.emplace_back(type->params[j]);
10661080
}
10671081
size_t numLocalTypes = getU32LEB();
10681082
for (size_t t = 0; t < numLocalTypes; t++) {
@@ -1077,23 +1091,16 @@ void WasmBinaryBuilder::readFunctions() {
10771091
throwError("too many locals, wasm VMs would not accept this binary");
10781092
}
10791093
while (num > 0) {
1080-
vars.emplace_back(type);
1094+
func->vars.push_back(type);
10811095
num--;
10821096
}
10831097
}
1084-
auto func = Builder(wasm).makeFunction(
1085-
Name::fromInt(i),
1086-
std::move(params),
1087-
type->result,
1088-
std::move(vars)
1089-
);
1090-
func->type = type->name;
1091-
currFunction = func;
1098+
std::swap(func->prologLocation, debugLocation);
10921099
{
10931100
// process the function body
10941101
if (debug) std::cerr << "processing function: " << i << std::endl;
10951102
nextLabel = 0;
1096-
useDebugLocation = false;
1103+
debugLocation.clear();
10971104
willBeIgnored = false;
10981105
// process body
10991106
assert(breakTargetNames.size() == 0);
@@ -1111,8 +1118,9 @@ void WasmBinaryBuilder::readFunctions() {
11111118
throwError("binary offset at function exit not at expected location");
11121119
}
11131120
}
1121+
std::swap(func->epilogLocation, debugLocation);
11141122
currFunction = nullptr;
1115-
useDebugLocation = false;
1123+
debugLocation.clear();
11161124
functions.push_back(func);
11171125
}
11181126
if (debug) std::cerr << " end function bodies" << std::endl;
@@ -1268,26 +1276,38 @@ void WasmBinaryBuilder::readSourceMapHeader() {
12681276
void WasmBinaryBuilder::readNextDebugLocation() {
12691277
if (!sourceMap) return;
12701278

1271-
char ch;
1272-
*sourceMap >> ch;
1273-
if (ch == '\"') { // end of records
1274-
nextDebugLocation.first = 0;
1275-
return;
1276-
}
1277-
if (ch != ',') {
1278-
throw MapParseException("Unexpected delimiter");
1279-
}
1279+
while (nextDebugLocation.first && nextDebugLocation.first <= pos) {
1280+
if (nextDebugLocation.first < pos) {
1281+
std::cerr << "skipping debug location info for 0x";
1282+
std::cerr << std::hex << nextDebugLocation.first << std::dec << std::endl;
1283+
}
1284+
debugLocation.clear();
1285+
// use debugLocation only for function expressions
1286+
if (currFunction) {
1287+
debugLocation.insert(nextDebugLocation.second);
1288+
}
12801289

1281-
int32_t positionDelta = readBase64VLQ(*sourceMap);
1282-
uint32_t position = nextDebugLocation.first + positionDelta;
1283-
int32_t fileIndexDelta = readBase64VLQ(*sourceMap);
1284-
uint32_t fileIndex = nextDebugLocation.second.fileIndex + fileIndexDelta;
1285-
int32_t lineNumberDelta = readBase64VLQ(*sourceMap);
1286-
uint32_t lineNumber = nextDebugLocation.second.lineNumber + lineNumberDelta;
1287-
int32_t columnNumberDelta = readBase64VLQ(*sourceMap);
1288-
uint32_t columnNumber = nextDebugLocation.second.columnNumber + columnNumberDelta;
1290+
char ch;
1291+
*sourceMap >> ch;
1292+
if (ch == '\"') { // end of records
1293+
nextDebugLocation.first = 0;
1294+
break;
1295+
}
1296+
if (ch != ',') {
1297+
throw MapParseException("Unexpected delimiter");
1298+
}
12891299

1290-
nextDebugLocation = { position, { fileIndex, lineNumber, columnNumber } };
1300+
int32_t positionDelta = readBase64VLQ(*sourceMap);
1301+
uint32_t position = nextDebugLocation.first + positionDelta;
1302+
int32_t fileIndexDelta = readBase64VLQ(*sourceMap);
1303+
uint32_t fileIndex = nextDebugLocation.second.fileIndex + fileIndexDelta;
1304+
int32_t lineNumberDelta = readBase64VLQ(*sourceMap);
1305+
uint32_t lineNumber = nextDebugLocation.second.lineNumber + lineNumberDelta;
1306+
int32_t columnNumberDelta = readBase64VLQ(*sourceMap);
1307+
uint32_t columnNumber = nextDebugLocation.second.columnNumber + columnNumberDelta;
1308+
1309+
nextDebugLocation = { position, { fileIndex, lineNumber, columnNumber } };
1310+
}
12911311
}
12921312

12931313
Expression* WasmBinaryBuilder::readExpression() {
@@ -1345,6 +1365,7 @@ void WasmBinaryBuilder::processExpressions() {
13451365
auto peek = input[pos];
13461366
if (peek == BinaryConsts::End || peek == BinaryConsts::Else) {
13471367
if (debug) std::cerr << "== processExpressions finished with unreachable" << std::endl;
1368+
readNextDebugLocation();
13481369
lastSeparator = BinaryConsts::ASTNodes(peek);
13491370
pos++;
13501371
return;
@@ -1654,15 +1675,10 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
16541675
throwError("Reached function end without seeing End opcode");
16551676
}
16561677
if (debug) std::cerr << "zz recurse into " << ++depth << " at " << pos << std::endl;
1657-
if (nextDebugLocation.first) {
1658-
while (nextDebugLocation.first && nextDebugLocation.first <= pos) {
1659-
if (nextDebugLocation.first < pos) {
1660-
std::cerr << "skipping debug location info for " << nextDebugLocation.first << std::endl;
1661-
}
1662-
debugLocation = nextDebugLocation.second;
1663-
useDebugLocation = currFunction != NULL; // using only for function expressions
1664-
readNextDebugLocation();
1665-
}
1678+
readNextDebugLocation();
1679+
std::set<Function::DebugLocation> currDebugLocation;
1680+
if (debugLocation.size()) {
1681+
currDebugLocation.insert(*debugLocation.begin());
16661682
}
16671683
uint8_t code = getInt8();
16681684
if (debug) std::cerr << "readExpression seeing " << (int)code << std::endl;
@@ -1710,8 +1726,8 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
17101726
break;
17111727
}
17121728
}
1713-
if (useDebugLocation && curr) {
1714-
currFunction->debugLocations[curr] = debugLocation;
1729+
if (curr && currDebugLocation.size()) {
1730+
currFunction->debugLocations[curr] = *currDebugLocation.begin();
17151731
}
17161732
if (debug) std::cerr << "zz recurse from " << depth-- << " at " << pos << std::endl;
17171733
return BinaryConsts::ASTNodes(code);
@@ -1764,13 +1780,18 @@ void WasmBinaryBuilder::visitBlock(Block* curr) {
17641780
curr->name = getNextLabel();
17651781
breakStack.push_back({curr->name, curr->type != none});
17661782
stack.push_back(curr);
1767-
if (getInt8() == BinaryConsts::Block) {
1783+
auto peek = input[pos];
1784+
if (peek == BinaryConsts::Block) {
17681785
// a recursion
1786+
readNextDebugLocation();
17691787
curr = allocator.alloc<Block>();
1788+
pos++;
1789+
if (debugLocation.size()) {
1790+
currFunction->debugLocations[curr] = *debugLocation.begin();
1791+
}
17701792
continue;
17711793
} else {
17721794
// end of recursion
1773-
ungetInt8();
17741795
break;
17751796
}
17761797
}

0 commit comments

Comments
 (0)