Index: vm/il_printer.cc |
=================================================================== |
--- vm/il_printer.cc (revision 8145) |
+++ vm/il_printer.cc (working copy) |
@@ -11,16 +11,21 @@ |
void BufferFormatter::Print(const char* format, ...) { |
+ va_list args; |
+ va_start(args, format); |
+ VPrint(format, args); |
+ va_end(args); |
+} |
+ |
+ |
+void BufferFormatter::VPrint(const char* format, va_list args) { |
intptr_t available = size_ - position_; |
if (available <= 0) return; |
- va_list args; |
- va_start(args, format); |
intptr_t written = |
OS::VSNPrint(buffer_ + position_, available, format, args); |
if (written >= 0) { |
position_ += (available <= written) ? available : written; |
} |
- va_end(args); |
} |
@@ -65,7 +70,6 @@ |
} |
- |
void Computation::PrintTo(BufferFormatter* f) const { |
f->Print("%s(", DebugName()); |
PrintOperandsTo(f); |
@@ -351,4 +355,187 @@ |
} |
+void FlowGraphVisualizer::Print(const char* format, ...) { |
+ char str[120]; |
+ BufferFormatter f(str, sizeof(str)); |
+ f.Print("%*s", 2 * indent_, ""); |
+ va_list args; |
+ va_start(args, format); |
+ f.VPrint(format, args); |
+ va_end(args); |
+ (*Dart::flow_graph_writer())(str, strlen(str)); |
+} |
+ |
+ |
+void FlowGraphVisualizer::PrintInstruction(Instruction* instr) { |
+ char str[120]; |
+ BufferFormatter f(str, sizeof(str)); |
+ instr->PrintToVisualizer(&f); |
+ f.Print("%s <|@\n", str); |
+ (*Dart::flow_graph_writer())(str, strlen(str)); |
+} |
+ |
+ |
+void FlowGraphVisualizer::PrintFunction() { |
+#define BEGIN(name) \ |
+ Print("begin_%s\n", name); \ |
+ indent_++; |
+#define END(name) \ |
+ Print("end_%s\n", name); \ |
+ indent_--; |
+ |
+ { |
+ BEGIN("compilation"); |
+ const char* name = function_.ToFullyQualifiedCString(); |
+ Print("%s \"%s\"\n", "name", name); |
+ Print("%s \"%s\"\n", "method", name); |
+ Print("%s %d\n", "date", 0); // Required field. Unused. |
+ END("compilation"); |
+ } |
+ |
+ { |
+ BEGIN("cfg"); |
+ Print("%s \"%s\"\n", "name", "Flow graph builder"); |
+ |
+ for (intptr_t i = 0; i < block_order_.length(); ++i) { |
+ BEGIN("block"); |
+ BlockEntryInstr* entry = block_order_[i]; |
+ Print("%s \"B%d\"\n", "name", entry->block_id()); |
+ Print("%s %d\n", "from_bci", -1); // Required field. Unused. |
+ Print("%s %d\n", "to_bci", -1); // Required field. Unused. |
+ |
+ Print("predecessors"); |
+ for (intptr_t j = 0; j < entry->PredecessorCount(); ++j) { |
+ BlockEntryInstr* pred = entry->PredecessorAt(j); |
+ Print(" \"B%d\"", pred->block_id()); |
+ } |
+ Print("\n"); |
+ |
+ Print("successors"); |
+ Instruction* last = entry->last_instruction(); |
+ for (intptr_t j = 0; j < last->SuccessorCount(); ++j) { |
+ intptr_t next_id = last->SuccessorAt(j)->block_id(); |
+ Print(" \"B%d\"", next_id); |
+ } |
+ Print("\n"); |
+ |
+ // TODO(fschneider): Use this for exception handlers. |
+ Print("xhandlers\n"); |
+ |
+ // Can be freely used to mark blocks |
+ Print("flags\n"); |
+ |
+ if (entry->dominator() != NULL) { |
+ Print("%s \"B%d\"\n", "dominator", entry->dominator()->block_id()); |
+ } |
+ |
+ // TODO(fschneider): Mark blocks with loop nesting level. |
+ Print("%s %d\n", "loop_depth", 0); |
+ |
+ { |
+ BEGIN("states"); // Required section. |
+ { |
+ BEGIN("locals"); // Required section. |
+ // TODO(fschneider): Insert phi-instructions here. |
+ intptr_t num_phis = 0; |
+ Print("%s %d\n", "size", num_phis); |
+ END("locals"); |
+ } |
+ END("states"); |
+ } |
+ |
+ { |
+ BEGIN("HIR"); |
+ // Print the block entry. |
+ Print("0 0 "); // Required fields "bci" and "use". Unused. |
+ Instruction* current = block_order_[i]; |
+ PrintInstruction(current); |
+ current = current->StraightLineSuccessor(); |
+ // And all the successors until an exit, branch, or a block entry. |
+ while ((current != NULL) && !current->IsBlockEntry()) { |
+ Print("0 0 "); |
+ PrintInstruction(current); |
+ current = current->StraightLineSuccessor(); |
+ } |
+ BlockEntryInstr* successor = |
+ (current == NULL) ? NULL : current->AsBlockEntry(); |
+ if (successor != NULL) { |
+ Print("0 0 _ Goto B%d <|@\n", successor->block_id()); |
+ } |
+ END("HIR"); |
+ } |
+ END("block"); |
+ } |
+ END("cfg"); |
+ } |
+#undef BEGIN |
+#undef END |
+} |
+ |
+ |
+// === Printing instructions in a visualizer-understandable format: |
+// "result instruction(op1, op2)" where result is a temporary name |
+// or _ for instruction without result. |
+void GraphEntryInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("_ [graph]"); |
+} |
+ |
+ |
+void JoinEntryInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("_ [join]"); |
+} |
+ |
+ |
+void TargetEntryInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("_ [target"); |
+ if (HasTryIndex()) { |
+ f->Print(" catch %d]", try_index()); |
+ } else { |
+ f->Print("]"); |
+ } |
+} |
+ |
+ |
+void DoInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("_ "); |
+ computation()->PrintTo(f); |
+} |
+ |
+ |
+void BindInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("t%d ", temp_index()); |
+ computation()->PrintTo(f); |
+} |
+ |
+ |
+void ReturnInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("_ %s ", DebugName()); |
+ value()->PrintTo(f); |
+} |
+ |
+ |
+void ThrowInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("_ %s ", DebugName()); |
+ exception()->PrintTo(f); |
+} |
+ |
+ |
+void ReThrowInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("_ %s ", DebugName()); |
+ exception()->PrintTo(f); |
+ f->Print(", "); |
+ stack_trace()->PrintTo(f); |
+} |
+ |
+ |
+void BranchInstr::PrintToVisualizer(BufferFormatter* f) const { |
+ f->Print("_ %s ", DebugName()); |
+ f->Print("if "); |
+ value()->PrintTo(f); |
+ f->Print(" goto (B%d, B%d)", |
+ true_successor()->block_id(), |
+ false_successor()->block_id()); |
+} |
+ |
+ |
} // namespace dart |