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