Mercurial > hg > truffle
comparison src/share/vm/opto/idealGraphPrinter.cpp @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | 2a1a77d3458f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a61af66fc99e |
---|---|
1 /* | |
2 * Copyright 2007 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 _traverse_outs = false; | |
104 _should_send_method = true; | |
105 _output = NULL; | |
106 buffer[0] = 0; | |
107 _depth = 0; | |
108 _current_method = NULL; | |
109 assert(!_current_method, "current method must be initialized to NULL"); | |
110 _arena = new Arena(); | |
111 | |
112 _stream = new (ResourceObj::C_HEAP) networkStream(); | |
113 | |
114 if (PrintIdealGraphFile != NULL) { | |
115 ThreadCritical tc; | |
116 // User wants all output to go to files | |
117 if (_file_count != 0) { | |
118 ResourceMark rm; | |
119 stringStream st; | |
120 const char* dot = strrchr(PrintIdealGraphFile, '.'); | |
121 if (dot) { | |
122 st.write(PrintIdealGraphFile, dot - PrintIdealGraphFile); | |
123 st.print("%d%s", _file_count, dot); | |
124 } else { | |
125 st.print("%s%d", PrintIdealGraphFile, _file_count); | |
126 } | |
127 _output = new (ResourceObj::C_HEAP) fileStream(st.as_string()); | |
128 } else { | |
129 _output = new (ResourceObj::C_HEAP) fileStream(PrintIdealGraphFile); | |
130 } | |
131 _file_count++; | |
132 } else { | |
133 // Try to connect to visualizer | |
134 if (_stream->connect(PrintIdealGraphAddress, PrintIdealGraphPort)) { | |
135 char c = 0; | |
136 _stream->read(&c, 1); | |
137 if (c != 'y') { | |
138 tty->print_cr("Client available, but does not want to receive data!"); | |
139 _stream->close(); | |
140 delete _stream; | |
141 _stream = NULL; | |
142 return; | |
143 } | |
144 _output = _stream; | |
145 } else { | |
146 // It would be nice if we could shut down cleanly but it should | |
147 // be an error if we can't connect to the visualizer. | |
148 fatal2("Couldn't connect to visualizer at %s:%d", PrintIdealGraphAddress, PrintIdealGraphPort); | |
149 } | |
150 } | |
151 | |
152 start_element(TOP_ELEMENT); | |
153 } | |
154 | |
155 // Destructor, close file or network stream | |
156 IdealGraphPrinter::~IdealGraphPrinter() { | |
157 | |
158 end_element(TOP_ELEMENT); | |
159 | |
160 if (_stream) { | |
161 delete _stream; | |
162 if (_stream == _output) { | |
163 _output = NULL; | |
164 } | |
165 _stream = NULL; | |
166 } | |
167 | |
168 if (_output) { | |
169 delete _output; | |
170 _output = NULL; | |
171 } | |
172 } | |
173 | |
174 void IdealGraphPrinter::print_ifg(PhaseIFG* ifg) { | |
175 | |
176 // Code to print an interference graph to tty, currently not used | |
177 | |
178 /* | |
179 if (!_current_method) return; | |
180 // Remove neighbor colors | |
181 | |
182 for (uint i = 0; i < ifg._maxlrg; i++) { | |
183 | |
184 IndexSet *s = ifg.neighbors(i); | |
185 IndexSetIterator elements(s); | |
186 uint neighbor; | |
187 while ((neighbor = elements.next()) != 0) { | |
188 tty->print_cr("Edge between %d and %d\n", i, neighbor); | |
189 } | |
190 } | |
191 | |
192 | |
193 for (uint i = 0; i < ifg._maxlrg; i++) { | |
194 LRG &l = ifg.lrgs(i); | |
195 if (l._def) { | |
196 OptoReg::Name name = l.reg(); | |
197 tty->print("OptoReg::dump: "); | |
198 OptoReg::dump(name); | |
199 tty->print_cr(""); | |
200 tty->print_cr("name=%d\n", name); | |
201 if (name) { | |
202 if (OptoReg::is_stack(name)) { | |
203 tty->print_cr("Stack number %d\n", OptoReg::reg2stack(name)); | |
204 | |
205 } else if (!OptoReg::is_valid(name)) { | |
206 tty->print_cr("BAD!!!"); | |
207 } else { | |
208 | |
209 if (OptoReg::is_reg(name)) { | |
210 tty->print_cr(OptoReg::regname(name)); | |
211 } else { | |
212 int x = 0; | |
213 } | |
214 } | |
215 int x = 0; | |
216 } | |
217 | |
218 if (l._def == NodeSentinel) { | |
219 tty->print("multiple mapping from %d: ", i); | |
220 for (int j=0; j<l._defs->length(); j++) { | |
221 tty->print("%d ", l._defs->at(j)->_idx); | |
222 } | |
223 tty->print_cr(""); | |
224 } else { | |
225 tty->print_cr("mapping between %d and %d\n", i, l._def->_idx); | |
226 } | |
227 } | |
228 }*/ | |
229 } | |
230 | |
231 void IdealGraphPrinter::print_method(ciMethod *method, int bci, InlineTree *tree) { | |
232 | |
233 Properties properties; | |
234 stringStream str; | |
235 method->print_name(&str); | |
236 | |
237 stringStream shortStr; | |
238 method->print_short_name(&shortStr); | |
239 | |
240 | |
241 properties.add(new Property(METHOD_NAME_PROPERTY, str.as_string())); | |
242 properties.add(new Property(METHOD_SHORT_NAME_PROPERTY, shortStr.as_string())); | |
243 properties.add(new Property(METHOD_BCI_PROPERTY, bci)); | |
244 start_element(METHOD_ELEMENT, &properties); | |
245 | |
246 start_element(BYTECODES_ELEMENT); | |
247 output()->print_cr("<![CDATA["); | |
248 method->print_codes_on(output()); | |
249 output()->print_cr("]]>"); | |
250 end_element(BYTECODES_ELEMENT); | |
251 | |
252 start_element(INLINE_ELEMENT); | |
253 if (tree != NULL) { | |
254 GrowableArray<InlineTree *> subtrees = tree->subtrees(); | |
255 for (int i = 0; i < subtrees.length(); i++) { | |
256 print_inline_tree(subtrees.at(i)); | |
257 } | |
258 } | |
259 end_element(INLINE_ELEMENT); | |
260 | |
261 end_element(METHOD_ELEMENT); | |
262 output()->flush(); | |
263 } | |
264 | |
265 void IdealGraphPrinter::print_inline_tree(InlineTree *tree) { | |
266 | |
267 if (tree == NULL) return; | |
268 | |
269 ciMethod *method = tree->method(); | |
270 print_method(tree->method(), tree->caller_bci(), tree); | |
271 | |
272 } | |
273 | |
274 void IdealGraphPrinter::clear_nodes() { | |
275 // for (int i = 0; i < _nodes.length(); i++) { | |
276 // _nodes.at(i)->clear_node(); | |
277 // } | |
278 } | |
279 | |
280 void IdealGraphPrinter::print_inlining(Compile* compile) { | |
281 | |
282 // Print inline tree | |
283 if (_should_send_method) { | |
284 InlineTree *inlineTree = compile->ilt(); | |
285 if (inlineTree != NULL) { | |
286 print_inline_tree(inlineTree); | |
287 } else { | |
288 // print this method only | |
289 } | |
290 } | |
291 } | |
292 | |
293 // Has to be called whenever a method is compiled | |
294 void IdealGraphPrinter::begin_method(Compile* compile) { | |
295 | |
296 ciMethod *method = compile->method(); | |
297 assert(_output, "output stream must exist!"); | |
298 assert(method, "null methods are not allowed!"); | |
299 assert(!_current_method, "current method must be null!"); | |
300 | |
301 _arena->destruct_contents(); | |
302 | |
303 start_element(GROUP_ELEMENT); | |
304 | |
305 // Print properties | |
306 Properties properties; | |
307 | |
308 // Add method name | |
309 stringStream strStream; | |
310 method->print_name(&strStream); | |
311 properties.add(new Property(METHOD_NAME_PROPERTY, strStream.as_string())); | |
312 | |
313 if (method->flags().is_public()) { | |
314 properties.add(new Property(METHOD_IS_PUBLIC_PROPERTY, TRUE_VALUE)); | |
315 } | |
316 | |
317 if (method->flags().is_static()) { | |
318 properties.add(new Property(METHOD_IS_STATIC_PROPERTY, TRUE_VALUE)); | |
319 } | |
320 | |
321 properties.print(this); | |
322 | |
323 if (_stream) { | |
324 char answer = 0; | |
325 _stream->flush(); | |
326 int result = _stream->read(&answer, 1); | |
327 _should_send_method = (answer == 'y'); | |
328 } | |
329 | |
330 this->_nodes = GrowableArray<NodeDescription *>(_arena, 2, 0, NULL); | |
331 this->_edges = GrowableArray< EdgeDescription * >(_arena, 2, 0, NULL); | |
332 | |
333 | |
334 this->_current_method = method; | |
335 | |
336 | |
337 | |
338 _output->flush(); | |
339 } | |
340 | |
341 // Has to be called whenever a method has finished compilation | |
342 void IdealGraphPrinter::end_method() { | |
343 | |
344 // if (finish && !in_method) return; | |
345 | |
346 nmethod* method = (nmethod*)this->_current_method->code(); | |
347 | |
348 start_element(ASSEMBLY_ELEMENT); | |
349 // Disassembler::decode(method, _output); | |
350 end_element(ASSEMBLY_ELEMENT); | |
351 | |
352 | |
353 end_element(GROUP_ELEMENT); | |
354 _current_method = NULL; | |
355 _output->flush(); | |
356 for (int i = 0; i < _nodes.length(); i++) { | |
357 NodeDescription *desc = _nodes.at(i); | |
358 if (desc) { | |
359 delete desc; | |
360 _nodes.at_put(i, NULL); | |
361 } | |
362 } | |
363 this->_nodes.clear(); | |
364 | |
365 | |
366 for (int i = 0; i < _edges.length(); i++) { | |
367 // for (int j=0; j<_edges.at(i)->length(); j++) { | |
368 EdgeDescription *conn = _edges.at(i); | |
369 conn->print(this); | |
370 if (conn) { | |
371 delete conn; | |
372 _edges.at_put(i, NULL); | |
373 } | |
374 //} | |
375 //_edges.at(i)->clear(); | |
376 //delete _edges.at(i); | |
377 //_edges.at_put(i, NULL); | |
378 } | |
379 this->_edges.clear(); | |
380 | |
381 // in_method = false; | |
382 } | |
383 | |
384 // Outputs an XML start element | |
385 void IdealGraphPrinter::start_element(const char *s, Properties *properties /* = NULL */, bool print_indent /* = false */, bool print_return /* = true */) { | |
386 | |
387 start_element_helper(s, properties, false, print_indent, print_return); | |
388 _depth++; | |
389 | |
390 } | |
391 | |
392 // Outputs an XML start element without body | |
393 void IdealGraphPrinter::simple_element(const char *s, Properties *properties /* = NULL */, bool print_indent /* = false */) { | |
394 start_element_helper(s, properties, true, print_indent, true); | |
395 } | |
396 | |
397 // Outputs an XML start element. If outputEnd is true, the element has no body. | |
398 void IdealGraphPrinter::start_element_helper(const char *s, Properties *properties, bool outputEnd, bool print_indent /* = false */, bool print_return /* = true */) { | |
399 | |
400 assert(_output, "output stream must exist!"); | |
401 | |
402 if (print_indent) this->print_indent(); | |
403 _output->print("<"); | |
404 _output->print(s); | |
405 if (properties) properties->print_as_attributes(this); | |
406 | |
407 if (outputEnd) { | |
408 _output->print("/"); | |
409 } | |
410 | |
411 _output->print(">"); | |
412 if (print_return) _output->print_cr(""); | |
413 | |
414 } | |
415 | |
416 // Print indent | |
417 void IdealGraphPrinter::print_indent() { | |
418 for (int i = 0; i < _depth; i++) { | |
419 _output->print(INDENT); | |
420 } | |
421 } | |
422 | |
423 // Outputs an XML end element | |
424 void IdealGraphPrinter::end_element(const char *s, bool print_indent /* = true */, bool print_return /* = true */) { | |
425 | |
426 assert(_output, "output stream must exist!"); | |
427 | |
428 _depth--; | |
429 | |
430 if (print_indent) this->print_indent(); | |
431 _output->print("</"); | |
432 _output->print(s); | |
433 _output->print(">"); | |
434 if (print_return) _output->print_cr(""); | |
435 | |
436 } | |
437 | |
438 bool IdealGraphPrinter::traverse_outs() { | |
439 return _traverse_outs; | |
440 } | |
441 | |
442 void IdealGraphPrinter::set_traverse_outs(bool b) { | |
443 _traverse_outs = b; | |
444 } | |
445 | |
446 void IdealGraphPrinter::walk(Node *start) { | |
447 | |
448 | |
449 VectorSet visited(Thread::current()->resource_area()); | |
450 GrowableArray<Node *> nodeStack(Thread::current()->resource_area(), 0, 0, NULL); | |
451 nodeStack.push(start); | |
452 visited.test_set(start->_idx); | |
453 while(nodeStack.length() > 0) { | |
454 | |
455 Node *n = nodeStack.pop(); | |
456 IdealGraphPrinter::pre_node(n, this); | |
457 | |
458 if (_traverse_outs) { | |
459 for (DUIterator i = n->outs(); n->has_out(i); i++) { | |
460 Node* p = n->out(i); | |
461 if (!visited.test_set(p->_idx)) { | |
462 nodeStack.push(p); | |
463 } | |
464 } | |
465 } | |
466 | |
467 for ( uint i = 0; i < n->len(); i++ ) { | |
468 if ( n->in(i) ) { | |
469 if (!visited.test_set(n->in(i)->_idx)) { | |
470 nodeStack.push(n->in(i)); | |
471 } | |
472 } | |
473 } | |
474 } | |
475 } | |
476 | |
477 void IdealGraphPrinter::compress(int index, GrowableArray<Block>* blocks) { | |
478 Block *block = blocks->adr_at(index); | |
479 | |
480 int ancestor = block->ancestor(); | |
481 assert(ancestor != -1, ""); | |
482 | |
483 Block *ancestor_block = blocks->adr_at(ancestor); | |
484 if (ancestor_block->ancestor() != -1) { | |
485 compress(ancestor, blocks); | |
486 | |
487 int label = block->label(); | |
488 Block *label_block = blocks->adr_at(label); | |
489 | |
490 int ancestor_label = ancestor_block->label(); | |
491 Block *ancestor_label_block = blocks->adr_at(label); | |
492 if (ancestor_label_block->semi() < label_block->semi()) { | |
493 block->set_label(ancestor_label); | |
494 } | |
495 | |
496 block->set_ancestor(ancestor_block->ancestor()); | |
497 } | |
498 } | |
499 | |
500 int IdealGraphPrinter::eval(int index, GrowableArray<Block>* blocks) { | |
501 Block *block = blocks->adr_at(index); | |
502 if (block->ancestor() == -1) { | |
503 return index; | |
504 } else { | |
505 compress(index, blocks); | |
506 return block->label(); | |
507 } | |
508 } | |
509 | |
510 void IdealGraphPrinter::link(int index1, int index2, GrowableArray<Block>* blocks) { | |
511 Block *block2 = blocks->adr_at(index2); | |
512 block2->set_ancestor(index1); | |
513 } | |
514 | |
515 void IdealGraphPrinter::build_dominators(GrowableArray<Block>* blocks) { | |
516 | |
517 if (blocks->length() == 0) return; | |
518 | |
519 GrowableArray<int> stack; | |
520 stack.append(0); | |
521 | |
522 GrowableArray<Block *> array; | |
523 | |
524 assert(blocks->length() > 0, ""); | |
525 blocks->adr_at(0)->set_dominator(0); | |
526 | |
527 int n = 0; | |
528 while(!stack.is_empty()) { | |
529 int index = stack.pop(); | |
530 Block *block = blocks->adr_at(index); | |
531 block->set_semi(n); | |
532 array.append(block); | |
533 n = n + 1; | |
534 for (int i = 0; i < block->succs()->length(); i++) { | |
535 int succ_index = block->succs()->at(i); | |
536 Block *succ = blocks->adr_at(succ_index); | |
537 if (succ->semi() == -1) { | |
538 succ->set_parent(index); | |
539 stack.push(succ_index); | |
540 } | |
541 succ->add_pred(index); | |
542 } | |
543 } | |
544 | |
545 for (int i=n-1; i>0; i--) { | |
546 Block *block = array.at(i); | |
547 int block_index = block->index(); | |
548 for (int j=0; j<block->pred()->length(); j++) { | |
549 int pred_index = block->pred()->at(j); | |
550 int cur_index = eval(pred_index, blocks); | |
551 | |
552 Block *cur_block = blocks->adr_at(cur_index); | |
553 if (cur_block->semi() < block->semi()) { | |
554 block->set_semi(cur_block->semi()); | |
555 } | |
556 } | |
557 | |
558 int semi_index = block->semi(); | |
559 Block *semi_block = array.at(semi_index); | |
560 semi_block->add_to_bucket(block_index); | |
561 | |
562 link(block->parent(), block_index, blocks); | |
563 Block *parent_block = blocks->adr_at(block->parent()); | |
564 | |
565 for (int j=0; j<parent_block->bucket()->length(); j++) { | |
566 int cur_index = parent_block->bucket()->at(j); | |
567 int new_index = eval(cur_index, blocks); | |
568 Block *cur_block = blocks->adr_at(cur_index); | |
569 Block *new_block = blocks->adr_at(new_index); | |
570 int dom = block->parent(); | |
571 | |
572 if (new_block->semi() < cur_block->semi()) { | |
573 dom = new_index; | |
574 } | |
575 | |
576 cur_block->set_dominator(dom); | |
577 } | |
578 | |
579 parent_block->clear_bucket(); | |
580 } | |
581 | |
582 for (int i=1; i < n; i++) { | |
583 | |
584 Block *block = array.at(i); | |
585 int block_index = block->index(); | |
586 | |
587 int semi_index = block->semi(); | |
588 Block *semi_block = array.at(semi_index); | |
589 | |
590 if (block->dominator() != semi_block->index()) { | |
591 int new_dom = blocks->adr_at(block->dominator())->dominator(); | |
592 block->set_dominator(new_dom); | |
593 } | |
594 } | |
595 | |
596 for (int i = 0; i < blocks->length(); i++) { | |
597 if (blocks->adr_at(i)->dominator() == -1) { | |
598 blocks->adr_at(i)->set_dominator(0); | |
599 } | |
600 } | |
601 | |
602 // Build dominates array | |
603 for (int i=1; i < blocks->length(); i++) { | |
604 Block *block = blocks->adr_at(i); | |
605 int dominator = block->dominator(); | |
606 Block *dom_block = blocks->adr_at(dominator); | |
607 dom_block->add_dominates(i); | |
608 dom_block->add_child(i); | |
609 | |
610 while(dominator != 0) { | |
611 dominator = dom_block->dominator(); | |
612 dom_block = blocks->adr_at(dominator); | |
613 dom_block->add_child(i); | |
614 } | |
615 } | |
616 } | |
617 | |
618 void IdealGraphPrinter::build_common_dominator(int **common_dominator, int index, GrowableArray<Block>* blocks) { | |
619 | |
620 common_dominator[index][index] = index; | |
621 Block *block = blocks->adr_at(index); | |
622 for (int i = 0; i < block->dominates()->length(); i++) { | |
623 Block *dominated = blocks->adr_at(block->dominates()->at(i)); | |
624 | |
625 for (int j=0; j<dominated->children()->length(); j++) { | |
626 Block *child = blocks->adr_at(dominated->children()->at(j)); | |
627 common_dominator[index][child->index()] = common_dominator[child->index()][index] = index; | |
628 | |
629 for (int k=0; k<i; k++) { | |
630 Block *other_dominated = blocks->adr_at(block->dominates()->at(k)); | |
631 common_dominator[child->index()][other_dominated->index()] = common_dominator[other_dominated->index()][child->index()] = index; | |
632 | |
633 for (int l=0 ; l<other_dominated->children()->length(); l++) { | |
634 Block *other_child = blocks->adr_at(other_dominated->children()->at(l)); | |
635 common_dominator[child->index()][other_child->index()] = common_dominator[other_child->index()][child->index()] = index; | |
636 } | |
637 } | |
638 } | |
639 | |
640 build_common_dominator(common_dominator, dominated->index(), blocks); | |
641 } | |
642 } | |
643 | |
644 void IdealGraphPrinter::schedule_latest(int **common_dominator, GrowableArray<Block>* blocks) { | |
645 | |
646 int queue_size = _nodes.length() + 1; | |
647 NodeDescription **queue = NEW_RESOURCE_ARRAY(NodeDescription *, queue_size); | |
648 int queue_start = 0; | |
649 int queue_end = 0; | |
650 Arena *a = new Arena(); | |
651 VectorSet on_queue(a); | |
652 | |
653 for (int i = 0; i < _nodes.length(); i++) { | |
654 NodeDescription *desc = _nodes.at(i); | |
655 if (desc) { | |
656 desc->init_succs(); | |
657 } | |
658 } | |
659 | |
660 for (int i = 0; i < _nodes.length(); i++) { | |
661 NodeDescription *desc = _nodes.at(i); | |
662 if (desc) { | |
663 for (uint j=0; j<desc->node()->len(); j++) { | |
664 Node *n = desc->node()->in(j); | |
665 if (n) { | |
666 NodeDescription *other_desc = _nodes.at(n->_idx); | |
667 other_desc->add_succ(desc); | |
668 } | |
669 } | |
670 } | |
671 } | |
672 | |
673 for (int i = 0; i < _nodes.length(); i++) { | |
674 NodeDescription *desc = _nodes.at(i); | |
675 if (desc && desc->block_index() == -1) { | |
676 | |
677 // Put Phi into same block as region | |
678 if (desc->node()->is_Phi() && desc->node()->in(0) && _nodes.at(desc->node()->in(0)->_idx)->block_index() != -1) { | |
679 int index = _nodes.at(desc->node()->in(0)->_idx)->block_index(); | |
680 desc->set_block_index(index); | |
681 blocks->adr_at(index)->add_node(desc); | |
682 | |
683 // Put Projections to same block as parent | |
684 } else if (desc->node()->is_block_proj() && _nodes.at(desc->node()->is_block_proj()->_idx)->block_index() != -1) { | |
685 int index = _nodes.at(desc->node()->is_block_proj()->_idx)->block_index(); | |
686 desc->set_block_index(index); | |
687 blocks->adr_at(index)->add_node(desc); | |
688 } else { | |
689 queue[queue_end] = desc; | |
690 queue_end++; | |
691 on_queue.set(desc->node()->_idx); | |
692 } | |
693 } | |
694 } | |
695 | |
696 | |
697 int z = 0; | |
698 while(queue_start != queue_end && z < 10000) { | |
699 | |
700 NodeDescription *desc = queue[queue_start]; | |
701 queue_start = (queue_start + 1) % queue_size; | |
702 on_queue >>= desc->node()->_idx; | |
703 | |
704 Node* node = desc->node(); | |
705 | |
706 if (desc->succs()->length() == 0) { | |
707 int x = 0; | |
708 } | |
709 | |
710 int block_index = -1; | |
711 if (desc->succs()->length() != 0) { | |
712 for (int i = 0; i < desc->succs()->length(); i++) { | |
713 NodeDescription *cur_desc = desc->succs()->at(i); | |
714 if (cur_desc != desc) { | |
715 if (cur_desc->succs()->length() == 0) { | |
716 | |
717 // Ignore nodes with 0 successors | |
718 | |
719 } else if (cur_desc->block_index() == -1) { | |
720 | |
721 // Let this node schedule first | |
722 block_index = -1; | |
723 break; | |
724 | |
725 } else if (cur_desc->node()->is_Phi()){ | |
726 | |
727 // Special treatment for Phi functions | |
728 PhiNode *phi = cur_desc->node()->as_Phi(); | |
729 assert(phi->in(0) && phi->in(0)->is_Region(), "Must have region node in first input"); | |
730 RegionNode *region = phi->in(0)->as_Region(); | |
731 | |
732 for (uint j=1; j<phi->len(); j++) { | |
733 Node *cur_phi_input = phi->in(j); | |
734 if (cur_phi_input == desc->node() && region->in(j)) { | |
735 NodeDescription *cur_region_input = _nodes.at(region->in(j)->_idx); | |
736 if (cur_region_input->block_index() == -1) { | |
737 | |
738 // Let this node schedule first | |
739 block_index = -1; | |
740 break; | |
741 } else { | |
742 if (block_index == -1) { | |
743 block_index = cur_region_input->block_index(); | |
744 } else { | |
745 block_index = common_dominator[block_index][cur_region_input->block_index()]; | |
746 } | |
747 } | |
748 } | |
749 } | |
750 | |
751 } else { | |
752 if (block_index == -1) { | |
753 block_index = cur_desc->block_index(); | |
754 } else { | |
755 block_index = common_dominator[block_index][cur_desc->block_index()]; | |
756 } | |
757 } | |
758 } | |
759 } | |
760 } | |
761 | |
762 if (block_index == -1) { | |
763 queue[queue_end] = desc; | |
764 queue_end = (queue_end + 1) % queue_size; | |
765 on_queue.set(desc->node()->_idx); | |
766 z++; | |
767 } else { | |
768 assert(desc->block_index() == -1, ""); | |
769 desc->set_block_index(block_index); | |
770 blocks->adr_at(block_index)->add_node(desc); | |
771 z = 0; | |
772 } | |
773 } | |
774 | |
775 for (int i = 0; i < _nodes.length(); i++) { | |
776 NodeDescription *desc = _nodes.at(i); | |
777 if (desc && desc->block_index() == -1) { | |
778 | |
779 //if (desc->node()->is_Proj() || desc->node()->is_Con()) { | |
780 Node *parent = desc->node()->in(0); | |
781 uint cur = 1; | |
782 while(!parent && cur < desc->node()->len()) { | |
783 parent = desc->node()->in(cur); | |
784 cur++; | |
785 } | |
786 | |
787 if (parent && _nodes.at(parent->_idx)->block_index() != -1) { | |
788 int index = _nodes.at(parent->_idx)->block_index(); | |
789 desc->set_block_index(index); | |
790 blocks->adr_at(index)->add_node(desc); | |
791 } else { | |
792 desc->set_block_index(0); | |
793 blocks->adr_at(0)->add_node(desc); | |
794 //ShouldNotReachHere(); | |
795 } | |
796 //} | |
797 /* | |
798 if (desc->node()->is_block_proj() && _nodes.at(desc->node()->is_block_proj()->_idx)->block_index() != -1) { | |
799 int index = _nodes.at(desc->node()->is_block_proj()->_idx)->block_index(); | |
800 desc->set_block_index(index); | |
801 blocks->adr_at(index)->add_node(desc); | |
802 } */ | |
803 } | |
804 } | |
805 | |
806 for (int i = 0; i < _nodes.length(); i++) { | |
807 NodeDescription *desc = _nodes.at(i); | |
808 if (desc) { | |
809 desc->clear_succs(); | |
810 } | |
811 } | |
812 | |
813 for (int i = 0; i < _nodes.length(); i++) { | |
814 NodeDescription *desc = _nodes.at(i); | |
815 if (desc) { | |
816 int block_index = desc->block_index(); | |
817 | |
818 assert(block_index >= 0 && block_index < blocks->length(), "Block index must be in range"); | |
819 assert(blocks->adr_at(block_index)->nodes()->contains(desc), "Node must be child of block"); | |
820 } | |
821 } | |
822 a->destruct_contents(); | |
823 } | |
824 | |
825 void IdealGraphPrinter::build_blocks(Node *root) { | |
826 | |
827 Arena *a = new Arena(); | |
828 Node_Stack stack(a, 100); | |
829 | |
830 VectorSet visited(a); | |
831 stack.push(root, 0); | |
832 GrowableArray<Block> blocks(a, 2, 0, Block(0)); | |
833 | |
834 for (int i = 0; i < _nodes.length(); i++) { | |
835 if (_nodes.at(i)) _nodes.at(i)->set_block_index(-1); | |
836 } | |
837 | |
838 | |
839 // Order nodes such that node index is equal to idx | |
840 for (int i = 0; i < _nodes.length(); i++) { | |
841 | |
842 if (_nodes.at(i)) { | |
843 NodeDescription *node = _nodes.at(i); | |
844 int index = node->node()->_idx; | |
845 if (index != i) { | |
846 _nodes.at_grow(index); | |
847 NodeDescription *tmp = _nodes.at(index); | |
848 *(_nodes.adr_at(index)) = node; | |
849 *(_nodes.adr_at(i)) = tmp; | |
850 i--; | |
851 } | |
852 } | |
853 } | |
854 | |
855 for (int i = 0; i < _nodes.length(); i++) { | |
856 NodeDescription *node = _nodes.at(i); | |
857 if (node) { | |
858 assert(node->node()->_idx == (uint)i, ""); | |
859 } | |
860 } | |
861 | |
862 while(stack.is_nonempty()) { | |
863 | |
864 //Node *n = stack.node(); | |
865 //int index = stack.index(); | |
866 Node *proj = stack.node();//n->in(index); | |
867 const Node *parent = proj->is_block_proj(); | |
868 if (parent == NULL) { | |
869 parent = proj; | |
870 } | |
871 | |
872 if (!visited.test_set(parent->_idx)) { | |
873 | |
874 NodeDescription *end_desc = _nodes.at(parent->_idx); | |
875 int block_index = blocks.length(); | |
876 Block block(block_index); | |
877 blocks.append(block); | |
878 Block *b = blocks.adr_at(block_index); | |
879 b->set_start(end_desc); | |
880 // assert(end_desc->block_index() == -1, ""); | |
881 end_desc->set_block_index(block_index); | |
882 b->add_node(end_desc); | |
883 | |
884 // Skip any control-pinned middle'in stuff | |
885 Node *p = proj; | |
886 NodeDescription *start_desc = NULL; | |
887 do { | |
888 proj = p; // Update pointer to last Control | |
889 if (p->in(0) == NULL) { | |
890 start_desc = end_desc; | |
891 break; | |
892 } | |
893 p = p->in(0); // Move control forward | |
894 start_desc = _nodes.at(p->_idx); | |
895 assert(start_desc, ""); | |
896 | |
897 if (start_desc != end_desc && start_desc->block_index() == -1) { | |
898 assert(start_desc->block_index() == -1, ""); | |
899 assert(block_index < blocks.length(), ""); | |
900 start_desc->set_block_index(block_index); | |
901 b->add_node(start_desc); | |
902 } | |
903 } while( !p->is_block_proj() && | |
904 !p->is_block_start() ); | |
905 | |
906 for (uint i = 0; i < start_desc->node()->len(); i++) { | |
907 | |
908 Node *pred_node = start_desc->node()->in(i); | |
909 | |
910 | |
911 if (pred_node && pred_node != start_desc->node()) { | |
912 const Node *cur_parent = pred_node->is_block_proj(); | |
913 if (cur_parent != NULL) { | |
914 pred_node = (Node *)cur_parent; | |
915 } | |
916 | |
917 NodeDescription *pred_node_desc = _nodes.at(pred_node->_idx); | |
918 if (pred_node_desc->block_index() != -1) { | |
919 blocks.adr_at(pred_node_desc->block_index())->add_succ(block_index); | |
920 } | |
921 } | |
922 } | |
923 | |
924 for (DUIterator_Fast dmax, i = end_desc->node()->fast_outs(dmax); i < dmax; i++) { | |
925 Node* cur_succ = end_desc->node()->fast_out(i); | |
926 NodeDescription *cur_succ_desc = _nodes.at(cur_succ->_idx); | |
927 | |
928 DUIterator_Fast dmax2, i2 = cur_succ->fast_outs(dmax2); | |
929 if (cur_succ->is_block_proj() && i2 < dmax2 && !cur_succ->is_Root()) { | |
930 | |
931 for (; i2<dmax2; i2++) { | |
932 Node *cur_succ2 = cur_succ->fast_out(i2); | |
933 if (cur_succ2) { | |
934 cur_succ_desc = _nodes.at(cur_succ2->_idx); | |
935 if (cur_succ_desc == NULL) { | |
936 // dead node so skip it | |
937 continue; | |
938 } | |
939 if (cur_succ2 != end_desc->node() && cur_succ_desc->block_index() != -1) { | |
940 b->add_succ(cur_succ_desc->block_index()); | |
941 } | |
942 } | |
943 } | |
944 | |
945 } else { | |
946 | |
947 if (cur_succ != end_desc->node() && cur_succ_desc && cur_succ_desc->block_index() != -1) { | |
948 b->add_succ(cur_succ_desc->block_index()); | |
949 } | |
950 } | |
951 } | |
952 | |
953 | |
954 int num_preds = p->len(); | |
955 int bottom = -1; | |
956 if (p->is_Region() || p->is_Phi()) { | |
957 bottom = 0; | |
958 } | |
959 | |
960 int pushed = 0; | |
961 for (int i=num_preds - 1; i > bottom; i--) { | |
962 if (p->in(i) != NULL && p->in(i) != p) { | |
963 stack.push(p->in(i), 0); | |
964 pushed++; | |
965 } | |
966 } | |
967 | |
968 if (pushed == 0 && p->is_Root() && !_matcher) { | |
969 // Special case when backedges to root are not yet built | |
970 for (int i = 0; i < _nodes.length(); i++) { | |
971 if (_nodes.at(i) && _nodes.at(i)->node()->is_SafePoint() && _nodes.at(i)->node()->outcnt() == 0) { | |
972 stack.push(_nodes.at(i)->node(), 0); | |
973 } | |
974 } | |
975 } | |
976 | |
977 } else { | |
978 stack.pop(); | |
979 } | |
980 } | |
981 | |
982 build_dominators(&blocks); | |
983 | |
984 int **common_dominator = NEW_RESOURCE_ARRAY(int *, blocks.length()); | |
985 for (int i = 0; i < blocks.length(); i++) { | |
986 int *cur = NEW_RESOURCE_ARRAY(int, blocks.length()); | |
987 common_dominator[i] = cur; | |
988 | |
989 for (int j=0; j<blocks.length(); j++) { | |
990 cur[j] = 0; | |
991 } | |
992 } | |
993 | |
994 for (int i = 0; i < blocks.length(); i++) { | |
995 blocks.adr_at(i)->add_child(blocks.adr_at(i)->index()); | |
996 } | |
997 build_common_dominator(common_dominator, 0, &blocks); | |
998 | |
999 schedule_latest(common_dominator, &blocks); | |
1000 | |
1001 start_element(CONTROL_FLOW_ELEMENT); | |
1002 | |
1003 for (int i = 0; i < blocks.length(); i++) { | |
1004 Block *block = blocks.adr_at(i); | |
1005 | |
1006 Properties props; | |
1007 props.add(new Property(BLOCK_NAME_PROPERTY, i)); | |
1008 props.add(new Property(BLOCK_DOMINATOR_PROPERTY, block->dominator())); | |
1009 start_element(BLOCK_ELEMENT, &props); | |
1010 | |
1011 if (block->succs()->length() > 0) { | |
1012 start_element(SUCCESSORS_ELEMENT); | |
1013 for (int j=0; j<block->succs()->length(); j++) { | |
1014 int cur_index = block->succs()->at(j); | |
1015 if (cur_index != 0 /* start_block has must not have inputs */) { | |
1016 Properties properties; | |
1017 properties.add(new Property(BLOCK_NAME_PROPERTY, cur_index)); | |
1018 simple_element(SUCCESSOR_ELEMENT, &properties); | |
1019 } | |
1020 } | |
1021 end_element(SUCCESSORS_ELEMENT); | |
1022 } | |
1023 | |
1024 start_element(NODES_ELEMENT); | |
1025 | |
1026 for (int j=0; j<block->nodes()->length(); j++) { | |
1027 NodeDescription *n = block->nodes()->at(j); | |
1028 Properties properties; | |
1029 properties.add(new Property(NODE_ID_PROPERTY, n->id())); | |
1030 simple_element(NODE_ELEMENT, &properties); | |
1031 } | |
1032 | |
1033 end_element(NODES_ELEMENT); | |
1034 | |
1035 end_element(BLOCK_ELEMENT); | |
1036 } | |
1037 | |
1038 | |
1039 end_element(CONTROL_FLOW_ELEMENT); | |
1040 | |
1041 a->destruct_contents(); | |
1042 } | |
1043 | |
1044 void IdealGraphPrinter::print_method(Compile* compile, const char *name, int level, bool clear_nodes) { | |
1045 print(compile, name, (Node *)compile->root(), level, clear_nodes); | |
1046 } | |
1047 | |
1048 // Print current ideal graph | |
1049 void IdealGraphPrinter::print(Compile* compile, const char *name, Node *node, int level, bool clear_nodes) { | |
1050 | |
1051 // if (finish && !in_method) return; | |
1052 if (!_current_method || !_should_send_method || level > PrintIdealGraphLevel) return; | |
1053 | |
1054 assert(_current_method, "newMethod has to be called first!"); | |
1055 | |
1056 if (clear_nodes) { | |
1057 int x = 0; | |
1058 } | |
1059 | |
1060 _clear_nodes = clear_nodes; | |
1061 | |
1062 // Warning, unsafe cast? | |
1063 _chaitin = (PhaseChaitin *)compile->regalloc(); | |
1064 _matcher = compile->matcher(); | |
1065 | |
1066 | |
1067 // Update nodes | |
1068 for (int i = 0; i < _nodes.length(); i++) { | |
1069 NodeDescription *desc = _nodes.at(i); | |
1070 if (desc) { | |
1071 desc->set_state(Invalid); | |
1072 } | |
1073 } | |
1074 Node *n = node; | |
1075 walk(n); | |
1076 | |
1077 // Update edges | |
1078 for (int i = 0; i < _edges.length(); i++) { | |
1079 _edges.at(i)->set_state(Invalid); | |
1080 } | |
1081 | |
1082 for (int i = 0; i < _nodes.length(); i++) { | |
1083 NodeDescription *desc = _nodes.at(i); | |
1084 if (desc && desc->state() != Invalid) { | |
1085 | |
1086 int to = desc->id(); | |
1087 uint len = desc->node()->len(); | |
1088 for (uint j=0; j<len; j++) { | |
1089 Node *n = desc->node()->in(j); | |
1090 | |
1091 if (n) { | |
1092 | |
1093 | |
1094 intptr_t from = (intptr_t)n; | |
1095 | |
1096 // Assert from node is valid | |
1097 /* | |
1098 bool ok = false; | |
1099 for (int k=0; k<_nodes.length(); k++) { | |
1100 NodeDescription *desc = _nodes.at(k); | |
1101 if (desc && desc->id() == from) { | |
1102 assert(desc->state() != Invalid, ""); | |
1103 ok = true; | |
1104 } | |
1105 } | |
1106 assert(ok, "");*/ | |
1107 | |
1108 uint index = j; | |
1109 if (index >= desc->node()->req()) { | |
1110 index = desc->node()->req(); | |
1111 } | |
1112 | |
1113 print_edge(from, to, index); | |
1114 } | |
1115 } | |
1116 } | |
1117 } | |
1118 | |
1119 bool is_different = false; | |
1120 | |
1121 for (int i = 0; i < _nodes.length(); i++) { | |
1122 NodeDescription *desc = _nodes.at(i); | |
1123 if (desc && desc->state() != Valid) { | |
1124 is_different = true; | |
1125 break; | |
1126 } | |
1127 } | |
1128 | |
1129 if (!is_different) { | |
1130 for (int i = 0; i < _edges.length(); i++) { | |
1131 EdgeDescription *conn = _edges.at(i); | |
1132 if (conn && conn->state() != Valid) { | |
1133 is_different = true; | |
1134 break; | |
1135 } | |
1136 } | |
1137 } | |
1138 | |
1139 // No changes -> do not print graph | |
1140 if (!is_different) return; | |
1141 | |
1142 Properties properties; | |
1143 properties.add(new Property(GRAPH_NAME_PROPERTY, (const char *)name)); | |
1144 start_element(GRAPH_ELEMENT, &properties); | |
1145 | |
1146 start_element(NODES_ELEMENT); | |
1147 for (int i = 0; i < _nodes.length(); i++) { | |
1148 NodeDescription *desc = _nodes.at(i); | |
1149 if (desc) { | |
1150 desc->print(this); | |
1151 if (desc->state() == Invalid) { | |
1152 delete desc; | |
1153 _nodes.at_put(i, NULL); | |
1154 } else { | |
1155 desc->set_state(Valid); | |
1156 } | |
1157 } | |
1158 } | |
1159 end_element(NODES_ELEMENT); | |
1160 | |
1161 build_blocks(node); | |
1162 | |
1163 start_element(EDGES_ELEMENT); | |
1164 for (int i = 0; i < _edges.length(); i++) { | |
1165 EdgeDescription *conn = _edges.at(i); | |
1166 | |
1167 // Assert from and to nodes are valid | |
1168 /* | |
1169 if (!conn->state() == Invalid) { | |
1170 bool ok1 = false; | |
1171 bool ok2 = false; | |
1172 for (int j=0; j<_nodes.length(); j++) { | |
1173 NodeDescription *desc = _nodes.at(j); | |
1174 if (desc && desc->id() == conn->from()) { | |
1175 ok1 = true; | |
1176 } | |
1177 | |
1178 if (desc && desc->id() == conn->to()) { | |
1179 ok2 = true; | |
1180 } | |
1181 } | |
1182 | |
1183 assert(ok1, "from node not found!"); | |
1184 assert(ok2, "to node not found!"); | |
1185 }*/ | |
1186 | |
1187 conn->print(this); | |
1188 if (conn->state() == Invalid) { | |
1189 _edges.remove_at(i); | |
1190 delete conn; | |
1191 i--; | |
1192 } | |
1193 } | |
1194 | |
1195 end_element(EDGES_ELEMENT); | |
1196 | |
1197 end_element(GRAPH_ELEMENT); | |
1198 | |
1199 _output->flush(); | |
1200 } | |
1201 | |
1202 // Print edge | |
1203 void IdealGraphPrinter::print_edge(int from, int to, int index) { | |
1204 | |
1205 EdgeDescription *conn = new EdgeDescription(from, to, index); | |
1206 for (int i = 0; i < _edges.length(); i++) { | |
1207 if (_edges.at(i)->equals(conn)) { | |
1208 conn->set_state(Valid); | |
1209 delete _edges.at(i); | |
1210 _edges.at_put(i, conn); | |
1211 return; | |
1212 } | |
1213 } | |
1214 | |
1215 _edges.append(conn); | |
1216 } | |
1217 | |
1218 extern const char *NodeClassNames[]; | |
1219 | |
1220 // Create node description | |
1221 IdealGraphPrinter::NodeDescription *IdealGraphPrinter::create_node_description(Node* node) { | |
1222 | |
1223 #ifndef PRODUCT | |
1224 node->_in_dump_cnt++; | |
1225 NodeDescription *desc = new NodeDescription(node); | |
1226 desc->properties()->add(new Property(NODE_NAME_PROPERTY, (const char *)node->Name())); | |
1227 | |
1228 const Type *t = node->bottom_type(); | |
1229 desc->properties()->add(new Property("type", (const char *)Type::msg[t->base()])); | |
1230 | |
1231 desc->properties()->add(new Property("idx", node->_idx)); | |
1232 #ifdef ASSERT | |
1233 desc->properties()->add(new Property("debug_idx", node->_debug_idx)); | |
1234 #endif | |
1235 | |
1236 | |
1237 const jushort flags = node->flags(); | |
1238 if (flags & Node::Flag_is_Copy) { | |
1239 desc->properties()->add(new Property("is_copy", "true")); | |
1240 } | |
1241 if (flags & Node::Flag_is_Call) { | |
1242 desc->properties()->add(new Property("is_call", "true")); | |
1243 } | |
1244 if (flags & Node::Flag_rematerialize) { | |
1245 desc->properties()->add(new Property("rematerialize", "true")); | |
1246 } | |
1247 if (flags & Node::Flag_needs_anti_dependence_check) { | |
1248 desc->properties()->add(new Property("needs_anti_dependence_check", "true")); | |
1249 } | |
1250 if (flags & Node::Flag_is_macro) { | |
1251 desc->properties()->add(new Property("is_macro", "true")); | |
1252 } | |
1253 if (flags & Node::Flag_is_Con) { | |
1254 desc->properties()->add(new Property("is_con", "true")); | |
1255 } | |
1256 if (flags & Node::Flag_is_cisc_alternate) { | |
1257 desc->properties()->add(new Property("is_cisc_alternate", "true")); | |
1258 } | |
1259 if (flags & Node::Flag_is_Branch) { | |
1260 desc->properties()->add(new Property("is_branch", "true")); | |
1261 } | |
1262 if (flags & Node::Flag_is_block_start) { | |
1263 desc->properties()->add(new Property("is_block_start", "true")); | |
1264 } | |
1265 if (flags & Node::Flag_is_Goto) { | |
1266 desc->properties()->add(new Property("is_goto", "true")); | |
1267 } | |
1268 if (flags & Node::Flag_is_dead_loop_safe) { | |
1269 desc->properties()->add(new Property("is_dead_loop_safe", "true")); | |
1270 } | |
1271 if (flags & Node::Flag_may_be_short_branch) { | |
1272 desc->properties()->add(new Property("may_be_short_branch", "true")); | |
1273 } | |
1274 if (flags & Node::Flag_is_safepoint_node) { | |
1275 desc->properties()->add(new Property("is_safepoint_node", "true")); | |
1276 } | |
1277 if (flags & Node::Flag_is_pc_relative) { | |
1278 desc->properties()->add(new Property("is_pc_relative", "true")); | |
1279 } | |
1280 | |
1281 if (_matcher) { | |
1282 if (_matcher->is_shared(desc->node())) { | |
1283 desc->properties()->add(new Property("is_shared", "true")); | |
1284 } else { | |
1285 desc->properties()->add(new Property("is_shared", "false")); | |
1286 } | |
1287 | |
1288 if (_matcher->is_dontcare(desc->node())) { | |
1289 desc->properties()->add(new Property("is_dontcare", "true")); | |
1290 } else { | |
1291 desc->properties()->add(new Property("is_dontcare", "false")); | |
1292 } | |
1293 } | |
1294 | |
1295 if (node->is_Proj()) { | |
1296 desc->properties()->add(new Property("con", (int)node->as_Proj()->_con)); | |
1297 } | |
1298 | |
1299 if (node->is_Mach()) { | |
1300 desc->properties()->add(new Property("idealOpcode", (const char *)NodeClassNames[node->as_Mach()->ideal_Opcode()])); | |
1301 } | |
1302 | |
1303 | |
1304 | |
1305 | |
1306 | |
1307 outputStream *oldTty = tty; | |
1308 buffer[0] = 0; | |
1309 stringStream s2(buffer, sizeof(buffer) - 1); | |
1310 | |
1311 node->dump_spec(&s2); | |
1312 assert(s2.size() < sizeof(buffer), "size in range"); | |
1313 desc->properties()->add(new Property("dump_spec", buffer)); | |
1314 | |
1315 if (node->is_block_proj()) { | |
1316 desc->properties()->add(new Property("is_block_proj", "true")); | |
1317 } | |
1318 | |
1319 if (node->is_block_start()) { | |
1320 desc->properties()->add(new Property("is_block_start", "true")); | |
1321 } | |
1322 | |
1323 const char *short_name = "short_name"; | |
1324 if (strcmp(node->Name(), "Parm") == 0 && node->as_Proj()->_con >= TypeFunc::Parms) { | |
1325 int index = node->as_Proj()->_con - TypeFunc::Parms; | |
1326 if (index >= 10) { | |
1327 desc->properties()->add(new Property(short_name, "PA")); | |
1328 } else { | |
1329 sprintf(buffer, "P%d", index); | |
1330 desc->properties()->add(new Property(short_name, buffer)); | |
1331 } | |
1332 } else if (strcmp(node->Name(), "IfTrue") == 0) { | |
1333 desc->properties()->add(new Property(short_name, "T")); | |
1334 } else if (strcmp(node->Name(), "IfFalse") == 0) { | |
1335 desc->properties()->add(new Property(short_name, "F")); | |
1336 } else if ((node->is_Con() && node->is_Type()) || node->is_Proj()) { | |
1337 | |
1338 if (t->base() == Type::Int && t->is_int()->is_con()) { | |
1339 const TypeInt *typeInt = t->is_int(); | |
1340 assert(typeInt->is_con(), "must be constant"); | |
1341 jint value = typeInt->get_con(); | |
1342 | |
1343 // max. 2 chars allowed | |
1344 if (value >= -9 && value <= 99) { | |
1345 sprintf(buffer, "%d", value); | |
1346 desc->properties()->add(new Property(short_name, buffer)); | |
1347 } | |
1348 else | |
1349 { | |
1350 desc->properties()->add(new Property(short_name, "I")); | |
1351 } | |
1352 } else if (t == Type::TOP) { | |
1353 desc->properties()->add(new Property(short_name, "^")); | |
1354 } else if (t->base() == Type::Long && t->is_long()->is_con()) { | |
1355 const TypeLong *typeLong = t->is_long(); | |
1356 assert(typeLong->is_con(), "must be constant"); | |
1357 jlong value = typeLong->get_con(); | |
1358 | |
1359 // max. 2 chars allowed | |
1360 if (value >= -9 && value <= 99) { | |
1361 sprintf(buffer, "%d", value); | |
1362 desc->properties()->add(new Property(short_name, buffer)); | |
1363 } | |
1364 else | |
1365 { | |
1366 desc->properties()->add(new Property(short_name, "L")); | |
1367 } | |
1368 } else if (t->base() == Type::KlassPtr) { | |
1369 const TypeKlassPtr *typeKlass = t->is_klassptr(); | |
1370 desc->properties()->add(new Property(short_name, "CP")); | |
1371 } else if (t->base() == Type::Control) { | |
1372 desc->properties()->add(new Property(short_name, "C")); | |
1373 } else if (t->base() == Type::Memory) { | |
1374 desc->properties()->add(new Property(short_name, "M")); | |
1375 } else if (t->base() == Type::Abio) { | |
1376 desc->properties()->add(new Property(short_name, "IO")); | |
1377 } else if (t->base() == Type::Return_Address) { | |
1378 desc->properties()->add(new Property(short_name, "RA")); | |
1379 } else if (t->base() == Type::AnyPtr) { | |
1380 desc->properties()->add(new Property(short_name, "P")); | |
1381 } else if (t->base() == Type::RawPtr) { | |
1382 desc->properties()->add(new Property(short_name, "RP")); | |
1383 } else if (t->base() == Type::AryPtr) { | |
1384 desc->properties()->add(new Property(short_name, "AP")); | |
1385 } | |
1386 } | |
1387 | |
1388 if (node->is_SafePoint()) { | |
1389 SafePointNode *safePointNode = node->as_SafePoint(); | |
1390 if (safePointNode->jvms()) { | |
1391 stringStream bciStream; | |
1392 bciStream.print("%d ", safePointNode->jvms()->bci()); | |
1393 JVMState *caller = safePointNode->jvms()->caller(); | |
1394 while(caller) { | |
1395 bciStream.print("%d ", caller->bci()); | |
1396 | |
1397 caller = caller->caller(); | |
1398 } | |
1399 desc->properties()->add(new Property("bci", bciStream.as_string())); | |
1400 } | |
1401 } | |
1402 | |
1403 if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) { | |
1404 buffer[0] = 0; | |
1405 _chaitin->dump_register(node, buffer); | |
1406 desc->properties()->add(new Property("reg", buffer)); | |
1407 desc->properties()->add(new Property("lrg", _chaitin->n2lidx(node))); | |
1408 } | |
1409 | |
1410 | |
1411 node->_in_dump_cnt--; | |
1412 return desc; | |
1413 #else | |
1414 return NULL; | |
1415 #endif | |
1416 } | |
1417 | |
1418 void IdealGraphPrinter::pre_node(Node* node, void *env) { | |
1419 | |
1420 IdealGraphPrinter *printer = (IdealGraphPrinter *)env; | |
1421 | |
1422 NodeDescription *newDesc = printer->create_node_description(node); | |
1423 | |
1424 if (printer->_clear_nodes) { | |
1425 | |
1426 printer->_nodes.append(newDesc); | |
1427 } else { | |
1428 | |
1429 NodeDescription *desc = printer->_nodes.at_grow(node->_idx, NULL); | |
1430 | |
1431 if (desc && desc->equals(newDesc)) { | |
1432 //desc->set_state(Valid); | |
1433 //desc->set_node(node); | |
1434 delete desc; | |
1435 printer->_nodes.at_put(node->_idx, NULL); | |
1436 newDesc->set_state(Valid); | |
1437 //printer->_nodes.at_put(node->_idx, newDesc); | |
1438 } else { | |
1439 | |
1440 if (desc && desc->id() == newDesc->id()) { | |
1441 delete desc; | |
1442 printer->_nodes.at_put(node->_idx, NULL); | |
1443 newDesc->set_state(New); | |
1444 | |
1445 } | |
1446 | |
1447 //if (desc) { | |
1448 // delete desc; | |
1449 //} | |
1450 | |
1451 //printer->_nodes.at_put(node->_idx, newDesc); | |
1452 } | |
1453 | |
1454 printer->_nodes.append(newDesc); | |
1455 } | |
1456 } | |
1457 | |
1458 void IdealGraphPrinter::post_node(Node* node, void *env) { | |
1459 } | |
1460 | |
1461 outputStream *IdealGraphPrinter::output() { | |
1462 return _output; | |
1463 } | |
1464 | |
1465 IdealGraphPrinter::Description::Description() { | |
1466 _state = New; | |
1467 } | |
1468 | |
1469 void IdealGraphPrinter::Description::print(IdealGraphPrinter *printer) { | |
1470 if (_state == Invalid) { | |
1471 print_removed(printer); | |
1472 } else if (_state == New) { | |
1473 print_changed(printer); | |
1474 } | |
1475 } | |
1476 | |
1477 void IdealGraphPrinter::Description::set_state(State s) { | |
1478 _state = s; | |
1479 } | |
1480 | |
1481 IdealGraphPrinter::State IdealGraphPrinter::Description::state() { | |
1482 return _state; | |
1483 } | |
1484 | |
1485 void IdealGraphPrinter::Block::set_proj(NodeDescription *n) { | |
1486 _proj = n; | |
1487 } | |
1488 | |
1489 void IdealGraphPrinter::Block::set_start(NodeDescription *n) { | |
1490 _start = n; | |
1491 } | |
1492 | |
1493 int IdealGraphPrinter::Block::semi() { | |
1494 return _semi; | |
1495 } | |
1496 | |
1497 int IdealGraphPrinter::Block::parent() { | |
1498 return _parent; | |
1499 } | |
1500 | |
1501 GrowableArray<int>* IdealGraphPrinter::Block::bucket() { | |
1502 return &_bucket; | |
1503 } | |
1504 | |
1505 GrowableArray<int>* IdealGraphPrinter::Block::children() { | |
1506 return &_children; | |
1507 } | |
1508 | |
1509 void IdealGraphPrinter::Block::add_child(int i) { | |
1510 _children.append(i); | |
1511 } | |
1512 | |
1513 GrowableArray<int>* IdealGraphPrinter::Block::dominates() { | |
1514 return &_dominates; | |
1515 } | |
1516 | |
1517 void IdealGraphPrinter::Block::add_dominates(int i) { | |
1518 _dominates.append(i); | |
1519 } | |
1520 | |
1521 void IdealGraphPrinter::Block::add_to_bucket(int i) { | |
1522 _bucket.append(i); | |
1523 } | |
1524 | |
1525 void IdealGraphPrinter::Block::clear_bucket() { | |
1526 _bucket.clear(); | |
1527 } | |
1528 | |
1529 void IdealGraphPrinter::Block::set_dominator(int i) { | |
1530 _dominator = i; | |
1531 } | |
1532 | |
1533 void IdealGraphPrinter::Block::set_label(int i) { | |
1534 _label = i; | |
1535 } | |
1536 | |
1537 int IdealGraphPrinter::Block::label() { | |
1538 return _label; | |
1539 } | |
1540 | |
1541 int IdealGraphPrinter::Block::ancestor() { | |
1542 return _ancestor; | |
1543 } | |
1544 | |
1545 void IdealGraphPrinter::Block::set_ancestor(int i) { | |
1546 _ancestor = i; | |
1547 } | |
1548 | |
1549 int IdealGraphPrinter::Block::dominator() { | |
1550 return _dominator; | |
1551 } | |
1552 | |
1553 int IdealGraphPrinter::Block::index() { | |
1554 return _index; | |
1555 } | |
1556 | |
1557 void IdealGraphPrinter::Block::set_parent(int i) { | |
1558 _parent = i; | |
1559 } | |
1560 | |
1561 GrowableArray<int>* IdealGraphPrinter::Block::pred() { | |
1562 return &_pred; | |
1563 } | |
1564 | |
1565 void IdealGraphPrinter::Block::set_semi(int i) { | |
1566 _semi = i; | |
1567 } | |
1568 | |
1569 IdealGraphPrinter::Block::Block() { | |
1570 } | |
1571 | |
1572 IdealGraphPrinter::Block::Block(int index) { | |
1573 _index = index; | |
1574 _label = index; | |
1575 _semi = -1; | |
1576 _ancestor = -1; | |
1577 _dominator = -1; | |
1578 } | |
1579 | |
1580 void IdealGraphPrinter::Block::add_pred(int i) { | |
1581 _pred.append(i); | |
1582 } | |
1583 | |
1584 IdealGraphPrinter::NodeDescription *IdealGraphPrinter::Block::proj() { | |
1585 return _proj; | |
1586 } | |
1587 | |
1588 IdealGraphPrinter::NodeDescription *IdealGraphPrinter::Block::start() { | |
1589 return _start; | |
1590 } | |
1591 | |
1592 GrowableArray<int>* IdealGraphPrinter::Block::succs() { | |
1593 return &_succs; | |
1594 } | |
1595 | |
1596 void IdealGraphPrinter::Block::add_succ(int index) { | |
1597 | |
1598 if (this->_index == 16 && index == 15) { | |
1599 int x = 0; | |
1600 } | |
1601 | |
1602 if (!_succs.contains(index)) { | |
1603 _succs.append(index); | |
1604 } | |
1605 } | |
1606 | |
1607 | |
1608 void IdealGraphPrinter::Block::add_node(NodeDescription *n) { | |
1609 if (!_nodes.contains(n)) { | |
1610 _nodes.append(n); | |
1611 } | |
1612 } | |
1613 | |
1614 GrowableArray<IdealGraphPrinter::NodeDescription *>* IdealGraphPrinter::Block::nodes() { | |
1615 return &_nodes; | |
1616 } | |
1617 | |
1618 int IdealGraphPrinter::NodeDescription::count = 0; | |
1619 | |
1620 IdealGraphPrinter::NodeDescription::NodeDescription(Node* node) : _node(node) { | |
1621 _id = (intptr_t)(node); | |
1622 _block_index = -1; | |
1623 } | |
1624 | |
1625 IdealGraphPrinter::NodeDescription::~NodeDescription() { | |
1626 _properties.clean(); | |
1627 } | |
1628 | |
1629 // void IdealGraphPrinter::NodeDescription::set_node(Node* node) { | |
1630 // //this->_node = node; | |
1631 // } | |
1632 | |
1633 int IdealGraphPrinter::NodeDescription::block_index() { | |
1634 return _block_index; | |
1635 } | |
1636 | |
1637 | |
1638 GrowableArray<IdealGraphPrinter::NodeDescription *>* IdealGraphPrinter::NodeDescription::succs() { | |
1639 return &_succs; | |
1640 } | |
1641 | |
1642 void IdealGraphPrinter::NodeDescription::clear_succs() { | |
1643 _succs.clear(); | |
1644 } | |
1645 | |
1646 void IdealGraphPrinter::NodeDescription::init_succs() { | |
1647 _succs = GrowableArray<NodeDescription *>(); | |
1648 } | |
1649 | |
1650 void IdealGraphPrinter::NodeDescription::add_succ(NodeDescription *desc) { | |
1651 _succs.append(desc); | |
1652 } | |
1653 | |
1654 void IdealGraphPrinter::NodeDescription::set_block_index(int i) { | |
1655 _block_index = i; | |
1656 } | |
1657 | |
1658 bool IdealGraphPrinter::NodeDescription::equals(NodeDescription *desc) { | |
1659 if (desc == NULL) return false; | |
1660 if (desc->id() != id()) return false; | |
1661 return properties()->equals(desc->properties()); | |
1662 } | |
1663 | |
1664 Node* IdealGraphPrinter::NodeDescription::node() { | |
1665 return _node; | |
1666 } | |
1667 | |
1668 IdealGraphPrinter::Properties* IdealGraphPrinter::NodeDescription::properties() { | |
1669 return &_properties; | |
1670 } | |
1671 | |
1672 uint IdealGraphPrinter::NodeDescription::id() { | |
1673 return _id; | |
1674 } | |
1675 | |
1676 void IdealGraphPrinter::NodeDescription::print_changed(IdealGraphPrinter *printer) { | |
1677 | |
1678 | |
1679 Properties properties; | |
1680 properties.add(new Property(NODE_ID_PROPERTY, id())); | |
1681 printer->start_element(NODE_ELEMENT, &properties); | |
1682 | |
1683 this->properties()->print(printer); | |
1684 | |
1685 | |
1686 printer->end_element(NODE_ELEMENT); | |
1687 } | |
1688 | |
1689 void IdealGraphPrinter::NodeDescription::print_removed(IdealGraphPrinter *printer) { | |
1690 | |
1691 Properties properties; | |
1692 properties.add(new Property(NODE_ID_PROPERTY, id())); | |
1693 printer->simple_element(REMOVE_NODE_ELEMENT, &properties); | |
1694 } | |
1695 | |
1696 IdealGraphPrinter::EdgeDescription::EdgeDescription(int from, int to, int index) { | |
1697 this->_from = from; | |
1698 this->_to = to; | |
1699 this->_index = index; | |
1700 } | |
1701 | |
1702 IdealGraphPrinter::EdgeDescription::~EdgeDescription() { | |
1703 } | |
1704 | |
1705 int IdealGraphPrinter::EdgeDescription::from() { | |
1706 return _from; | |
1707 } | |
1708 | |
1709 int IdealGraphPrinter::EdgeDescription::to() { | |
1710 return _to; | |
1711 } | |
1712 | |
1713 void IdealGraphPrinter::EdgeDescription::print_changed(IdealGraphPrinter *printer) { | |
1714 | |
1715 Properties properties; | |
1716 properties.add(new Property(INDEX_PROPERTY, _index)); | |
1717 properties.add(new Property(FROM_PROPERTY, _from)); | |
1718 properties.add(new Property(TO_PROPERTY, _to)); | |
1719 printer->simple_element(EDGE_ELEMENT, &properties); | |
1720 } | |
1721 | |
1722 void IdealGraphPrinter::EdgeDescription::print_removed(IdealGraphPrinter *printer) { | |
1723 | |
1724 Properties properties; | |
1725 properties.add(new Property(INDEX_PROPERTY, _index)); | |
1726 properties.add(new Property(FROM_PROPERTY, _from)); | |
1727 properties.add(new Property(TO_PROPERTY, _to)); | |
1728 printer->simple_element(REMOVE_EDGE_ELEMENT, &properties); | |
1729 } | |
1730 | |
1731 bool IdealGraphPrinter::EdgeDescription::equals(IdealGraphPrinter::EdgeDescription *desc) { | |
1732 if (desc == NULL) return false; | |
1733 return (_from == desc->_from && _to == desc->_to && _index == desc->_index); | |
1734 } | |
1735 | |
1736 IdealGraphPrinter::Properties::Properties() : list(new (ResourceObj::C_HEAP) GrowableArray<Property *>(2, 0, NULL, true)) { | |
1737 } | |
1738 | |
1739 IdealGraphPrinter::Properties::~Properties() { | |
1740 clean(); | |
1741 delete list; | |
1742 } | |
1743 | |
1744 void IdealGraphPrinter::Properties::add(Property *p) { | |
1745 assert(p != NULL, "Property not NULL"); | |
1746 list->append(p); | |
1747 } | |
1748 | |
1749 void IdealGraphPrinter::Properties::print(IdealGraphPrinter *printer) { | |
1750 printer->start_element(PROPERTIES_ELEMENT); | |
1751 | |
1752 for (int i = 0; i < list->length(); i++) { | |
1753 list->at(i)->print(printer); | |
1754 } | |
1755 | |
1756 printer->end_element(PROPERTIES_ELEMENT); | |
1757 } | |
1758 | |
1759 void IdealGraphPrinter::Properties::clean() { | |
1760 for (int i = 0; i < list->length(); i++) { | |
1761 delete list->at(i); | |
1762 list->at_put(i, NULL); | |
1763 } | |
1764 list->clear(); | |
1765 assert(list->length() == 0, "List cleared"); | |
1766 } | |
1767 | |
1768 void IdealGraphPrinter::Properties::remove(const char *name) { | |
1769 for (int i = 0; i < list->length(); i++) { | |
1770 if (strcmp(list->at(i)->name(), name) == 0) { | |
1771 delete list->at(i); | |
1772 list->remove_at(i); | |
1773 i--; | |
1774 } | |
1775 } | |
1776 } | |
1777 | |
1778 void IdealGraphPrinter::Properties::print_as_attributes(IdealGraphPrinter *printer) { | |
1779 | |
1780 for (int i = 0; i < list->length(); i++) { | |
1781 assert(list->at(i) != NULL, "Property not null!"); | |
1782 printer->output()->print(" "); | |
1783 list->at(i)->print_as_attribute(printer); | |
1784 } | |
1785 } | |
1786 | |
1787 bool IdealGraphPrinter::Properties::equals(Properties* p) { | |
1788 if (p->list->length() != this->list->length()) return false; | |
1789 | |
1790 for (int i = 0; i < list->length(); i++) { | |
1791 assert(list->at(i) != NULL, "Property not null!"); | |
1792 if (!list->at(i)->equals(p->list->at(i))) return false; | |
1793 } | |
1794 | |
1795 return true; | |
1796 } | |
1797 | |
1798 IdealGraphPrinter::Property::Property() { | |
1799 _name = NULL; | |
1800 _value = NULL; | |
1801 } | |
1802 | |
1803 const char *IdealGraphPrinter::Property::name() { | |
1804 return _name; | |
1805 } | |
1806 | |
1807 IdealGraphPrinter::Property::Property(const Property* p) { | |
1808 | |
1809 this->_name = NULL; | |
1810 this->_value = NULL; | |
1811 | |
1812 if (p->_name != NULL) { | |
1813 _name = dup(p->_name); | |
1814 } | |
1815 | |
1816 if (p->_value) { | |
1817 _value = dup(p->_value); | |
1818 } | |
1819 } | |
1820 | |
1821 IdealGraphPrinter::Property::~Property() { | |
1822 | |
1823 clean(); | |
1824 } | |
1825 | |
1826 IdealGraphPrinter::Property::Property(const char *name, const char *value) { | |
1827 | |
1828 assert(name, "Name must not be null!"); | |
1829 assert(value, "Value must not be null!"); | |
1830 | |
1831 _name = dup(name); | |
1832 _value = dup(value); | |
1833 } | |
1834 | |
1835 IdealGraphPrinter::Property::Property(const char *name, int intValue) { | |
1836 _name = dup(name); | |
1837 | |
1838 stringStream stream; | |
1839 stream.print("%d", intValue); | |
1840 _value = dup(stream.as_string()); | |
1841 } | |
1842 | |
1843 void IdealGraphPrinter::Property::clean() { | |
1844 if (_name) { | |
1845 delete _name; | |
1846 _name = NULL; | |
1847 } | |
1848 | |
1849 if (_value) { | |
1850 delete _value; | |
1851 _value = NULL; | |
1852 } | |
1853 } | |
1854 | |
1855 | |
1856 bool IdealGraphPrinter::Property::is_null() { | |
1857 return _name == NULL; | |
1858 } | |
1859 | |
1860 void IdealGraphPrinter::Property::print(IdealGraphPrinter *printer) { | |
1861 | |
1862 assert(!is_null(), "null properties cannot be printed!"); | |
1863 Properties properties; | |
1864 properties.add(new Property(PROPERTY_NAME_PROPERTY, _name)); | |
1865 printer->start_element(PROPERTY_ELEMENT, &properties, false, false); | |
1866 printer->print_xml(_value); | |
1867 printer->end_element(PROPERTY_ELEMENT, false, true); | |
1868 } | |
1869 | |
1870 void IdealGraphPrinter::Property::print_as_attribute(IdealGraphPrinter *printer) { | |
1871 | |
1872 printer->output()->print(_name); | |
1873 printer->output()->print("=\""); | |
1874 printer->print_xml(_value); | |
1875 printer->output()->print("\""); | |
1876 } | |
1877 | |
1878 | |
1879 bool IdealGraphPrinter::Property::equals(Property* p) { | |
1880 | |
1881 if (is_null() && p->is_null()) return true; | |
1882 if (is_null()) return false; | |
1883 if (p->is_null()) return false; | |
1884 | |
1885 int cmp1 = strcmp(p->_name, _name); | |
1886 if (cmp1 != 0) return false; | |
1887 | |
1888 int cmp2 = strcmp(p->_value, _value); | |
1889 if (cmp2 != 0) return false; | |
1890 | |
1891 return true; | |
1892 } | |
1893 | |
1894 void IdealGraphPrinter::print_xml(const char *value) { | |
1895 size_t len = strlen(value); | |
1896 | |
1897 char buf[2]; | |
1898 buf[1] = 0; | |
1899 for (size_t i = 0; i < len; i++) { | |
1900 char c = value[i]; | |
1901 | |
1902 switch(c) { | |
1903 case '<': | |
1904 output()->print("<"); | |
1905 break; | |
1906 | |
1907 case '>': | |
1908 output()->print(">"); | |
1909 break; | |
1910 | |
1911 default: | |
1912 buf[0] = c; | |
1913 output()->print(buf); | |
1914 break; | |
1915 } | |
1916 } | |
1917 } | |
1918 | |
1919 #endif |