Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 5 segment source mappings #6795

Merged
merged 40 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
bc6dd69
Handle single-segment source mapping in source map header decoder
osa1 Jul 31, 2024
a12e4ad
Support 5-segment source mappings
osa1 Jul 31, 2024
363a03e
Merge remote-tracking branch 'origin/main' into 5_segment_source_mapp…
osa1 Aug 7, 2024
d8555c5
Revert formatting change
osa1 Aug 7, 2024
3b986eb
Fix formatting
osa1 Aug 7, 2024
2015e88
Merge remote-tracking branch 'origin/main' into 5_segment_source_mapp…
osa1 Sep 16, 2024
9465b2e
Revert debug change
osa1 Sep 16, 2024
4076b7a
Apply suggestions from code review
osa1 Sep 19, 2024
b63ec19
Merge remote-tracking branch 'origin/main' into 5_segment_source_mapp…
osa1 Sep 20, 2024
6171fe9
Add test
osa1 Sep 20, 2024
0a9d251
Implement parsing and printing
osa1 Sep 20, 2024
6858dac
Format
osa1 Sep 20, 2024
4111ce8
Fix parsing
osa1 Sep 20, 2024
f92899c
Fixes?
osa1 Sep 20, 2024
8675c23
Revert lit test, wasm-opt doesn't generate symbol names
osa1 Sep 20, 2024
8a35d16
Fix formatting
osa1 Sep 20, 2024
0051cbb
Merge remote-tracking branch 'origin/main' into 5_segment_source_mapp…
osa1 Sep 25, 2024
56abcb5
Fix wat parsing
osa1 Sep 25, 2024
7013707
Fix wat parsing a little bit more
osa1 Sep 25, 2024
cd2ac9d
Fix wat parsing even more
osa1 Sep 25, 2024
f70be71
Update lit test
osa1 Sep 25, 2024
ef71d81
Fix symbol name index updates
osa1 Sep 25, 2024
7e284ed
Improve test
osa1 Sep 25, 2024
c18d339
Formatting
osa1 Sep 25, 2024
7b59358
Refactor weird code
osa1 Sep 26, 2024
c96ad9a
Implement a TODO
osa1 Sep 26, 2024
25e1d80
Update merge test
osa1 Sep 27, 2024
95e24c7
Update metadce test
osa1 Sep 27, 2024
5dac139
Add inlining test
osa1 Sep 27, 2024
7d6529d
Merge remote-tracking branch 'origin/main' into 5_segment_source_mapp…
osa1 Sep 27, 2024
836d387
Revert formatting change
osa1 Sep 27, 2024
1c4157c
Update lit output
osa1 Sep 27, 2024
a278429
Merge remote-tracking branch 'origin/main' into 5_segment_source_mapp…
osa1 Oct 1, 2024
0098182
Address some of the comments
osa1 Oct 1, 2024
415bb88
Formatting
osa1 Oct 1, 2024
2f8cf68
Remove local
osa1 Oct 1, 2024
b1dff53
Merge remote-tracking branch 'origin/main' into 5_segment_source_mapp…
osa1 Oct 1, 2024
8a9ee2d
Revert C API changes
osa1 Oct 1, 2024
c54b226
Update comment
osa1 Oct 1, 2024
a721d72
Fix typo
osa1 Oct 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 55 additions & 4 deletions src/ir/module-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,42 @@ static void updateLocationSet(std::set<Function::DebugLocation>& locations,
std::swap(locations, updatedLocations);
}

// Update the symbol name indices when moving a set of debug locations from one
// module to another.
static void updateSymbolSet(std::set<Function::DebugLocation>& locations,
osa1 marked this conversation as resolved.
Show resolved Hide resolved
std::vector<Index>& symbolIndexMap) {
std::set<Function::DebugLocation> updatedLocations;

for (auto iter : locations) {
if (iter.symbolNameIndex) {
iter.symbolNameIndex = symbolIndexMap[*iter.symbolNameIndex];
}
updatedLocations.insert(iter);
}
locations.clear();
std::swap(locations, updatedLocations);
}

// Copies a function into a module. If newName is provided it is used as the
// name of the function (otherwise the original name is copied). If fileIndexMap
// is specified, it is used to rename source map filename indices when copying
// the function from one module to another one.
osa1 marked this conversation as resolved.
Show resolved Hide resolved
Function* copyFunction(Function* func,
Module& out,
Name newName,
std::optional<std::vector<Index>> fileIndexMap) {
auto ret = copyFunctionWithoutAdd(func, out, newName, fileIndexMap);
std::optional<std::vector<Index>> fileIndexMap,
std::optional<std::vector<Index>> symbolNameIndexMap) {
auto ret = copyFunctionWithoutAdd(
func, out, newName, fileIndexMap, symbolNameIndexMap);
return out.addFunction(std::move(ret));
}

std::unique_ptr<Function>
copyFunctionWithoutAdd(Function* func,
Module& out,
Name newName,
std::optional<std::vector<Index>> fileIndexMap) {
std::optional<std::vector<Index>> fileIndexMap,
std::optional<std::vector<Index>> symbolNameIndexMap) {
auto ret = std::make_unique<Function>();
ret->name = newName.is() ? newName : func->name;
ret->hasExplicitName = func->hasExplicitName;
Expand All @@ -76,6 +95,18 @@ copyFunctionWithoutAdd(Function* func,
updateLocationSet(ret->prologLocation, *fileIndexMap);
updateLocationSet(ret->epilogLocation, *fileIndexMap);
}
if (symbolNameIndexMap) {
for (auto& iter : ret->debugLocations) {
if (iter.second) {
if (iter.second->symbolNameIndex.has_value()) {
iter.second->symbolNameIndex =
(*symbolNameIndexMap)[*(iter.second->symbolNameIndex)];
}
}
updateSymbolSet(ret->prologLocation, *symbolNameIndexMap);
updateSymbolSet(ret->epilogLocation, *symbolNameIndexMap);
}
}
ret->module = func->module;
ret->base = func->base;
ret->noFullInline = func->noFullInline;
Expand Down Expand Up @@ -199,8 +230,27 @@ void copyModuleItems(const Module& in, Module& out) {
}
}

std::optional<std::vector<Index>> symbolNameIndexMap;
if (!in.debugInfoSymbolNames.empty()) {
std::unordered_map<std::string, Index> debugInfoSymbolNameIndices;
for (Index i = 0; i < out.debugInfoSymbolNames.size(); i++) {
debugInfoSymbolNameIndices[out.debugInfoSymbolNames[i]] = i;
}
symbolNameIndexMap.emplace();
for (Index i = 0; i < in.debugInfoSymbolNames.size(); i++) {
std::string file = in.debugInfoSymbolNames[i];
auto iter = debugInfoSymbolNameIndices.find(file);
if (iter == debugInfoSymbolNameIndices.end()) {
Index index = out.debugInfoSymbolNames.size();
out.debugInfoSymbolNames.push_back(file);
debugInfoSymbolNameIndices[file] = index;
}
symbolNameIndexMap->push_back(debugInfoSymbolNameIndices[file]);
}
}

for (auto& curr : in.functions) {
copyFunction(curr.get(), out, Name(), fileIndexMap);
copyFunction(curr.get(), out, Name(), fileIndexMap, symbolNameIndexMap);
}
for (auto& curr : in.globals) {
copyGlobal(curr.get(), out);
Expand Down Expand Up @@ -241,6 +291,7 @@ void copyModule(const Module& in, Module& out) {
out.start = in.start;
out.customSections = in.customSections;
out.debugInfoFileNames = in.debugInfoFileNames;
out.debugInfoSymbolNames = in.debugInfoSymbolNames;
out.features = in.features;
}

Expand Down
21 changes: 12 additions & 9 deletions src/ir/module-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,24 @@
namespace wasm::ModuleUtils {

// Copies a function into a module. If newName is provided it is used as the
// name of the function (otherwise the original name is copied). If fileIndexMap
// is specified, it is used to rename source map filename indices when copying
// the function from one module to another one.
Function*
copyFunction(Function* func,
Module& out,
Name newName = Name(),
std::optional<std::vector<Index>> fileIndexMap = std::nullopt);
// name of the function (otherwise the original name is copied). When specified,
// fileIndexMap and symbolNameIndexMap are used to rename source map filename
// and symbol name indices when copying the function from one module to another
// one.
Function* copyFunction(
Function* func,
Module& out,
Name newName = Name(),
std::optional<std::vector<Index>> fileIndexMap = std::nullopt,
std::optional<std::vector<Index>> symbolNameIndexMap = std::nullopt);

// As above, but does not add the copy to the module.
std::unique_ptr<Function> copyFunctionWithoutAdd(
Function* func,
Module& out,
Name newName = Name(),
std::optional<std::vector<Index>> fileIndexMap = std::nullopt);
std::optional<std::vector<Index>> fileIndexMap = std::nullopt,
std::optional<std::vector<Index>> symbolNameIndexMap = std::nullopt);

Global* copyGlobal(Global* global, Module& out);

Expand Down
27 changes: 24 additions & 3 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
typeNames;
const std::unordered_map<Index, Index>& implicitElemIndices;

std::unordered_map<std::string_view, Index> debugSymbolNameIndices;
std::unordered_map<std::string_view, Index> debugFileIndices;

// The index of the current module element.
Expand Down Expand Up @@ -1777,12 +1778,32 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
}
contents = contents.substr(lineSize + 1);

lexer = Lexer(contents);
auto colSize = contents.find(':');
if (colSize == contents.npos) {
colSize = contents.size();
if (colSize == 0) {
return;
}
}
lexer = Lexer(contents.substr(0, colSize));
auto col = lexer.takeU32();
if (!col || !lexer.empty()) {
if (!col) {
return;
}

std::optional<BinaryLocation> symbolNameIndex;
if (colSize != contents.size()) {
contents = contents.substr(colSize + 1);
auto symbolName = contents;
auto [it, inserted] = debugSymbolNameIndices.insert(
{symbolName, debugSymbolNameIndices.size()});
if (inserted) {
assert(wasm.debugInfoSymbolNames.size() == it->second);
wasm.debugInfoSymbolNames.push_back(std::string(symbolName));
}
symbolNameIndex = it->second;
}

// TODO: If we ever parallelize the parse, access to
// `wasm.debugInfoFileNames` will have to be protected by a lock.
auto [it, inserted] =
Expand All @@ -1792,7 +1813,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
wasm.debugInfoFileNames.push_back(std::string(file));
}
irBuilder.setDebugLocation(
Function::DebugLocation({it->second, *line, *col}));
Function::DebugLocation({it->second, *line, *col, symbolNameIndex}));
}

Result<> makeBlock(Index pos,
Expand Down
10 changes: 9 additions & 1 deletion src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2516,7 +2516,15 @@ void PrintSExpression::printDebugLocation(
} else {
auto fileName = currModule->debugInfoFileNames[location->fileIndex];
o << ";;@ " << fileName << ":" << location->lineNumber << ":"
<< location->columnNumber << '\n';
<< location->columnNumber;

if (location->symbolNameIndex) {
auto symbolName =
currModule->debugInfoSymbolNames[*(location->symbolNameIndex)];
o << ":" << symbolName;
}

o << '\n';
}
doIndent(o, indent);
}
Expand Down
1 change: 1 addition & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,7 @@ class WasmBinaryReader {
// Debug information reading helpers
void setDebugLocations(std::istream* sourceMap_) { sourceMap = sourceMap_; }
std::unordered_map<std::string, Index> debugInfoFileIndices;
std::unordered_map<std::string, Index> debugInfoSymbolNameIndices;
void readNextDebugLocation();
void readSourceMapHeader();

Expand Down
18 changes: 11 additions & 7 deletions src/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -2073,22 +2073,25 @@ class Function : public Importable {
std::unordered_map<Index, Name> localNames;
std::unordered_map<Name, Index> localIndices;

// Source maps debugging info: map expression nodes to their file, line, col.
// Source maps debugging info: map expression nodes to their file, line, col,
// symbol name.
struct DebugLocation {
BinaryLocation fileIndex, lineNumber, columnNumber;
std::optional<BinaryLocation> symbolNameIndex;
bool operator==(const DebugLocation& other) const {
return fileIndex == other.fileIndex && lineNumber == other.lineNumber &&
columnNumber == other.columnNumber;
columnNumber == other.columnNumber &&
symbolNameIndex == other.symbolNameIndex;
}
bool operator!=(const DebugLocation& other) const {
return !(*this == other);
}
bool operator<(const DebugLocation& other) const {
return fileIndex != other.fileIndex
? fileIndex < other.fileIndex
: lineNumber != other.lineNumber
? lineNumber < other.lineNumber
: columnNumber < other.columnNumber;
return fileIndex != other.fileIndex ? fileIndex < other.fileIndex
: lineNumber != other.lineNumber ? lineNumber < other.lineNumber
: columnNumber != other.columnNumber
? columnNumber < other.columnNumber
: symbolNameIndex < other.symbolNameIndex;
}
};
// One can explicitly set the debug location of an expression to
Expand Down Expand Up @@ -2300,6 +2303,7 @@ class Module {

// Source maps debug info.
std::vector<std::string> debugInfoFileNames;
std::vector<std::string> debugInfoSymbolNames;

// `features` are the features allowed to be used in this module and should be
// respected regardless of the value of`hasFeaturesSection`.
Expand Down
74 changes: 61 additions & 13 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,7 @@ void WasmBinaryWriter::writeSymbolMap() {
}

void WasmBinaryWriter::initializeDebugInfo() {
lastDebugLocation = {0, /* lineNumber = */ 1, 0};
lastDebugLocation = {0, /* lineNumber = */ 1, 0, std::nullopt};
}

void WasmBinaryWriter::writeSourceMapProlog() {
Expand Down Expand Up @@ -1225,7 +1225,17 @@ void WasmBinaryWriter::writeSourceMapProlog() {
// TODO respect JSON string encoding, e.g. quotes and control chars.
*sourceMap << "\"" << wasm->debugInfoFileNames[i] << "\"";
}
*sourceMap << "],\"names\":[],\"mappings\":\"";
*sourceMap << "],\"names\":[";

for (size_t i = 0; i < wasm->debugInfoSymbolNames.size(); i++) {
if (i > 0) {
*sourceMap << ",";
}
// TODO respect JSON string encoding, e.g. quotes and control chars.
*sourceMap << "\"" << wasm->debugInfoSymbolNames[i] << "\"";
}

*sourceMap << "],\"mappings\":\"";
}

static void writeBase64VLQ(std::ostream& out, int32_t n) {
Expand All @@ -1249,21 +1259,31 @@ static void writeBase64VLQ(std::ostream& out, int32_t n) {
void WasmBinaryWriter::writeSourceMapEpilog() {
// write source map entries
size_t lastOffset = 0;
Function::DebugLocation lastLoc = {0, /* lineNumber = */ 1, 0};
BinaryLocation lastFileIndex = 0;
BinaryLocation lastLineNumber = 1;
BinaryLocation lastColumnNumber = 0;
BinaryLocation lastSymbolNameIndex = 0;
for (const auto& [offset, loc] : sourceMapLocations) {
if (lastOffset > 0) {
*sourceMap << ",";
}
writeBase64VLQ(*sourceMap, int32_t(offset - lastOffset));
lastOffset = offset;
if (loc) {
// There is debug information for this location, so emit the next 3
// fields and update lastLoc.
writeBase64VLQ(*sourceMap, int32_t(loc->fileIndex - lastLoc.fileIndex));
writeBase64VLQ(*sourceMap, int32_t(loc->lineNumber - lastLoc.lineNumber));
writeBase64VLQ(*sourceMap,
int32_t(loc->columnNumber - lastLoc.columnNumber));
lastLoc = *loc;
writeBase64VLQ(*sourceMap, int32_t(loc->fileIndex - lastFileIndex));
lastFileIndex = loc->fileIndex;

writeBase64VLQ(*sourceMap, int32_t(loc->lineNumber - lastLineNumber));
lastLineNumber = loc->lineNumber;

writeBase64VLQ(*sourceMap, int32_t(loc->columnNumber - lastColumnNumber));
lastColumnNumber = loc->columnNumber;

if (loc->symbolNameIndex) {
writeBase64VLQ(*sourceMap,
int32_t(*loc->symbolNameIndex - lastSymbolNameIndex));
lastSymbolNameIndex = *loc->symbolNameIndex;
}
}
}
*sourceMap << "\"}";
Expand Down Expand Up @@ -1716,7 +1736,7 @@ WasmBinaryReader::WasmBinaryReader(Module& wasm,
FeatureSet features,
const std::vector<char>& input)
: wasm(wasm), allocator(wasm.allocator), input(input), sourceMap(nullptr),
nextDebugPos(0), nextDebugLocation{0, 0, 0},
nextDebugPos(0), nextDebugLocation{0, 0, 0, std::nullopt},
nextDebugLocationHasDebugInfo(false), debugLocation() {
wasm.features = features;
}
Expand Down Expand Up @@ -2885,6 +2905,21 @@ void WasmBinaryReader::readSourceMapHeader() {
mustReadChar(']');
}

if (findField("names")) {
skipWhitespace();
mustReadChar('[');
if (!maybeReadChar(']')) {
do {
std::string symbol;
readString(symbol);
Index index = wasm.debugInfoSymbolNames.size();
wasm.debugInfoSymbolNames.push_back(symbol);
debugInfoSymbolNameIndices[symbol] = index;
} while (maybeReadChar(','));
mustReadChar(']');
}
}

if (!findField("mappings")) {
throw MapParseException("cannot find the 'mappings' field in map");
}
Expand All @@ -2911,7 +2946,12 @@ void WasmBinaryReader::readSourceMapHeader() {
uint32_t lineNumber =
readBase64VLQ(*sourceMap) + 1; // adjust zero-based line number
uint32_t columnNumber = readBase64VLQ(*sourceMap);
nextDebugLocation = {fileIndex, lineNumber, columnNumber};
std::optional<BinaryLocation> symbolNameIndex;
peek = sourceMap->peek();
if (!(peek == ',' || peek == '\"')) {
symbolNameIndex = readBase64VLQ(*sourceMap);
}
nextDebugLocation = {fileIndex, lineNumber, columnNumber, symbolNameIndex};
nextDebugLocationHasDebugInfo = true;
}
}
Expand Down Expand Up @@ -2966,7 +3006,15 @@ void WasmBinaryReader::readNextDebugLocation() {
int32_t columnNumberDelta = readBase64VLQ(*sourceMap);
uint32_t columnNumber = nextDebugLocation.columnNumber + columnNumberDelta;

nextDebugLocation = {fileIndex, lineNumber, columnNumber};
std::optional<BinaryLocation> symbolNameIndex;
peek = sourceMap->peek();
if (!(peek == ',' || peek == '\"')) {
int32_t symbolNameIndexDelta = readBase64VLQ(*sourceMap);
symbolNameIndex =
nextDebugLocation.symbolNameIndex.value_or(0) + symbolNameIndexDelta;
}

nextDebugLocation = {fileIndex, lineNumber, columnNumber, symbolNameIndex};
nextDebugLocationHasDebugInfo = true;
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/wasm/wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1863,6 +1863,9 @@ void Module::updateMaps() {
assert(tagsMap.size() == tags.size());
}

void Module::clearDebugInfo() { debugInfoFileNames.clear(); }
void Module::clearDebugInfo() {
debugInfoFileNames.clear();
debugInfoSymbolNames.clear();
}

} // namespace wasm
Loading
Loading