Skip to content

Commit

Permalink
Storing debug information such as files and locations from .s files.
Browse files Browse the repository at this point in the history
LLVM backend can provide debug information about source code locations
for compiled bytecode in form of .file and .loc directives. We can store
and use them in s-expression format (via comments?), asm.js via source maps
and later in binary in additional sections.
  • Loading branch information
yurydelendik committed May 27, 2016
1 parent 0ffa458 commit bb512f2
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 29 deletions.
18 changes: 15 additions & 3 deletions src/pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,26 @@ class NameManager : public WalkerPass<PostWalker<NameManager, Visitor<NameManage
size_t counter = 0;
};

struct PrinterArgs {
std::ostream& o;
bool minify;
bool fullAST;
bool debugInfo;

PrinterArgs(): o(std::cout), minify(false), fullAST(false), debugInfo(false) {}
PrinterArgs(std::ostream& o): o(o), minify(false), fullAST(false), debugInfo(false) {}
PrinterArgs(std::ostream& o, bool minify, bool fullAST, bool debugInfo): o(o), minify(minify), fullAST(fullAST), debugInfo(debugInfo) {}
};

// Prints out a module
class Printer : public Pass {
protected:
std::ostream& o;
PrinterArgs args;

public:
Printer() : o(std::cout) {}
Printer(std::ostream& o) : o(o) {}
Printer() : args(PrinterArgs()) {}
Printer(std::ostream& o) : args(PrinterArgs(o)) {}
Printer(const PrinterArgs& args) : args(args) {}

void run(PassRunner* runner, Module* module) override;
};
Expand Down
118 changes: 101 additions & 17 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
std::ostream& o;
unsigned indent = 0;

bool debugInfoComments = false;
size_t lastDebugLocationId = 0;
std::vector<DebugLocation>* functionDebugLocations = nullptr;
size_t lastLabelId = 0;
std::vector<Name>* functionLabels = nullptr;

bool minify;
const char *maybeSpace;
const char *maybeNewLine;
Expand All @@ -49,6 +55,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {

void setFullAST(bool fullAST_) { fullAST = fullAST_; }

void setDebugInfoComments(bool debugInfoComments_) { debugInfoComments = debugInfoComments_; }

void incIndent() {
if (minify) return;
o << '\n';
Expand Down Expand Up @@ -78,6 +86,32 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
return name;
}

void visit(Expression *curr) {
if (debugInfoComments && curr->debugInfo.labelIndex != lastLabelId) {
lastLabelId = curr->debugInfo.labelIndex;
if (functionLabels) { // no labels -- skipping
const Name& labelName = (*functionLabels)[lastLabelId];
o << "(;!bookmark " << labelName.str << ";)";
o << maybeNewLine;
!minify && doIndent(o, indent);
}
}
if (debugInfoComments && curr->debugInfo.locationIndex != lastDebugLocationId) {
lastDebugLocationId = curr->debugInfo.locationIndex;
// skipping location id 0 or debug information is absent
if (functionDebugLocations && lastDebugLocationId) {
const DebugLocation& debugLocation = (*functionDebugLocations)[lastDebugLocationId];
o << "(;!loc " << debugLocation.fileId << ' ' << debugLocation.row << ' ' << debugLocation.column << ";)";
o << maybeNewLine;
!minify && doIndent(o, indent);
}
}
Visitor<PrintSExpression>::visit(curr);
// keeping previously set location for next siblings
lastDebugLocationId = curr->debugInfo.locationIndex;
lastLabelId = curr->debugInfo.labelIndex;
}

void visitBlock(Block *curr) {
// special-case Block, because Block nesting (in their first element) can be incredibly deep
std::vector<Block*> stack;
Expand Down Expand Up @@ -506,6 +540,11 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
void visitFunction(Function *curr) {
currFunction = curr;
printOpening(o, "func ", true) << curr->name;
functionDebugLocations = &(curr->debugLocations);
lastDebugLocationId = 0;
functionLabels = &(curr->labels);
lastLabelId = 0;

if (curr->type.is()) {
o << maybeSpace << "(type " << curr->type << ')';
}
Expand All @@ -525,6 +564,12 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
printMinorOpening(o, "local ") << printableLocal(i) << ' ' << printWasmType(curr->getLocalType(i)) << ")";
o << maybeNewLine;
}
if (debugInfoComments && functionLabels) { // no labels -- skipping
const Name& labelName = (*functionLabels)[0]; // first label is normally a function name
doIndent(o, indent);
o << "(;!bookmark " << labelName.str << ";)";
o << maybeNewLine;
}
// It is ok to emit a block here, as a function can directly contain a list, even if our
// ast avoids that for simplicity. We can just do that optimization here..
if (!fullAST && curr->body->is<Block>() && curr->body->cast<Block>()->name.isNull()) {
Expand All @@ -544,6 +589,35 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
o << ')';
}
void printDebugSections(Module *curr) {
if (!debugInfoComments)
return;

bool hasSequences = false;
for (auto& child : curr->functions) {
if (child->labels.size() > 0) {
hasSequences = true;
}
}
if (hasSequences) {
doIndent(o, indent);
o << "(;!dbg_section .label_sequences\n";
for (auto& child : curr->functions) {
o << "\t.function";
for (auto item : child->labels) {
o << " " << item.str;
}
o << '\n';
}
o << ";)";
o << maybeNewLine;
}
for (auto& child : curr->debugSections) {
doIndent(o, indent);
o << "(;!dbg_section " << child.c_str() << ";)";
o << maybeNewLine;
}
}
void visitModule(Module *curr) {
printOpening(o, "module", true);
incIndent();
Expand Down Expand Up @@ -608,18 +682,31 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
visitTable(&curr->table);
o << maybeNewLine;
}
if (debugInfoComments) {
for(auto const &item : curr->debugFileMap) {
doIndent(o, indent);
o << "(;!file " << item.first << " ";
printText(o, item.second.str);
o << ";)";
o << maybeNewLine;
}
}
for (auto& child : curr->functions) {
doIndent(o, indent);
visitFunction(child.get());
o << maybeNewLine;
}
printDebugSections(curr);
decIndent();
o << maybeNewLine;
}
};

void Printer::run(PassRunner* runner, Module* module) {
PrintSExpression print(o);
PrintSExpression print(args.o);
print.setMinify(args.minify);
print.setFullAST(args.fullAST);
print.setDebugInfoComments(args.debugInfo);
print.visitModule(module);
}

Expand All @@ -629,14 +716,8 @@ static RegisterPass<Printer> registerPass("print", "print in s-expression format

class MinifiedPrinter : public Printer {
public:
MinifiedPrinter() : Printer() {}
MinifiedPrinter(std::ostream& o) : Printer(o) {}

void run(PassRunner* runner, Module* module) override {
PrintSExpression print(o);
print.setMinify(true);
print.visitModule(module);
}
MinifiedPrinter() : Printer(PrinterArgs(std::cout, true, false, false)) {}
MinifiedPrinter(std::ostream& o) : Printer(PrinterArgs(o, true, false, false)) {}
};

static RegisterPass<MinifiedPrinter> registerMinifyPass("print-minified", "print in minified s-expression format");
Expand All @@ -645,18 +726,21 @@ static RegisterPass<MinifiedPrinter> registerMinifyPass("print-minified", "print

class FullPrinter : public Printer {
public:
FullPrinter() : Printer() {}
FullPrinter(std::ostream& o) : Printer(o) {}

void run(PassRunner* runner, Module* module) override {
PrintSExpression print(o);
print.setFullAST(true);
print.visitModule(module);
}
FullPrinter() : Printer(PrinterArgs(std::cout, false, true, false)) {}
FullPrinter(std::ostream& o) : Printer(PrinterArgs(o, false, true, false)) {}
};

static RegisterPass<FullPrinter> registerFullASTPass("print-full", "print in full s-expression format");

// Prints out full ast module with additional debug info comments
class DebugInfoCommentsPrinter : public Printer {
public:
DebugInfoCommentsPrinter() : Printer(PrinterArgs(std::cout, false, true, true)) {}
DebugInfoCommentsPrinter(std::ostream& o) : Printer(PrinterArgs(o, false, true, true)) {}
};

static RegisterPass<DebugInfoCommentsPrinter> registerDebugInfoCommentsPass("print-debug-info", "print in full s-expression format with debug info comments");

// Print individual expressions

std::ostream& WasmPrinter::printExpression(Expression* expression, std::ostream& o, bool minify) {
Expand Down
Loading

0 comments on commit bb512f2

Please sign in to comment.