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