1 /*
   2  * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "memory/resourceArea.hpp"
  27 #include "opto/chaitin.hpp"
  28 #include "opto/idealGraphPrinter.hpp"
  29 #include "opto/machnode.hpp"
  30 #include "opto/parse.hpp"
  31 #include "runtime/threadCritical.hpp"
  32 
  33 #ifndef PRODUCT
  34 
  35 // Constants
  36 // Keep consistent with Java constants
  37 const char *IdealGraphPrinter::INDENT = "  ";
  38 const char *IdealGraphPrinter::TOP_ELEMENT = "graphDocument";
  39 const char *IdealGraphPrinter::GROUP_ELEMENT = "group";
  40 const char *IdealGraphPrinter::GRAPH_ELEMENT = "graph";
  41 const char *IdealGraphPrinter::PROPERTIES_ELEMENT = "properties";
  42 const char *IdealGraphPrinter::EDGES_ELEMENT = "edges";
  43 const char *IdealGraphPrinter::PROPERTY_ELEMENT = "p";
  44 const char *IdealGraphPrinter::EDGE_ELEMENT = "edge";
  45 const char *IdealGraphPrinter::NODE_ELEMENT = "node";
  46 const char *IdealGraphPrinter::NODES_ELEMENT = "nodes";
  47 const char *IdealGraphPrinter::REMOVE_EDGE_ELEMENT = "removeEdge";
  48 const char *IdealGraphPrinter::REMOVE_NODE_ELEMENT = "removeNode";
  49 const char *IdealGraphPrinter::METHOD_NAME_PROPERTY = "name";
  50 const char *IdealGraphPrinter::METHOD_IS_PUBLIC_PROPERTY = "public";
  51 const char *IdealGraphPrinter::METHOD_IS_STATIC_PROPERTY = "static";
  52 const char *IdealGraphPrinter::TRUE_VALUE = "true";
  53 const char *IdealGraphPrinter::NODE_NAME_PROPERTY = "name";
  54 const char *IdealGraphPrinter::EDGE_NAME_PROPERTY = "name";
  55 const char *IdealGraphPrinter::NODE_ID_PROPERTY = "id";
  56 const char *IdealGraphPrinter::FROM_PROPERTY = "from";
  57 const char *IdealGraphPrinter::TO_PROPERTY = "to";
  58 const char *IdealGraphPrinter::PROPERTY_NAME_PROPERTY = "name";
  59 const char *IdealGraphPrinter::GRAPH_NAME_PROPERTY = "name";
  60 const char *IdealGraphPrinter::INDEX_PROPERTY = "index";
  61 const char *IdealGraphPrinter::METHOD_ELEMENT = "method";
  62 const char *IdealGraphPrinter::INLINE_ELEMENT = "inlined";
  63 const char *IdealGraphPrinter::BYTECODES_ELEMENT = "bytecodes";
  64 const char *IdealGraphPrinter::METHOD_BCI_PROPERTY = "bci";
  65 const char *IdealGraphPrinter::METHOD_SHORT_NAME_PROPERTY = "shortName";
  66 const char *IdealGraphPrinter::CONTROL_FLOW_ELEMENT = "controlFlow";
  67 const char *IdealGraphPrinter::BLOCK_NAME_PROPERTY = "name";
  68 const char *IdealGraphPrinter::BLOCK_DOMINATOR_PROPERTY = "dom";
  69 const char *IdealGraphPrinter::BLOCK_ELEMENT = "block";
  70 const char *IdealGraphPrinter::SUCCESSORS_ELEMENT = "successors";
  71 const char *IdealGraphPrinter::SUCCESSOR_ELEMENT = "successor";
  72 const char *IdealGraphPrinter::ASSEMBLY_ELEMENT = "assembly";
  73 
  74 int IdealGraphPrinter::_file_count = 0;
  75 
  76 IdealGraphPrinter *IdealGraphPrinter::printer() {
  77   if (!PrintIdealGraph) {
  78     return NULL;
  79   }
  80 
  81   JavaThread *thread = JavaThread::current();
  82   if (!thread->is_Compiler_thread()) return NULL;
  83 
  84   CompilerThread *compiler_thread = (CompilerThread *)thread;
  85   if (compiler_thread->ideal_graph_printer() == NULL) {
  86     IdealGraphPrinter *printer = new IdealGraphPrinter();
  87     compiler_thread->set_ideal_graph_printer(printer);
  88   }
  89 
  90   return compiler_thread->ideal_graph_printer();
  91 }
  92 
  93 void IdealGraphPrinter::clean_up() {
  94   JavaThread *p;
  95   for (p = Threads::first(); p; p = p->next()) {
  96     if (p->is_Compiler_thread()) {
  97       CompilerThread *c = (CompilerThread *)p;
  98       IdealGraphPrinter *printer = c->ideal_graph_printer();
  99       if (printer) {
 100         delete printer;
 101       }
 102       c->set_ideal_graph_printer(NULL);
 103     }
 104   }
 105 }
 106 
 107 // Constructor, either file or network output
 108 IdealGraphPrinter::IdealGraphPrinter() {
 109 
 110   // By default dump both ins and outs since dead or unreachable code
 111   // needs to appear in the graph.  There are also some special cases
 112   // in the mach where kill projections have no users but should
 113   // appear in the dump.
 114   _traverse_outs = true;
 115   _should_send_method = true;
 116   _output = NULL;
 117   buffer[0] = 0;
 118   _depth = 0;
 119   _current_method = NULL;
 120   assert(!_current_method, "current method must be initialized to NULL");
 121   _stream = NULL;
 122 
 123   if (PrintIdealGraphFile != NULL) {
 124     ThreadCritical tc;
 125     // User wants all output to go to files
 126     if (_file_count != 0) {
 127       ResourceMark rm;
 128       stringStream st;
 129       const char* dot = strrchr(PrintIdealGraphFile, '.');
 130       if (dot) {
 131         st.write(PrintIdealGraphFile, dot - PrintIdealGraphFile);
 132         st.print("%d%s", _file_count, dot);
 133       } else {
 134         st.print("%s%d", PrintIdealGraphFile, _file_count);
 135       }
 136       fileStream *stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(st.as_string());
 137       _output = stream;
 138     } else {
 139       fileStream *stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(PrintIdealGraphFile);
 140       _output = stream;
 141     }
 142     _file_count++;
 143   } else {
 144     _stream = new (ResourceObj::C_HEAP, mtCompiler) networkStream();
 145 
 146     // Try to connect to visualizer
 147     if (_stream->connect(PrintIdealGraphAddress, PrintIdealGraphPort)) {
 148       char c = 0;
 149       _stream->read(&c, 1);
 150       if (c != 'y') {
 151         tty->print_cr("Client available, but does not want to receive data!");
 152         _stream->close();
 153         delete _stream;
 154         _stream = NULL;
 155         return;
 156       }
 157       _output = _stream;
 158     } else {
 159       // It would be nice if we could shut down cleanly but it should
 160       // be an error if we can't connect to the visualizer.
 161       fatal("Couldn't connect to visualizer at %s:" INTX_FORMAT,
 162             PrintIdealGraphAddress, PrintIdealGraphPort);
 163     }
 164   }
 165 
 166   _xml = new (ResourceObj::C_HEAP, mtCompiler) xmlStream(_output);
 167 
 168   head(TOP_ELEMENT);
 169 }
 170 
 171 // Destructor, close file or network stream
 172 IdealGraphPrinter::~IdealGraphPrinter() {
 173 
 174   tail(TOP_ELEMENT);
 175 
 176   // tty->print_cr("Walk time: %d", (int)_walk_time.milliseconds());
 177   // tty->print_cr("Output time: %d", (int)_output_time.milliseconds());
 178   // tty->print_cr("Build blocks time: %d", (int)_build_blocks_time.milliseconds());
 179 
 180   if(_xml) {
 181     delete _xml;
 182     _xml = NULL;
 183   }
 184 
 185   if (_stream) {
 186     delete _stream;
 187     if (_stream == _output) {
 188       _output = NULL;
 189     }
 190     _stream = NULL;
 191   }
 192 
 193   if (_output) {
 194     delete _output;
 195     _output = NULL;
 196   }
 197 }
 198 
 199 void IdealGraphPrinter::begin_elem(const char *s) {
 200   _xml->begin_elem("%s", s);
 201 }
 202 
 203 void IdealGraphPrinter::end_elem() {
 204   _xml->end_elem();
 205 }
 206 
 207 void IdealGraphPrinter::begin_head(const char *s) {
 208   _xml->begin_head("%s", s);
 209 }
 210 
 211 void IdealGraphPrinter::end_head() {
 212   _xml->end_head();
 213 }
 214 
 215 void IdealGraphPrinter::print_attr(const char *name, intptr_t val) {
 216   stringStream stream;
 217   stream.print(INTX_FORMAT, val);
 218   print_attr(name, stream.as_string());
 219 }
 220 
 221 void IdealGraphPrinter::print_attr(const char *name, const char *val) {
 222   _xml->print(" %s='", name);
 223   text(val);
 224   _xml->print("'");
 225 }
 226 
 227 void IdealGraphPrinter::head(const char *name) {
 228   _xml->head("%s", name);
 229 }
 230 
 231 void IdealGraphPrinter::tail(const char *name) {
 232   _xml->tail(name);
 233 }
 234 
 235 void IdealGraphPrinter::text(const char *s) {
 236   _xml->text("%s", s);
 237 }
 238 
 239 void IdealGraphPrinter::print_prop(const char *name, int val) {
 240   stringStream stream;
 241   stream.print("%d", val);
 242   print_prop(name, stream.as_string());
 243 }
 244 
 245 void IdealGraphPrinter::print_prop(const char *name, const char *val) {
 246   begin_head(PROPERTY_ELEMENT);
 247   print_attr(PROPERTY_NAME_PROPERTY, name);
 248   end_head();
 249   text(val);
 250   tail(PROPERTY_ELEMENT);
 251 }
 252 
 253 void IdealGraphPrinter::print_method(ciMethod *method, int bci, InlineTree *tree) {
 254   begin_head(METHOD_ELEMENT);
 255 
 256   stringStream str;
 257   method->print_name(&str);
 258 
 259   stringStream shortStr;
 260   method->print_short_name(&shortStr);
 261 
 262   print_attr(METHOD_NAME_PROPERTY, str.as_string());
 263   print_attr(METHOD_SHORT_NAME_PROPERTY, shortStr.as_string());
 264   print_attr(METHOD_BCI_PROPERTY, bci);
 265 
 266   end_head();
 267 
 268   head(BYTECODES_ELEMENT);
 269   _xml->print_cr("<![CDATA[");
 270   method->print_codes_on(_xml);
 271   _xml->print_cr("]]>");
 272   tail(BYTECODES_ELEMENT);
 273 
 274   if (tree != NULL && tree->subtrees().length() > 0) {
 275     head(INLINE_ELEMENT);
 276     GrowableArray<InlineTree *> subtrees = tree->subtrees();
 277     for (int i = 0; i < subtrees.length(); i++) {
 278       print_inline_tree(subtrees.at(i));
 279     }
 280     tail(INLINE_ELEMENT);
 281   }
 282 
 283   tail(METHOD_ELEMENT);
 284   _xml->flush();
 285 }
 286 
 287 void IdealGraphPrinter::print_inline_tree(InlineTree *tree) {
 288 
 289   if (tree == NULL) return;
 290 
 291   ciMethod *method = tree->method();
 292   print_method(tree->method(), tree->caller_bci(), tree);
 293 
 294 }
 295 
 296 void IdealGraphPrinter::print_inlining() {
 297 
 298   // Print inline tree
 299   if (_should_send_method) {
 300     InlineTree *inlineTree = C->ilt();
 301     if (inlineTree != NULL) {
 302       print_inline_tree(inlineTree);
 303     } else {
 304       // print this method only
 305     }
 306   }
 307 }
 308 
 309 // Has to be called whenever a method is compiled
 310 void IdealGraphPrinter::begin_method() {
 311 
 312   ciMethod *method = C->method();
 313   assert(_output, "output stream must exist!");
 314   assert(method, "null methods are not allowed!");
 315   assert(!_current_method, "current method must be null!");
 316 
 317   head(GROUP_ELEMENT);
 318 
 319   head(PROPERTIES_ELEMENT);
 320 
 321   // Print properties
 322   // Add method name
 323   stringStream strStream;
 324   method->print_name(&strStream);
 325   print_prop(METHOD_NAME_PROPERTY, strStream.as_string());
 326 
 327   if (method->flags().is_public()) {
 328     print_prop(METHOD_IS_PUBLIC_PROPERTY, TRUE_VALUE);
 329   }
 330 
 331   if (method->flags().is_static()) {
 332     print_prop(METHOD_IS_STATIC_PROPERTY, TRUE_VALUE);
 333   }
 334 
 335   tail(PROPERTIES_ELEMENT);
 336 
 337   _should_send_method = true;
 338   this->_current_method = method;
 339 
 340   _xml->flush();
 341 }
 342 
 343 // Has to be called whenever a method has finished compilation
 344 void IdealGraphPrinter::end_method() {
 345 
 346   nmethod* method = (nmethod*)this->_current_method->code();
 347 
 348   tail(GROUP_ELEMENT);
 349   _current_method = NULL;
 350   _xml->flush();
 351 }
 352 
 353 // Print indent
 354 void IdealGraphPrinter::print_indent() {
 355   tty->print_cr("printing indent %d", _depth);
 356   for (int i = 0; i < _depth; i++) {
 357     _xml->print("%s", INDENT);
 358   }
 359 }
 360 
 361 bool IdealGraphPrinter::traverse_outs() {
 362   return _traverse_outs;
 363 }
 364 
 365 void IdealGraphPrinter::set_traverse_outs(bool b) {
 366   _traverse_outs = b;
 367 }
 368 
 369 void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) {
 370 
 371   if (edges) {
 372 
 373     // Output edge
 374     node_idx_t dest_id = n->_idx;
 375     for ( uint i = 0; i < n->len(); i++ ) {
 376       if ( n->in(i) ) {
 377         Node *source = n->in(i);
 378         begin_elem(EDGE_ELEMENT);
 379         print_attr(FROM_PROPERTY, source->_idx);
 380         print_attr(TO_PROPERTY, dest_id);
 381         print_attr(INDEX_PROPERTY, i);
 382         end_elem();
 383       }
 384     }
 385 
 386   } else {
 387 
 388     // Output node
 389     begin_head(NODE_ELEMENT);
 390     print_attr(NODE_ID_PROPERTY, n->_idx);
 391     end_head();
 392 
 393     head(PROPERTIES_ELEMENT);
 394 
 395     Node *node = n;
 396 #ifndef PRODUCT
 397     Compile::current()->_in_dump_cnt++;
 398     print_prop(NODE_NAME_PROPERTY, (const char *)node->Name());
 399     const Type *t = node->bottom_type();
 400     print_prop("type", t->msg());
 401     print_prop("idx", node->_idx);
 402 #ifdef ASSERT
 403     print_prop("debug_idx", node->_debug_idx);
 404 #endif
 405 
 406     if (C->cfg() != NULL) {
 407       Block* block = C->cfg()->get_block_for_node(node);
 408       if (block == NULL) {
 409         print_prop("block", C->cfg()->get_block(0)->_pre_order);
 410       } else {
 411         print_prop("block", block->_pre_order);
 412       }
 413     }
 414 
 415     const jushort flags = node->flags();
 416     if (flags & Node::Flag_is_Copy) {
 417       print_prop("is_copy", "true");
 418     }
 419     if (flags & Node::Flag_rematerialize) {
 420       print_prop("rematerialize", "true");
 421     }
 422     if (flags & Node::Flag_needs_anti_dependence_check) {
 423       print_prop("needs_anti_dependence_check", "true");
 424     }
 425     if (flags & Node::Flag_is_macro) {
 426       print_prop("is_macro", "true");
 427     }
 428     if (flags & Node::Flag_is_Con) {
 429       print_prop("is_con", "true");
 430     }
 431     if (flags & Node::Flag_is_cisc_alternate) {
 432       print_prop("is_cisc_alternate", "true");
 433     }
 434     if (flags & Node::Flag_is_dead_loop_safe) {
 435       print_prop("is_dead_loop_safe", "true");
 436     }
 437     if (flags & Node::Flag_may_be_short_branch) {
 438       print_prop("may_be_short_branch", "true");
 439     }
 440     if (flags & Node::Flag_has_call) {
 441       print_prop("has_call", "true");
 442     }
 443 
 444     if (C->matcher() != NULL) {
 445       if (C->matcher()->is_shared(node)) {
 446         print_prop("is_shared", "true");
 447       } else {
 448         print_prop("is_shared", "false");
 449       }
 450       if (C->matcher()->is_dontcare(node)) {
 451         print_prop("is_dontcare", "true");
 452       } else {
 453         print_prop("is_dontcare", "false");
 454       }
 455 
 456 #ifdef ASSERT
 457       Node* old = C->matcher()->find_old_node(node);
 458       if (old != NULL) {
 459         print_prop("old_node_idx", old->_idx);
 460       }
 461 #endif
 462     }
 463 
 464     if (node->is_Proj()) {
 465       print_prop("con", (int)node->as_Proj()->_con);
 466     }
 467 
 468     if (node->is_Mach()) {
 469       print_prop("idealOpcode", (const char *)NodeClassNames[node->as_Mach()->ideal_Opcode()]);
 470     }
 471 
 472     buffer[0] = 0;
 473     stringStream s2(buffer, sizeof(buffer) - 1);
 474 
 475     node->dump_spec(&s2);
 476     if (t != NULL && (t->isa_instptr() || t->isa_klassptr())) {
 477       const TypeInstPtr  *toop = t->isa_instptr();
 478       const TypeKlassPtr *tkls = t->isa_klassptr();
 479       ciKlass*           klass = toop ? toop->klass() : (tkls ? tkls->klass() : NULL );
 480       if( klass && klass->is_loaded() && klass->is_interface() ) {
 481         s2.print("  Interface:");
 482       } else if( toop ) {
 483         s2.print("  Oop:");
 484       } else if( tkls ) {
 485         s2.print("  Klass:");
 486       }
 487       t->dump_on(&s2);
 488     } else if( t == Type::MEMORY ) {
 489       s2.print("  Memory:");
 490       MemNode::dump_adr_type(node, node->adr_type(), &s2);
 491     }
 492 
 493     assert(s2.size() < sizeof(buffer), "size in range");
 494     print_prop("dump_spec", buffer);
 495 
 496     if (node->is_block_proj()) {
 497       print_prop("is_block_proj", "true");
 498     }
 499 
 500     if (node->is_block_start()) {
 501       print_prop("is_block_start", "true");
 502     }
 503 
 504     const char *short_name = "short_name";
 505     if (strcmp(node->Name(), "Parm") == 0 && node->as_Proj()->_con >= TypeFunc::Parms) {
 506       int index = node->as_Proj()->_con - TypeFunc::Parms;
 507       if (index >= 10) {
 508         print_prop(short_name, "PA");
 509       } else {
 510         sprintf(buffer, "P%d", index);
 511         print_prop(short_name, buffer);
 512       }
 513     } else if (strcmp(node->Name(), "IfTrue") == 0) {
 514       print_prop(short_name, "T");
 515     } else if (strcmp(node->Name(), "IfFalse") == 0) {
 516       print_prop(short_name, "F");
 517     } else if ((node->is_Con() && node->is_Type()) || node->is_Proj()) {
 518 
 519       if (t->base() == Type::Int && t->is_int()->is_con()) {
 520         const TypeInt *typeInt = t->is_int();
 521         assert(typeInt->is_con(), "must be constant");
 522         jint value = typeInt->get_con();
 523 
 524         // max. 2 chars allowed
 525         if (value >= -9 && value <= 99) {
 526           sprintf(buffer, "%d", value);
 527           print_prop(short_name, buffer);
 528         } else {
 529           print_prop(short_name, "I");
 530         }
 531       } else if (t == Type::TOP) {
 532         print_prop(short_name, "^");
 533       } else if (t->base() == Type::Long && t->is_long()->is_con()) {
 534         const TypeLong *typeLong = t->is_long();
 535         assert(typeLong->is_con(), "must be constant");
 536         jlong value = typeLong->get_con();
 537 
 538         // max. 2 chars allowed
 539         if (value >= -9 && value <= 99) {
 540           sprintf(buffer, JLONG_FORMAT, value);
 541           print_prop(short_name, buffer);
 542         } else {
 543           print_prop(short_name, "L");
 544         }
 545       } else if (t->base() == Type::KlassPtr) {
 546         const TypeKlassPtr *typeKlass = t->is_klassptr();
 547         print_prop(short_name, "CP");
 548       } else if (t->base() == Type::Control) {
 549         print_prop(short_name, "C");
 550       } else if (t->base() == Type::Memory) {
 551         print_prop(short_name, "M");
 552       } else if (t->base() == Type::Abio) {
 553         print_prop(short_name, "IO");
 554       } else if (t->base() == Type::Return_Address) {
 555         print_prop(short_name, "RA");
 556       } else if (t->base() == Type::AnyPtr) {
 557         print_prop(short_name, "P");
 558       } else if (t->base() == Type::RawPtr) {
 559         print_prop(short_name, "RP");
 560       } else if (t->base() == Type::AryPtr) {
 561         print_prop(short_name, "AP");
 562       }
 563     }
 564 
 565     JVMState* caller = NULL;
 566     if (node->is_SafePoint()) {
 567       caller = node->as_SafePoint()->jvms();
 568     } else {
 569       Node_Notes* notes = C->node_notes_at(node->_idx);
 570       if (notes != NULL) {
 571         caller = notes->jvms();
 572       }
 573     }
 574 
 575     if (caller != NULL) {
 576       stringStream bciStream;
 577       ciMethod* last = NULL;
 578       int last_bci;
 579       while(caller) {
 580         if (caller->has_method()) {
 581           last = caller->method();
 582           last_bci = caller->bci();
 583         }
 584         bciStream.print("%d ", caller->bci());
 585         caller = caller->caller();
 586       }
 587       print_prop("bci", bciStream.as_string());
 588       if (last != NULL && last->has_linenumber_table() && last_bci >= 0) {
 589         print_prop("line", last->line_number_from_bci(last_bci));
 590       }
 591     }
 592 
 593 #ifdef ASSERT
 594     if (node->debug_orig() != NULL) {
 595       temp_set->Clear();
 596       stringStream dorigStream;
 597       Node* dorig = node->debug_orig();
 598       while (dorig && temp_set->test_set(dorig->_idx)) {
 599         dorigStream.print("%d ", dorig->_idx);
 600       }
 601       print_prop("debug_orig", dorigStream.as_string());
 602     }
 603 #endif
 604 
 605     if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) {
 606       buffer[0] = 0;
 607       _chaitin->dump_register(node, buffer);
 608       print_prop("reg", buffer);
 609       uint lrg_id = 0;
 610       if (node->_idx < _chaitin->_lrg_map.size()) {
 611         lrg_id = _chaitin->_lrg_map.live_range_id(node);
 612       }
 613       print_prop("lrg", lrg_id);
 614     }
 615 
 616     Compile::current()->_in_dump_cnt--;
 617 #endif
 618 
 619     tail(PROPERTIES_ELEMENT);
 620     tail(NODE_ELEMENT);
 621   }
 622 }
 623 
 624 void IdealGraphPrinter::walk_nodes(Node *start, bool edges, VectorSet* temp_set) {
 625 
 626 
 627   VectorSet visited(Thread::current()->resource_area());
 628   GrowableArray<Node *> nodeStack(Thread::current()->resource_area(), 0, 0, NULL);
 629   nodeStack.push(start);
 630   visited.test_set(start->_idx);
 631   if (C->cfg() != NULL) {
 632     // once we have a CFG there are some nodes that aren't really
 633     // reachable but are in the CFG so add them here.
 634     for (uint i = 0; i < C->cfg()->number_of_blocks(); i++) {
 635       Block* block = C->cfg()->get_block(i);
 636       for (uint s = 0; s < block->number_of_nodes(); s++) {
 637         nodeStack.push(block->get_node(s));
 638       }
 639     }
 640   }
 641 
 642   while(nodeStack.length() > 0) {
 643 
 644     Node *n = nodeStack.pop();
 645     visit_node(n, edges, temp_set);
 646 
 647     if (_traverse_outs) {
 648       for (DUIterator i = n->outs(); n->has_out(i); i++) {
 649         Node* p = n->out(i);
 650         if (!visited.test_set(p->_idx)) {
 651           nodeStack.push(p);
 652         }
 653       }
 654     }
 655 
 656     for ( uint i = 0; i < n->len(); i++ ) {
 657       if ( n->in(i) ) {
 658         if (!visited.test_set(n->in(i)->_idx)) {
 659           nodeStack.push(n->in(i));
 660         }
 661       }
 662     }
 663   }
 664 }
 665 
 666 void IdealGraphPrinter::print_method(const char *name, int level, bool clear_nodes) {
 667   print(name, (Node *)C->root(), level, clear_nodes);
 668 }
 669 
 670 // Print current ideal graph
 671 void IdealGraphPrinter::print(const char *name, Node *node, int level, bool clear_nodes) {
 672 
 673   if (!_current_method || !_should_send_method || !should_print(level)) return;
 674 
 675   // Warning, unsafe cast?
 676   _chaitin = (PhaseChaitin *)C->regalloc();
 677 
 678   begin_head(GRAPH_ELEMENT);
 679   print_attr(GRAPH_NAME_PROPERTY, (const char *)name);
 680   end_head();
 681 
 682   VectorSet temp_set(Thread::current()->resource_area());
 683 
 684   head(NODES_ELEMENT);
 685   walk_nodes(node, false, &temp_set);
 686   tail(NODES_ELEMENT);
 687 
 688   head(EDGES_ELEMENT);
 689   walk_nodes(node, true, &temp_set);
 690   tail(EDGES_ELEMENT);
 691   if (C->cfg() != NULL) {
 692     head(CONTROL_FLOW_ELEMENT);
 693     for (uint i = 0; i < C->cfg()->number_of_blocks(); i++) {
 694       Block* block = C->cfg()->get_block(i);
 695       begin_head(BLOCK_ELEMENT);
 696       print_attr(BLOCK_NAME_PROPERTY, block->_pre_order);
 697       end_head();
 698 
 699       head(SUCCESSORS_ELEMENT);
 700       for (uint s = 0; s < block->_num_succs; s++) {
 701         begin_elem(SUCCESSOR_ELEMENT);
 702         print_attr(BLOCK_NAME_PROPERTY, block->_succs[s]->_pre_order);
 703         end_elem();
 704       }
 705       tail(SUCCESSORS_ELEMENT);
 706 
 707       head(NODES_ELEMENT);
 708       for (uint s = 0; s < block->number_of_nodes(); s++) {
 709         begin_elem(NODE_ELEMENT);
 710         print_attr(NODE_ID_PROPERTY, block->get_node(s)->_idx);
 711         end_elem();
 712       }
 713       tail(NODES_ELEMENT);
 714 
 715       tail(BLOCK_ELEMENT);
 716     }
 717     tail(CONTROL_FLOW_ELEMENT);
 718   }
 719   tail(GRAPH_ELEMENT);
 720   _xml->flush();
 721 }
 722 
 723 // Should method be printed?
 724 bool IdealGraphPrinter::should_print(int level) {
 725   return C->directive()->IGVPrintLevelOption >= level;
 726 }
 727 
 728 extern const char *NodeClassNames[];
 729 
 730 #endif