|
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 |