Skip to content

Commit f030449

Browse files
authored
[NFC] Cleanly separate expression tracking from source maps (#7571)
We track debug info in two ways: for source maps, and for DWARF. DWARF needs more information, not just the start of each expression's location but also the end and delimiters (else for an if) as well. The existing code slightly mixed the two together, which is annoying because code annotations require the same tracking DWARF does. To improve that, this PR refactors the code to cleanly separate the two forms of tracking: * writeSourceMapLocation is now the only method that source maps use. * trackExpressionStart|End|Delimiter is now used by DWARF (and soon code annotations). As a result, * BinaryInstWriter no longer needs a sourceMap param. It was using !sourceMap in the sense of "maybe DWARF", but given custom annotations we'll need more anyhow. Simplify the code by letting the parent decide what to do. Replace DWARF scanning ahead of sections with a "preScan" method. This will be extended for code annotations later.
1 parent 3be188b commit f030449

File tree

4 files changed

+83
-63
lines changed

4 files changed

+83
-63
lines changed

src/wasm-binary.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,9 +1351,12 @@ class WasmBinaryWriter {
13511351
void writeSourceMapEpilog();
13521352
void writeDebugLocation(const Function::DebugLocation& loc);
13531353
void writeNoDebugLocation();
1354-
void writeDebugLocation(Expression* curr, Function* func);
1355-
void writeDebugLocationEnd(Expression* curr, Function* func);
1356-
void writeExtraDebugLocation(Expression* curr, Function* func, size_t id);
1354+
void writeSourceMapLocation(Expression* curr, Function* func);
1355+
1356+
// Track where expressions go in the binary format.
1357+
void trackExpressionStart(Expression* curr, Function* func);
1358+
void trackExpressionEnd(Expression* curr, Function* func);
1359+
void trackExpressionDelimiter(Expression* curr, Function* func, size_t id);
13571360

13581361
// helpers
13591362
void writeInlineString(std::string_view name);
@@ -1614,9 +1617,9 @@ class WasmBinaryReader {
16141617

16151618
static Name escape(Name name);
16161619
void findAndReadNames();
1617-
void readFeatures(size_t);
1618-
void readDylink(size_t);
1619-
void readDylink0(size_t);
1620+
void readFeatures(size_t payloadLen);
1621+
void readDylink(size_t payloadLen);
1622+
void readDylink0(size_t payloadLen);
16201623

16211624
Index readMemoryAccess(Address& alignment, Address& offset);
16221625
std::tuple<Name, Address, Address> getMemarg();
@@ -1627,7 +1630,14 @@ class WasmBinaryReader {
16271630
}
16281631

16291632
private:
1630-
bool hasDWARFSections();
1633+
// In certain modes we need to note the locations of expressions, to match
1634+
// them against sections like DWARF or custom annotations. As this incurs
1635+
// overhead, we only note locations when we actually need to.
1636+
bool needCodeLocations = false;
1637+
1638+
// Scans ahead in the binary to check certain conditions like
1639+
// needCodeLocations.
1640+
void preScan();
16311641
};
16321642

16331643
} // namespace wasm

src/wasm-stack.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,16 @@ class BinaryInstWriter : public OverriddenVisitor<BinaryInstWriter> {
9393
BinaryInstWriter(WasmBinaryWriter& parent,
9494
BufferWithRandomAccess& o,
9595
Function* func,
96-
bool sourceMap,
9796
bool DWARF)
98-
: parent(parent), o(o), func(func), sourceMap(sourceMap), DWARF(DWARF) {}
97+
: parent(parent), o(o), func(func), DWARF(DWARF) {}
9998

10099
void visit(Expression* curr) {
101-
if (func && !sourceMap) {
102-
parent.writeDebugLocation(curr, func);
100+
if (func) {
101+
parent.trackExpressionStart(curr, func);
103102
}
104103
OverriddenVisitor<BinaryInstWriter>::visit(curr);
105-
if (func && !sourceMap) {
106-
parent.writeDebugLocationEnd(curr, func);
104+
if (func) {
105+
parent.trackExpressionEnd(curr, func);
107106
}
108107
}
109108

@@ -136,7 +135,6 @@ class BinaryInstWriter : public OverriddenVisitor<BinaryInstWriter> {
136135
WasmBinaryWriter& parent;
137136
BufferWithRandomAccess& o;
138137
Function* func = nullptr;
139-
bool sourceMap;
140138
bool DWARF;
141139

142140
std::vector<Name> breakStack;
@@ -452,7 +450,7 @@ class BinaryenIRToBinaryWriter
452450
bool sourceMap = false,
453451
bool DWARF = false)
454452
: BinaryenIRWriter<BinaryenIRToBinaryWriter>(func), parent(parent),
455-
writer(parent, o, func, sourceMap, DWARF), sourceMap(sourceMap) {}
453+
writer(parent, o, func, DWARF), sourceMap(sourceMap) {}
456454

457455
void emit(Expression* curr) { writer.visit(curr); }
458456
void emitHeader() {
@@ -480,7 +478,7 @@ class BinaryenIRToBinaryWriter
480478
void emitUnreachable() { writer.emitUnreachable(); }
481479
void emitDebugLocation(Expression* curr) {
482480
if (sourceMap) {
483-
parent.writeDebugLocation(curr, func);
481+
parent.writeSourceMapLocation(curr, func);
484482
}
485483
}
486484

@@ -521,7 +519,7 @@ class StackIRToBinaryWriter {
521519
StackIR& stackIR,
522520
bool sourceMap = false,
523521
bool DWARF = false)
524-
: parent(parent), writer(parent, o, func, sourceMap, DWARF), func(func),
522+
: parent(parent), writer(parent, o, func, DWARF), func(func),
525523
stackIR(stackIR), sourceMap(sourceMap) {}
526524

527525
void write();

src/wasm/wasm-binary.cpp

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,37 +1489,43 @@ void WasmBinaryWriter::writeNoDebugLocation() {
14891489
}
14901490
}
14911491

1492-
void WasmBinaryWriter::writeDebugLocation(Expression* curr, Function* func) {
1493-
if (sourceMap) {
1494-
auto& debugLocations = func->debugLocations;
1495-
auto iter = debugLocations.find(curr);
1496-
if (iter != debugLocations.end() && iter->second) {
1497-
// There is debug information here, write it out.
1498-
writeDebugLocation(*(iter->second));
1499-
} else {
1500-
// This expression has no debug location.
1501-
writeNoDebugLocation();
1502-
}
1492+
void WasmBinaryWriter::writeSourceMapLocation(Expression* curr,
1493+
Function* func) {
1494+
assert(sourceMap);
1495+
1496+
auto& debugLocations = func->debugLocations;
1497+
auto iter = debugLocations.find(curr);
1498+
if (iter != debugLocations.end() && iter->second) {
1499+
// There is debug information here, write it out.
1500+
writeDebugLocation(*(iter->second));
1501+
} else {
1502+
// This expression has no debug location.
1503+
writeNoDebugLocation();
15031504
}
1505+
}
1506+
1507+
void WasmBinaryWriter::trackExpressionStart(Expression* curr, Function* func) {
15041508
// If this is an instruction in a function, and if the original wasm had
1505-
// binary locations tracked, then track it in the output as well.
1509+
// binary locations tracked, then track it in the output as well. We also
1510+
// track locations of instructions that have code annotations, as their binary
1511+
// location goes in the custom section.
15061512
if (func && !func->expressionLocations.empty()) {
15071513
binaryLocations.expressions[curr] =
15081514
BinaryLocations::Span{BinaryLocation(o.size()), 0};
15091515
binaryLocationTrackedExpressionsForFunc.push_back(curr);
15101516
}
15111517
}
15121518

1513-
void WasmBinaryWriter::writeDebugLocationEnd(Expression* curr, Function* func) {
1519+
void WasmBinaryWriter::trackExpressionEnd(Expression* curr, Function* func) {
15141520
if (func && !func->expressionLocations.empty()) {
15151521
auto& span = binaryLocations.expressions.at(curr);
15161522
span.end = o.size();
15171523
}
15181524
}
15191525

1520-
void WasmBinaryWriter::writeExtraDebugLocation(Expression* curr,
1521-
Function* func,
1522-
size_t id) {
1526+
void WasmBinaryWriter::trackExpressionDelimiter(Expression* curr,
1527+
Function* func,
1528+
size_t id) {
15231529
if (func && !func->expressionLocations.empty()) {
15241530
binaryLocations.delimiters[curr][id] = o.size();
15251531
}
@@ -1799,11 +1805,19 @@ WasmBinaryReader::WasmBinaryReader(Module& wasm,
17991805
wasm.features = features;
18001806
}
18011807

1802-
bool WasmBinaryReader::hasDWARFSections() {
1808+
void WasmBinaryReader::preScan() {
1809+
// TODO: Once we support code annotations here, we will need to always scan,
1810+
// but for now, DWARF is the only reason.
1811+
if (!DWARF) {
1812+
return;
1813+
}
1814+
18031815
assert(pos == 0);
18041816
getInt32(); // magic
18051817
getInt32(); // version
1806-
bool has = false;
1818+
1819+
bool foundDWARF = false;
1820+
18071821
while (more()) {
18081822
uint8_t sectionCode = getInt8();
18091823
uint32_t payloadLen = getU32LEB();
@@ -1813,31 +1827,32 @@ bool WasmBinaryReader::hasDWARFSections() {
18131827
auto oldPos = pos;
18141828
if (sectionCode == BinaryConsts::Section::Custom) {
18151829
auto sectionName = getInlineString();
1816-
if (Debug::isDWARFSection(sectionName)) {
1817-
has = true;
1830+
// DWARF sections contain code offsets.
1831+
if (DWARF && Debug::isDWARFSection(sectionName)) {
1832+
needCodeLocations = true;
1833+
foundDWARF = true;
18181834
break;
18191835
}
18201836
}
18211837
pos = oldPos + payloadLen;
18221838
}
1839+
1840+
if (DWARF && !foundDWARF) {
1841+
// The user asked for DWARF, but no DWARF sections exist in practice, so
1842+
// disable the support.
1843+
DWARF = false;
1844+
}
1845+
1846+
// Reset.
18231847
pos = 0;
1824-
return has;
18251848
}
18261849

18271850
void WasmBinaryReader::read() {
1828-
if (DWARF) {
1829-
// In order to update dwarf, we must store info about each IR node's
1830-
// binary position. This has noticeable memory overhead, so we don't do it
1831-
// by default: the user must request it by setting "DWARF", and even if so
1832-
// we scan ahead to see that there actually *are* DWARF sections, so that
1833-
// we don't do unnecessary work.
1834-
if (!hasDWARFSections()) {
1835-
DWARF = false;
1836-
}
1837-
}
1851+
preScan();
18381852

18391853
// Skip ahead and read the name section so we know what names to use when we
18401854
// construct module elements.
1855+
// TODO: Combine this pre-scan with the one in preScan().
18411856
if (debugInfo) {
18421857
findAndReadNames();
18431858
}
@@ -1879,7 +1894,7 @@ void WasmBinaryReader::read() {
18791894
readFunctionSignatures();
18801895
break;
18811896
case BinaryConsts::Section::Code:
1882-
if (DWARF) {
1897+
if (needCodeLocations) {
18831898
codeSectionLocation = pos;
18841899
}
18851900
readFunctions();
@@ -2871,7 +2886,7 @@ void WasmBinaryReader::readFunctions() {
28712886
if (numFuncBodies + numFuncImports != wasm.functions.size()) {
28722887
throwError("invalid function section size, must equal types");
28732888
}
2874-
if (DWARF) {
2889+
if (needCodeLocations) {
28752890
builder.setBinaryLocation(&pos, codeSectionLocation);
28762891
}
28772892
for (size_t i = 0; i < numFuncBodies; i++) {
@@ -2885,7 +2900,7 @@ void WasmBinaryReader::readFunctions() {
28852900
auto& func = wasm.functions[numFuncImports + i];
28862901
currFunction = func.get();
28872902

2888-
if (DWARF) {
2903+
if (needCodeLocations) {
28892904
func->funcLocation = BinaryLocations::FunctionLocations{
28902905
BinaryLocation(sizePos - codeSectionLocation),
28912906
BinaryLocation(pos - codeSectionLocation),

src/wasm/wasm-stack.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ void BinaryInstWriter::visitIf(If* curr) {
5050
}
5151

5252
void BinaryInstWriter::emitIfElse(If* curr) {
53-
if (func && !sourceMap) {
54-
parent.writeExtraDebugLocation(curr, func, BinaryLocations::Else);
53+
if (func) {
54+
parent.trackExpressionDelimiter(curr, func, BinaryLocations::Else);
5555
}
5656
o << int8_t(BinaryConsts::Else);
5757
}
@@ -2156,16 +2156,16 @@ void BinaryInstWriter::visitTryTable(TryTable* curr) {
21562156
}
21572157

21582158
void BinaryInstWriter::emitCatch(Try* curr, Index i) {
2159-
if (func && !sourceMap) {
2160-
parent.writeExtraDebugLocation(curr, func, i);
2159+
if (func) {
2160+
parent.trackExpressionDelimiter(curr, func, i);
21612161
}
21622162
o << int8_t(BinaryConsts::Catch_Legacy)
21632163
<< U32LEB(parent.getTagIndex(curr->catchTags[i]));
21642164
}
21652165

21662166
void BinaryInstWriter::emitCatchAll(Try* curr) {
2167-
if (func && !sourceMap) {
2168-
parent.writeExtraDebugLocation(curr, func, curr->catchBodies.size());
2167+
if (func) {
2168+
parent.trackExpressionDelimiter(curr, func, curr->catchBodies.size());
21692169
}
21702170
o << int8_t(BinaryConsts::CatchAll_Legacy);
21712171
}
@@ -2736,8 +2736,8 @@ void BinaryInstWriter::emitScopeEnd(Expression* curr) {
27362736
assert(!breakStack.empty());
27372737
breakStack.pop_back();
27382738
o << int8_t(BinaryConsts::End);
2739-
if (func && !sourceMap) {
2740-
parent.writeDebugLocationEnd(curr, func);
2739+
if (func) {
2740+
parent.trackExpressionEnd(curr, func);
27412741
}
27422742
}
27432743

@@ -3213,12 +3213,9 @@ void StackIRToBinaryWriter::write() {
32133213
case StackInst::LoopBegin:
32143214
case StackInst::TryTableBegin: {
32153215
if (sourceMap) {
3216-
parent.writeDebugLocation(inst->origin, func);
3216+
parent.writeSourceMapLocation(inst->origin, func);
32173217
}
32183218
writer.visit(inst->origin);
3219-
if (sourceMap) {
3220-
parent.writeDebugLocationEnd(inst->origin, func);
3221-
}
32223219
break;
32233220
}
32243221
case StackInst::TryEnd:

0 commit comments

Comments
 (0)