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