Skip to content

Commit

Permalink
Recording all label and their sequence; also all debug sections.
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik committed May 27, 2016
1 parent 59dda70 commit ff171e1
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 29 deletions.
40 changes: 40 additions & 0 deletions split.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
(module
(func $return_i32 (result i32)
(unreachable))
(func $return_f64 (result f64)
(unreachable))

(func $if (param i32) (result f32)
(if (get_local 0) (unreachable) (f32.const 0)))

(func $block
(block (i32.const 1) (unreachable) (i32.const 2)))

(func $return_i64 (result i64)
(return (i64.const 1))
(unreachable))

(func $call (result f64)
(call $return_i32)
(unreachable))

(func $misc1 (result i32)
(i32.xor (unreachable) (i32.const 10))
)

(export "return_i32" $return_i32)
(export "return_f64" $return_f64)
(export "if" $if)
(export "block" $block)
(export "return_i64" $return_i64)
(export "call" $call)
(export "misc1" $misc1)
)
(assert_trap (invoke "return_i32") "unreachable executed")
(assert_trap (invoke "return_f64") "unreachable executed")
(assert_trap (invoke "if" (i32.const 1)) "unreachable executed")
(assert_return (invoke "if" (i32.const 0)) (f32.const 0))
(assert_trap (invoke "block") "unreachable executed")
(assert_return (invoke "return_i64") (i64.const 1))
(assert_trap (invoke "call") "unreachable executed")
(assert_trap (invoke "misc1") "unreachable executed")
55 changes: 52 additions & 3 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {

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

bool minify;
const char *maybeSpace;
Expand Down Expand Up @@ -82,8 +84,17 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}

void visit(Expression *curr) {
if (curr->debugLocationIndex != lastDebugLocationId) {
lastDebugLocationId = curr->debugLocationIndex;
if (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 (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];
Expand All @@ -94,7 +105,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
Visitor<PrintSExpression>::visit(curr);
// keeping previously set location for next siblings
lastDebugLocationId = curr->debugLocationIndex;
lastDebugLocationId = curr->debugInfo.locationIndex;
lastLabelId = curr->debugInfo.labelIndex;
}

void visitBlock(Block *curr) {
Expand Down Expand Up @@ -526,6 +538,10 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
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 @@ -545,6 +561,12 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
printMinorOpening(o, "local ") << printableLocal(i) << ' ' << printWasmType(curr->getLocalType(i)) << ")";
o << maybeNewLine;
}
if (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 @@ -564,6 +586,32 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
o << ')';
}
void printDebugSections(Module *curr) {
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 @@ -640,6 +688,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
visitFunction(child.get());
o << maybeNewLine;
}
printDebugSections(curr);
decIndent();
o << maybeNewLine;
}
Expand Down
57 changes: 33 additions & 24 deletions src/s2wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,11 @@ class S2WasmBuilder {
auto section = getCommaSeparated();
// Skipping .debug_ sections
if (!strncmp(section.c_str(), ".debug_", strlen(".debug_"))) {
s -= strlen(section.c_str()); // we want name as well
const char *next = strstr(s, ".section");
s = !next ? s + strlen(s) : next;
if (!next) next = s + strlen(s);
wasm->debugSections.emplace_back(s, next);
s = next;
return;
}
// Initializers are anything in a section whose name begins with .init_array
Expand Down Expand Up @@ -504,6 +507,9 @@ class S2WasmBuilder {
std::vector<DebugLocation> debugLocations;
debugLocations.emplace_back(); // reserve 0 slot
size_t currentDebugLocationIndex = 0;
std::vector<Name> labels;
labels.emplace_back(name); // reserve 0 slot for function name (which is a label too)
size_t currentLabelIndex = 0;

auto recordFile = [&]() {
if (debug) dump("file");
Expand All @@ -528,8 +534,9 @@ class S2WasmBuilder {
auto recordLabel = [&]() {
if (debug) dump("label");
Name label = getStrToSep();
labels.emplace_back(label);
currentLabelIndex++;
// TODO: track and create map of labels and their ranges for our AST
WASM_UNUSED(label);
s = strchr(s, '\n');
};

Expand Down Expand Up @@ -627,7 +634,7 @@ class S2WasmBuilder {
auto curr = allocator->alloc<GetLocal>();
curr->index = func->getLocalIndex(getStrToSep());
curr->type = func->getLocalType(curr->index);
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
inputs[i] = curr;
} else {
abort_on("bad input register");
Expand Down Expand Up @@ -657,7 +664,7 @@ class S2WasmBuilder {
set->index = func->getLocalIndex(assign);
set->value = curr;
set->type = curr->type;
set->debugLocationIndex = currentDebugLocationIndex;
set->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
addToBlock(set);
}
};
Expand Down Expand Up @@ -687,7 +694,7 @@ class S2WasmBuilder {
auto inputs = getInputs(2);
curr->left = inputs[0];
curr->right = inputs[1];
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
curr->finalize();
assert(curr->type == type);
setOutput(curr, assign);
Expand All @@ -699,30 +706,30 @@ class S2WasmBuilder {
curr->op = op;
curr->value = getInput();
curr->type = type;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
curr->finalize();
setOutput(curr, assign);
};
auto makeHost = [&](HostOp op) {
Name assign = getAssign();
auto curr = allocator->alloc<Host>();
curr->op = op;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
setOutput(curr, assign);
};
auto makeHost1 = [&](HostOp op) {
Name assign = getAssign();
auto curr = allocator->alloc<Host>();
curr->op = op;
curr->operands.push_back(getInput());
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
setOutput(curr, assign);
};
auto makeLoad = [&](WasmType type) {
skipComma();
auto curr = allocator->alloc<Load>();
curr->type = type;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
int32_t bytes = getInt() / CHAR_BIT;
curr->bytes = bytes > 0 ? bytes : getWasmTypeSize(type);
curr->signed_ = match("_s");
Expand All @@ -743,7 +750,7 @@ class S2WasmBuilder {
skipComma();
auto curr = allocator->alloc<Store>();
curr->type = type;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
int32_t bytes = getInt() / CHAR_BIT;
curr->bytes = bytes > 0 ? bytes : getWasmTypeSize(type);
Name assign = getAssign();
Expand All @@ -770,7 +777,7 @@ class S2WasmBuilder {
curr->condition = inputs[2];
assert(curr->condition->type == i32);
curr->type = type;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
setOutput(curr, assign);
};
auto makeCall = [&](WasmType type) {
Expand All @@ -785,7 +792,7 @@ class S2WasmBuilder {
auto* funcType = ensureFunctionType(getSig(type, operands), wasm);
assert(type == funcType->result);
auto* indirect = builder.makeCallIndirect(funcType, target, std::move(operands));
indirect->debugLocationIndex = currentDebugLocationIndex;
indirect->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
setOutput(indirect, assign);

} else {
Expand All @@ -796,7 +803,7 @@ class S2WasmBuilder {
Call* curr = allocator->alloc<Call>();
curr->target = target;
curr->type = type;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
if (!linkerObj->isFunctionImplemented(target)) {
linkerObj->addUndefinedFunctionCall(curr);
}
Expand Down Expand Up @@ -831,7 +838,7 @@ class S2WasmBuilder {
// may be a relocation
auto curr = allocator->alloc<Const>();
curr->type = curr->value.type = i32;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
getRelocatableConst((uint32_t*)curr->value.geti32Ptr());
setOutput(curr, assign);
} else {
Expand Down Expand Up @@ -994,7 +1001,7 @@ class S2WasmBuilder {
} else if (match("block")) {
auto curr = allocator->alloc<Block>();
curr->name = getNextLabel();
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
addToBlock(curr);
bstack.push_back(curr);
} else if (match("end_block")) {
Expand All @@ -1012,11 +1019,11 @@ class S2WasmBuilder {
addToBlock(curr);
curr->in = getNextLabel();
curr->out = getNextLabel();
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
auto block = allocator->alloc<Block>();
block->name = curr->out; // temporary, fake - this way, on bstack we have the right label at the right offset for a br
curr->body = block;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
loopBlocks.push_back(block);
bstack.push_back(block);
bstack.push_back(curr);
Expand All @@ -1032,7 +1039,7 @@ class S2WasmBuilder {
assert(curr->targets.size() > 0);
curr->default_ = curr->targets.back();
curr->targets.pop_back();
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
addToBlock(curr);
} else if (match("br")) {
auto curr = allocator->alloc<Break>();
Expand All @@ -1042,7 +1049,7 @@ class S2WasmBuilder {
hasCondition = true;
}
curr->name = getBranchLabel(getInt());
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
if (hasCondition) {
skipComma();
curr->condition = getInput();
Expand All @@ -1062,24 +1069,25 @@ class S2WasmBuilder {
skipComma();
curr->value = getInput();
curr->type = curr->value->type;
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
setOutput(curr, assign);
} else if (match("return")) {
auto curr = builder.makeReturn(*s == '$' ? getInput() : nullptr);
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
addToBlock(curr);
} else if (match("unreachable")) {
auto curr = allocator->alloc<Unreachable>();
curr->debugLocationIndex = currentDebugLocationIndex;
curr->setDebugInfo(currentDebugLocationIndex, currentLabelIndex);
addToBlock(curr);
} else if (match("current_memory")) {
makeHost(CurrentMemory);
} else if (match("grow_memory")) {
makeHost1(GrowMemory);
} else if (peek(".Lfunc_end")) {
// TODO fix handwritten tests to have .endfunc
recordLabel();
s = strchr(s, '\n');
s++;
// skip the next line, which has a .size we can ignore
s = strstr(s, ".size");
s = strchr(s, '\n');
break; // the function is done
} else if (match(".endfunc")) {
Expand Down Expand Up @@ -1117,6 +1125,7 @@ class S2WasmBuilder {
}
func->body->dynCast<Block>()->finalize();
func->debugLocations.swap(debugLocations);
func->labels.swap(labels);
wasm->addFunction(func);
}

Expand Down
Loading

0 comments on commit ff171e1

Please sign in to comment.