1 /*
   2  * Copyright 2007-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any 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       fatal2("Couldn't connect to visualizer at %s:%d", PrintIdealGraphAddress, PrintIdealGraphPort);
 155     }
 156   }
 157 
 158   _xml = new (ResourceObj::C_HEAP) xmlStream(_output);
 159 
 160   head(TOP_ELEMENT);
 161 }
 162 
 163 // Destructor, close file or network stream
 164 IdealGraphPrinter::~IdealGraphPrinter() {
 165 
 166   tail(TOP_ELEMENT);
 167 
 168   // tty->print_cr("Walk time: %d", (int)_walk_time.milliseconds());
 169   // tty->print_cr("Output time: %d", (int)_output_time.milliseconds());
 170   // tty->print_cr("Build blocks time: %d", (int)_build_blocks_time.milliseconds());
 171 
 172   if(_xml) {
 173     delete _xml;
 174     _xml = NULL;
 175   }
 176 
 177   if (_stream) {
 178     delete _stream;
 179     if (_stream == _output) {
 180       _output = NULL;
 181     }
 182     _stream = NULL;
 183   }
 184 
 185   if (_output) {
 186     delete _output;
 187     _output = NULL;
 188   }
 189 }
 190 
 191 
 192 void IdealGraphPrinter::begin_elem(const char *s) {
 193   _xml->begin_elem(s);
 194 }
 195 
 196 void IdealGraphPrinter::end_elem() {
 197   _xml->end_elem();
 198 }
 199 
 200 void IdealGraphPrinter::begin_head(const char *s) {
 201   _xml->begin_head(s);
 202 }
 203 
 204 void IdealGraphPrinter::end_head() {
 205   _xml->end_head();
 206 }
 207 
 208 void IdealGraphPrinter::print_attr(const char *name, intptr_t val) {
 209   stringStream stream;
 210   stream.print(INTX_FORMAT, val);
 211   print_attr(name, stream.as_string());
 212 }
 213 
 214 void IdealGraphPrinter::print_attr(const char *name, const char *val) {
 215   _xml->print(" %s='", name);
 216   text(val);
 217   _xml->print("'");
 218 }
 219 
 220 void IdealGraphPrinter::head(const char *name) {
 221   _xml->head(name);
 222 }
 223 
 224 void IdealGraphPrinter::tail(const char *name) {
 225   _xml->tail(name);
 226 }
 227 
 228 void IdealGraphPrinter::text(const char *s) {
 229   _xml->text(s);
 230 }
 231 
 232 void IdealGraphPrinter::print_prop(const char *name, int val) {
 233 
 234   stringStream stream;
 235   stream.print("%d", val);
 236   print_prop(name, stream.as_string());
 237 }
 238 
 239 void IdealGraphPrinter::print_prop(const char *name, const char *val) {
 240   begin_head(PROPERTY_ELEMENT);
 241   print_attr(PROPERTY_NAME_PROPERTY, name);
 242   end_head();
 243   text(val);
 244   tail(PROPERTY_ELEMENT);
 245 }
 246 
 247 void IdealGraphPrinter::print_method(ciMethod *method, int bci, InlineTree *tree) {
 248   begin_head(METHOD_ELEMENT);
 249 
 250   stringStream str;
 251   method->print_name(&str);
 252 
 253   stringStream shortStr;
 254   method->print_short_name(&shortStr);
 255 
 256   print_attr(METHOD_NAME_PROPERTY, str.as_string());
 257   print_attr(METHOD_SHORT_NAME_PROPERTY, shortStr.as_string());
 258   print_attr(METHOD_BCI_PROPERTY, bci);
 259 
 260   end_head();
 261 
 262   head(BYTECODES_ELEMENT);
 263   output()->print_cr("<![CDATA[");
 264   method->print_codes_on(output());
 265   output()->print_cr("]]>");
 266   tail(BYTECODES_ELEMENT);
 267 
 268   head(INLINE_ELEMENT);
 269   if (tree != NULL) {
 270     GrowableArray<InlineTree *> subtrees = tree->subtrees();
 271     for (int i = 0; i < subtrees.length(); i++) {
 272       print_inline_tree(subtrees.at(i));
 273     }
 274   }
 275   tail(INLINE_ELEMENT);
 276 
 277   tail(METHOD_ELEMENT);
 278   output()->flush();
 279 }
 280 
 281 void IdealGraphPrinter::print_inline_tree(InlineTree *tree) {
 282 
 283   if (tree == NULL) return;
 284 
 285   ciMethod *method = tree->method();
 286   print_method(tree->method(), tree->caller_bci(), tree);
 287 
 288 }
 289 
 290 void IdealGraphPrinter::print_inlining(Compile* compile) {
 291 
 292   // Print inline tree
 293   if (_should_send_method) {
 294     InlineTree *inlineTree = compile->ilt();
 295     if (inlineTree != NULL) {
 296       print_inline_tree(inlineTree);
 297     } else {
 298       // print this method only
 299     }
 300   }
 301 }
 302 
 303 // Has to be called whenever a method is compiled
 304 void IdealGraphPrinter::begin_method(Compile* compile) {
 305 
 306   ciMethod *method = compile->method();
 307   assert(_output, "output stream must exist!");
 308   assert(method, "null methods are not allowed!");
 309   assert(!_current_method, "current method must be null!");
 310 
 311   head(GROUP_ELEMENT);
 312 
 313   head(PROPERTIES_ELEMENT);
 314 
 315   // Print properties
 316   // Add method name
 317   stringStream strStream;
 318   method->print_name(&strStream);
 319   print_prop(METHOD_NAME_PROPERTY, strStream.as_string());
 320 
 321   if (method->flags().is_public()) {
 322     print_prop(METHOD_IS_PUBLIC_PROPERTY, TRUE_VALUE);
 323   }
 324 
 325   if (method->flags().is_static()) {
 326     print_prop(METHOD_IS_STATIC_PROPERTY, TRUE_VALUE);
 327   }
 328 
 329   tail(PROPERTIES_ELEMENT);
 330 
 331   if (_stream) {
 332     char answer = 0;
 333     _xml->flush();
 334     int result = _stream->read(&answer, 1);
 335     _should_send_method = (answer == 'y');
 336   }
 337 
 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 ident %d", _depth);
 356   for (int i = 0; i < _depth; i++) {
 357     _xml->print(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 intptr_t IdealGraphPrinter::get_node_id(Node *n) {
 370   return (intptr_t)(n);
 371 }
 372 
 373 void IdealGraphPrinter::visit_node(Node *n, void *param) {
 374 
 375   if(param) {
 376 
 377     // Output edge
 378     intptr_t dest_id = get_node_id(n);
 379     for ( uint i = 0; i < n->len(); i++ ) {
 380       if ( n->in(i) ) {
 381         Node *source = n->in(i);
 382         begin_elem(EDGE_ELEMENT);
 383         intptr_t source_id = get_node_id(source);
 384         print_attr(FROM_PROPERTY, source_id);
 385         print_attr(TO_PROPERTY, dest_id);
 386         print_attr(INDEX_PROPERTY, i);
 387         end_elem();
 388       }
 389     }
 390 
 391   } else {
 392 
 393     // Output node
 394     begin_head(NODE_ELEMENT);
 395     print_attr(NODE_ID_PROPERTY, get_node_id(n));
 396     end_head();
 397 
 398     head(PROPERTIES_ELEMENT);
 399 
 400     Node *node = n;
 401 #ifndef PRODUCT
 402     node->_in_dump_cnt++;
 403     print_prop(NODE_NAME_PROPERTY, (const char *)node->Name());
 404     const Type *t = node->bottom_type();
 405     print_prop("type", (const char *)Type::msg[t->base()]);
 406     print_prop("idx", node->_idx);
 407 #ifdef ASSERT
 408     print_prop("debug_idx", node->_debug_idx);
 409 #endif
 410 
 411     if(C->cfg() != NULL) {
 412       Block *block = C->cfg()->_bbs[node->_idx];
 413       if(block == NULL) {
 414         print_prop("block", C->cfg()->_blocks[0]->_pre_order);
 415       } else {
 416         print_prop("block", block->_pre_order);
 417       }
 418     }
 419 
 420     const jushort flags = node->flags();
 421     if (flags & Node::Flag_is_Copy) {
 422       print_prop("is_copy", "true");
 423     }
 424     if (flags & Node::Flag_is_Call) {
 425       print_prop("is_call", "true");
 426     }
 427     if (flags & Node::Flag_rematerialize) {
 428       print_prop("rematerialize", "true");
 429     }
 430     if (flags & Node::Flag_needs_anti_dependence_check) {
 431       print_prop("needs_anti_dependence_check", "true");
 432     }
 433     if (flags & Node::Flag_is_macro) {
 434       print_prop("is_macro", "true");
 435     }
 436     if (flags & Node::Flag_is_Con) {
 437       print_prop("is_con", "true");
 438     }
 439     if (flags & Node::Flag_is_cisc_alternate) {
 440       print_prop("is_cisc_alternate", "true");
 441     }
 442     if (flags & Node::Flag_is_Branch) {
 443       print_prop("is_branch", "true");
 444     }
 445     if (flags & Node::Flag_is_block_start) {
 446       print_prop("is_block_start", "true");
 447     }
 448     if (flags & Node::Flag_is_Goto) {
 449       print_prop("is_goto", "true");
 450     }
 451     if (flags & Node::Flag_is_dead_loop_safe) {
 452       print_prop("is_dead_loop_safe", "true");
 453     }
 454     if (flags & Node::Flag_may_be_short_branch) {
 455       print_prop("may_be_short_branch", "true");
 456     }
 457     if (flags & Node::Flag_is_safepoint_node) {
 458       print_prop("is_safepoint_node", "true");
 459     }
 460     if (flags & Node::Flag_is_pc_relative) {
 461       print_prop("is_pc_relative", "true");
 462     }
 463 
 464     if (C->matcher() != NULL) {
 465       if (C->matcher()->is_shared(node)) {
 466         print_prop("is_shared", "true");
 467       } else {
 468         print_prop("is_shared", "false");
 469       }
 470       if (C->matcher()->is_dontcare(node)) {
 471         print_prop("is_dontcare", "true");
 472       } else {
 473         print_prop("is_dontcare", "false");
 474       }
 475 
 476 #ifdef ASSERT
 477       Node* old = C->matcher()->find_old_node(node);
 478       if (old != NULL) {
 479         print_prop("old_node_idx", old->_idx);
 480       }
 481 #endif
 482     }
 483 
 484     if (node->is_Proj()) {
 485       print_prop("con", (int)node->as_Proj()->_con);
 486     }
 487 
 488     if (node->is_Mach()) {
 489       print_prop("idealOpcode", (const char *)NodeClassNames[node->as_Mach()->ideal_Opcode()]);
 490     }
 491 
 492     buffer[0] = 0;
 493     stringStream s2(buffer, sizeof(buffer) - 1);
 494 
 495     node->dump_spec(&s2);
 496     if (t != NULL && (t->isa_instptr() || t->isa_klassptr())) {
 497       const TypeInstPtr  *toop = t->isa_instptr();
 498       const TypeKlassPtr *tkls = t->isa_klassptr();
 499       ciKlass*           klass = toop ? toop->klass() : (tkls ? tkls->klass() : NULL );
 500       if( klass && klass->is_loaded() && klass->is_interface() ) {
 501         s2.print("  Interface:");
 502       } else if( toop ) {
 503         s2.print("  Oop:");
 504       } else if( tkls ) {
 505         s2.print("  Klass:");
 506       }
 507       t->dump_on(&s2);
 508     } else if( t == Type::MEMORY ) {
 509       s2.print("  Memory:");
 510       MemNode::dump_adr_type(node, node->adr_type(), &s2);
 511     }
 512 
 513     assert(s2.size() < sizeof(buffer), "size in range");
 514     print_prop("dump_spec", buffer);
 515 
 516     if (node->is_block_proj()) {
 517       print_prop("is_block_proj", "true");
 518     }
 519 
 520     if (node->is_block_start()) {
 521       print_prop("is_block_start", "true");
 522     }
 523 
 524     const char *short_name = "short_name";
 525     if (strcmp(node->Name(), "Parm") == 0 && node->as_Proj()->_con >= TypeFunc::Parms) {
 526       int index = node->as_Proj()->_con - TypeFunc::Parms;
 527       if (index >= 10) {
 528         print_prop(short_name, "PA");
 529       } else {
 530         sprintf(buffer, "P%d", index);
 531         print_prop(short_name, buffer);
 532       }
 533     } else if (strcmp(node->Name(), "IfTrue") == 0) {
 534       print_prop(short_name, "T");
 535     } else if (strcmp(node->Name(), "IfFalse") == 0) {
 536       print_prop(short_name, "F");
 537     } else if ((node->is_Con() && node->is_Type()) || node->is_Proj()) {
 538 
 539       if (t->base() == Type::Int && t->is_int()->is_con()) {
 540         const TypeInt *typeInt = t->is_int();
 541         assert(typeInt->is_con(), "must be constant");
 542         jint value = typeInt->get_con();
 543 
 544         // max. 2 chars allowed
 545         if (value >= -9 && value <= 99) {
 546           sprintf(buffer, "%d", value);
 547           print_prop(short_name, buffer);
 548         } else {
 549           print_prop(short_name, "I");
 550         }
 551       } else if (t == Type::TOP) {
 552         print_prop(short_name, "^");
 553       } else if (t->base() == Type::Long && t->is_long()->is_con()) {
 554         const TypeLong *typeLong = t->is_long();
 555         assert(typeLong->is_con(), "must be constant");
 556         jlong value = typeLong->get_con();
 557 
 558         // max. 2 chars allowed
 559         if (value >= -9 && value <= 99) {
 560           sprintf(buffer, "%d", value);
 561           print_prop(short_name, buffer);
 562         } else {
 563           print_prop(short_name, "L");
 564         }
 565       } else if (t->base() == Type::KlassPtr) {
 566         const TypeKlassPtr *typeKlass = t->is_klassptr();
 567         print_prop(short_name, "CP");
 568       } else if (t->base() == Type::Control) {
 569         print_prop(short_name, "C");
 570       } else if (t->base() == Type::Memory) {
 571         print_prop(short_name, "M");
 572       } else if (t->base() == Type::Abio) {
 573         print_prop(short_name, "IO");
 574       } else if (t->base() == Type::Return_Address) {
 575         print_prop(short_name, "RA");
 576       } else if (t->base() == Type::AnyPtr) {
 577         print_prop(short_name, "P");
 578       } else if (t->base() == Type::RawPtr) {
 579         print_prop(short_name, "RP");
 580       } else if (t->base() == Type::AryPtr) {
 581         print_prop(short_name, "AP");
 582       }
 583     }
 584 
 585     JVMState* caller = NULL;
 586     if (node->is_SafePoint()) {
 587       caller = node->as_SafePoint()->jvms();
 588     } else {
 589       Node_Notes* notes = C->node_notes_at(node->_idx);
 590       if (notes != NULL) {
 591         caller = notes->jvms();
 592       }
 593     }
 594 
 595     if (caller != NULL) {
 596       stringStream bciStream;
 597       while(caller) {
 598         bciStream.print("%d ", caller->bci());
 599         caller = caller->caller();
 600       }
 601       print_prop("bci", bciStream.as_string());
 602     }
 603 
 604     if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) {
 605       buffer[0] = 0;
 606       _chaitin->dump_register(node, buffer);
 607       print_prop("reg", buffer);
 608       print_prop("lrg", _chaitin->n2lidx(node));
 609     }
 610 
 611     node->_in_dump_cnt--;
 612 #endif
 613 
 614     tail(PROPERTIES_ELEMENT);
 615     tail(NODE_ELEMENT);
 616   }
 617 }
 618 
 619 void IdealGraphPrinter::walk_nodes(Node *start, void *param) {
 620 
 621 
 622   VectorSet visited(Thread::current()->resource_area());
 623   GrowableArray<Node *> nodeStack(Thread::current()->resource_area(), 0, 0, NULL);
 624   nodeStack.push(start);
 625   visited.test_set(start->_idx);
 626   while(nodeStack.length() > 0) {
 627 
 628     Node *n = nodeStack.pop();
 629     visit_node(n, param);
 630 
 631     if (_traverse_outs) {
 632       for (DUIterator i = n->outs(); n->has_out(i); i++) {
 633         Node* p = n->out(i);
 634         if (!visited.test_set(p->_idx)) {
 635           nodeStack.push(p);
 636         }
 637       }
 638     }
 639 
 640     for ( uint i = 0; i < n->len(); i++ ) {
 641       if ( n->in(i) ) {
 642         if (!visited.test_set(n->in(i)->_idx)) {
 643           nodeStack.push(n->in(i));
 644         }
 645       }
 646     }
 647   }
 648 }
 649 
 650 void IdealGraphPrinter::print_method(Compile* compile, const char *name, int level, bool clear_nodes) {
 651   print(compile, name, (Node *)compile->root(), level, clear_nodes);
 652 }
 653 
 654 // Print current ideal graph
 655 void IdealGraphPrinter::print(Compile* compile, const char *name, Node *node, int level, bool clear_nodes) {
 656 
 657   if (!_current_method || !_should_send_method || level > PrintIdealGraphLevel) return;
 658 
 659   this->C = compile;
 660 
 661   // Warning, unsafe cast?
 662   _chaitin = (PhaseChaitin *)C->regalloc();
 663 
 664   begin_head(GRAPH_ELEMENT);
 665   print_attr(GRAPH_NAME_PROPERTY, (const char *)name);
 666   end_head();
 667 
 668   head(NODES_ELEMENT);
 669   walk_nodes(node, NULL);
 670   tail(NODES_ELEMENT);
 671 
 672   head(EDGES_ELEMENT);
 673   walk_nodes(node, (void *)1);
 674   tail(EDGES_ELEMENT);
 675   if (C->cfg() != NULL) {
 676     head(CONTROL_FLOW_ELEMENT);
 677     for (uint i = 0; i < C->cfg()->_blocks.size(); i++) {
 678       Block *b = C->cfg()->_blocks[i];
 679       begin_head(BLOCK_ELEMENT);
 680       print_attr(BLOCK_NAME_PROPERTY, b->_pre_order);
 681       end_head();
 682 
 683       head(SUCCESSORS_ELEMENT);
 684       for (uint s = 0; s < C->cfg()->_blocks[i]->_num_succs; s++) {
 685         begin_elem(SUCCESSOR_ELEMENT);
 686         print_attr(BLOCK_NAME_PROPERTY, b->_succs[s]->_pre_order);
 687         end_elem();
 688       }
 689       tail(SUCCESSORS_ELEMENT);
 690 
 691       tail(BLOCK_ELEMENT);
 692     }
 693 
 694     tail(CONTROL_FLOW_ELEMENT);
 695   }
 696   tail(GRAPH_ELEMENT);
 697   output()->flush();
 698 }
 699 
 700 extern const char *NodeClassNames[];
 701 
 702 outputStream *IdealGraphPrinter::output() {
 703   return _xml;
 704 }
 705 
 706 #endif