001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.util; 014 015import java.util.Enumeration; 016 017import org.jikesrvm.compilers.opt.OptimizingCompilerException; 018 019/** 020 * SpaceEffGraphNode is a generic graph node. Extend this to implement 021 * specific graph node types. A node has a list of out edges and a 022 * list of in edges. We maintain both to support bidirectional traversal 023 * of the graph. 024 */ 025public class SpaceEffGraphNode implements GraphNode { 026 027 /** 028 * The following word is used for various purposes. The first 029 * 8 bits are used for flags, and the remaining 24 bits for any 030 * node information (node number, for example) 031 */ 032 protected int info; 033 034 static final int DFS_VISITED = 0x01000000; 035 static final int TOP_VISITED = 0x02000000; 036 static final int ON_STACK = 0x04000000; 037 038 static final int LOOP_HEADER = 0x08000000; 039 040 static final int INFO_MASK = 0x00ffffff; 041 042 public final boolean dfsVisited() { 043 return (info & DFS_VISITED) != 0; 044 } 045 046 public final boolean topVisited() { 047 return (info & TOP_VISITED) != 0; 048 } 049 050 public final boolean onStack() { 051 return (info & ON_STACK) != 0; 052 } 053 054 public final boolean flagsOn() { 055 return (info & (DFS_VISITED | TOP_VISITED | ON_STACK)) != 0; 056 } 057 058 public final boolean isLoopHeader() { 059 return (info & LOOP_HEADER) != 0; 060 } 061 062 public final void setDfsVisited() { 063 info |= DFS_VISITED; 064 } 065 066 public final void setTopVisited() { 067 info |= TOP_VISITED; 068 } 069 070 public final void setOnStack() { 071 info |= ON_STACK; 072 } 073 074 public final void setDfsVisitedOnStack() { 075 info |= (DFS_VISITED | ON_STACK); 076 } 077 078 public final void setLoopHeader() { 079 info |= LOOP_HEADER; 080 } 081 082 public final void clearDfsVisited() { 083 info &= ~DFS_VISITED; 084 } 085 086 public final void clearTopVisited() { 087 info &= ~TOP_VISITED; 088 } 089 090 public final void clearOnStack() { 091 info &= ~ON_STACK; 092 } 093 094 public final void clearFlags() { 095 info &= ~(DFS_VISITED | TOP_VISITED | ON_STACK); 096 } 097 098 public final void clearLoopHeader() { 099 info &= ~LOOP_HEADER; 100 } 101 102 public final void setNumber(int value) { 103 info = (info & ~INFO_MASK) | (value & INFO_MASK); 104 } 105 106 public final int getNumber() { 107 return info & INFO_MASK; 108 } 109 110 @Override 111 public final int getIndex() { 112 return getNumber(); 113 } 114 115 @Override 116 public final void setIndex(int i) { 117 setNumber(i); 118 } 119 120 ///////////////// 121 // The following is used by several node sorting schemes 122 ///////////////// 123 124 public SpaceEffGraphNode nextSorted; 125 126 // return the first in/out edge 127 128 public final SpaceEffGraphEdge firstInEdge() { 129 return _inEdgeStart; 130 } 131 132 public final SpaceEffGraphEdge firstOutEdge() { 133 return _outEdgeStart; 134 } 135 136 public final SpaceEffGraphNode firstInNode() { 137 return _inEdgeStart.fromNode(); 138 } 139 140 public final SpaceEffGraphNode firstOutNode() { 141 return _outEdgeStart.toNode(); 142 } 143 144 /** 145 * clear the in set of edges 146 */ 147 final void clearIn() { 148 _inEdgeStart = _inEdgeEnd = null; 149 } 150 151 /** 152 * clear the out set of edges 153 */ 154 final void clearOut() { 155 _outEdgeStart = _outEdgeEnd = null; 156 } 157 158 // deletes all the in/out edges 159 160 public final void deleteIn() { 161 for (SpaceEffGraphEdge e = _inEdgeStart; e != null; e = e.nextIn) { 162 e.fromNode().removeOut(e); 163 } 164 clearIn(); 165 } 166 167 public final void deleteOut() { 168 for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) { 169 e.toNode().removeIn(e); 170 } 171 clearOut(); 172 } 173 174 /* get number of in/out edges */ 175 176 public final int getNumberOfIn() { 177 int count = 0; 178 for (SpaceEffGraphEdge e = _inEdgeStart; e != null; e = e.nextIn) { 179 count++; 180 } 181 return count; 182 } 183 184 public final int getNumberOfOut() { 185 int count = 0; 186 for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) { 187 count++; 188 } 189 return count; 190 } 191 192 /* specialized versions */ 193 public final boolean hasZeroOut() { 194 return _outEdgeStart == null; 195 } 196 197 public final boolean hasZeroIn() { 198 return _inEdgeStart == null; 199 } 200 201 public final boolean hasOneOut() { 202 SpaceEffGraphEdge first = _outEdgeStart; 203 return (first != null) && (first.nextOut == null); 204 } 205 206 public final boolean hasOneIn() { 207 SpaceEffGraphEdge first = _inEdgeStart; 208 return (first != null) && (first.nextIn == null); 209 } 210 211 /* returns true if points to the in/out set */ 212 213 public final boolean pointsIn(SpaceEffGraphNode inNode) { 214 for (SpaceEffGraphEdge e = _inEdgeStart; e != null; e = e.nextIn) { 215 if (e.fromNode() == inNode) return true; 216 } 217 return false; 218 } 219 220 public final boolean pointsOut(SpaceEffGraphNode outNode) { 221 for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) { 222 if (e.toNode() == outNode) return true; 223 } 224 return false; 225 } 226 227 public final boolean hasIn(GraphNode in) { 228 return pointsIn((SpaceEffGraphNode) in); 229 } 230 231 public final boolean hasOut(GraphNode out) { 232 return pointsOut((SpaceEffGraphNode) out); 233 } 234 235 /* 236 * returns the out edge pointing to node n, if it exists. 237 * returns null otherwise 238 */ 239 public final SpaceEffGraphEdge findOutEdgeTo(SpaceEffGraphNode n) { 240 for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) { 241 if (e.toNode() == n) return e; 242 } 243 return null; 244 } 245 246 /** 247 * Replaces the in edge matching e1 with e2. 248 * maintains the ordering of edges<p> 249 * 250 * @param e1 original edge 251 * @param e2 new edge 252 * 253 * TODO YUCK: this data structure is messy. I assume this is in the name 254 * of efficiency, but it makes control flow graph manipulations 255 * a real pain. (SJF) 256 */ 257 public final void replaceInEdge(SpaceEffGraphEdge e1, SpaceEffGraphEdge e2) { 258 // set the predecessor of e1 to point to e2 259 if (_inEdgeStart == e1) { 260 _inEdgeStart = e2; 261 } else { 262 // walk the list until we find the predecessor to e1 263 SpaceEffGraphEdge pred = null; 264 for (pred = _inEdgeStart; pred != null; pred = pred.nextIn) { 265 if (pred.nextIn == e1) break; 266 } 267 // if not found, there's an error 268 if (pred == null) { 269 throw new OptimizingCompilerException("SpaceEffGraphNode.replaceInEdge: called incorrectly"); 270 } 271 pred.nextIn = e2; 272 } 273 // set e2 to point to e1.nextIn 274 e2.nextIn = e1.nextIn; 275 276 // fix up _inEdgeStart, _inEdgeEnd 277 if (_inEdgeStart == e1) _inEdgeStart = e2; 278 if (_inEdgeEnd == e1) _inEdgeEnd = e2; 279 280 // clear the links of e1 281 e1.nextIn = null; 282 } 283 284 /** 285 * @param inNode the node that might be the single predecessor 286 * @return {@code true} if the node is the single predecessor of this node 287 */ 288 public final boolean hasOneIn(SpaceEffGraphNode inNode) { 289 SpaceEffGraphEdge first = _inEdgeStart; 290 return (first != null) && (first.nextIn == null) && (first.fromNode() == inNode); 291 } 292 293 /** 294 * 295 * @param outNode the node that might be the single successor 296 * @return {@code true} if the node is the single successor of this node 297 */ 298 public final boolean hasOneOut(SpaceEffGraphNode outNode) { 299 SpaceEffGraphEdge first = _outEdgeStart; 300 return (first != null) && (first.nextOut == null) && (first.toNode() == outNode); 301 } 302 303 public final void replaceOut(SpaceEffGraphNode oldOut, SpaceEffGraphNode newOut) { 304 deleteOut(oldOut); 305 insertOut(newOut); 306 } 307 308 public final void insertOut(SpaceEffGraphNode to, SpaceEffGraphEdge e) { 309 this.appendOutEdge(e); 310 to.appendInEdge(e); 311 } 312 313 public final void insertOut(SpaceEffGraphNode to) { 314 if (this.pointsOut(to)) return; 315 SpaceEffGraphEdge e = new SpaceEffGraphEdge(this, to); 316 this.appendOutEdge(e); 317 to.appendInEdge(e); 318 } 319 320 public final void deleteOut(SpaceEffGraphNode node) { 321 SpaceEffGraphEdge edge = this.removeOut(node); 322 node.removeIn(edge); 323 } 324 325 public final void deleteOut(SpaceEffGraphEdge e) { 326 SpaceEffGraphNode to = e.toNode(); 327 this.removeOut(e); 328 to.removeIn(e); 329 } 330 331 /* sort nodes according to DFS. result is a list of nodes with the current 332 as root. Note: it assumes that the dfs flags have been cleared before */ 333 public final void sortDFS() { 334 _sortDFS(null); 335 } 336 337 protected final void _sortDFS(SpaceEffGraphNode header) { 338 setDfsVisited(); 339 for (SpaceEffGraphEdge e = _outEdgeStart; e != null; e = e.nextOut) { 340 SpaceEffGraphNode n = e.toNode(); 341 if (!n.dfsVisited()) { 342 n._sortDFS(header); 343 header = n; 344 } 345 } 346 nextSorted = header; 347 } 348 349 /* clear all out/in flags */ 350 351 public final void clearOutFlags() { 352 clearFlags(); 353 for (SpaceEffGraphEdge e = firstOutEdge(); e != null; e = e.getNextOut()) { 354 SpaceEffGraphNode succ = e.toNode(); 355 e.clearVisited(); 356 if (succ.flagsOn()) { 357 succ.clearOutFlags(); 358 } 359 } 360 } 361 362 public final void clearInFlags() { 363 clearFlags(); 364 for (SpaceEffGraphEdge e = firstInEdge(); e != null; e = e.getNextIn()) { 365 SpaceEffGraphNode succ = e.fromNode(); 366 e.clearVisited(); 367 if (succ.flagsOn()) { 368 succ.clearInFlags(); 369 } 370 } 371 } 372 373 /* topological sort of nodes. result is a list of nodes with the current 374 as root */ 375 376 public final void sortTop() { 377 clearOutFlags(); 378 setDfsVisitedOnStack(); 379 nextSorted = _sortTop(null); 380 } 381 382 protected final SpaceEffGraphNode _sortTop(SpaceEffGraphNode tail) { 383 for (SpaceEffGraphEdge e = firstOutEdge(); e != null; e = e.getNextOut()) { 384 SpaceEffGraphNode succ = e.toNode(); 385 if (!succ.dfsVisited()) { 386 succ.setDfsVisitedOnStack(); 387 tail = succ._sortTop(tail); 388 } else if (succ.onStack() || succ == this) { 389 e.setVisited(); // back edge 390 } 391 } 392 clearOnStack(); 393 for (SpaceEffGraphEdge e = firstOutEdge(); e != null; e = e.getNextOut()) { 394 SpaceEffGraphNode succ = e.toNode(); 395 if (!succ.topVisited() && !e.visited()) { 396 succ.nextSorted = tail; 397 tail = succ; 398 succ.setTopVisited(); 399 } 400 } 401 return tail; 402 } 403 404 /* reverse topological sort of nodes. result is a list of nodes with the 405 current as root */ 406 407 public final void sortRevTop() { 408 clearInFlags(); 409 setDfsVisitedOnStack(); 410 nextSorted = _sortRevTop(null); 411 } 412 413 protected final SpaceEffGraphNode _sortRevTop(SpaceEffGraphNode tail) { 414 for (SpaceEffGraphEdge e = firstInEdge(); e != null; e = e.getNextIn()) { 415 SpaceEffGraphNode succ = e.fromNode(); 416 if (!succ.dfsVisited()) { 417 succ.setDfsVisitedOnStack(); 418 tail = succ._sortRevTop(tail); 419 } else if (succ.onStack() || succ == this) { 420 e.setVisited(); // forward edge 421 } 422 } 423 clearOnStack(); 424 for (SpaceEffGraphEdge e = firstInEdge(); e != null; e = e.getNextIn()) { 425 SpaceEffGraphNode succ = e.fromNode(); 426 if (!succ.topVisited() && !e.visited()) { 427 succ.nextSorted = tail; 428 tail = succ; 429 succ.setTopVisited(); 430 } 431 } 432 return tail; 433 } 434 435 /* print sorted nodes starting from this */ 436 437 final void printSorted() { 438 for (SpaceEffGraphNode n = this; n != null; n = n.nextSorted) { 439 System.out.println(n); 440 } 441 } 442 443 /** 444 * Revert the sequence of out edges 445 */ 446 final void revertOuts() { 447 SpaceEffGraphEdge last = null; 448 SpaceEffGraphEdge e = firstOutEdge(); 449 _outEdgeStart = _outEdgeEnd; 450 _outEdgeEnd = e; 451 while (e != null) { 452 SpaceEffGraphEdge next = e.getNextOut(); 453 e.appendOut(last); 454 last = e; 455 e = next; 456 } 457 } 458 459 /* enumerations to get the nodes/edges */ 460 461 public interface GraphEdgeEnumeration<T extends GraphEdge> extends Enumeration<T> { 462 // Same as nextElement but avoid the need to downcast from Object 463 T next(); 464 } 465 466 public final InEdgeEnumeration inEdges() { 467 return new InEdgeEnumeration(this); 468 } 469 470 public final OutEdgeEnumeration outEdges() { 471 return new OutEdgeEnumeration(this); 472 } 473 474 @Override 475 public final Enumeration<GraphNode> inNodes() { 476 return new InNodeEnumeration(this); 477 } 478 479 @Override 480 public final Enumeration<GraphNode> outNodes() { 481 return new OutNodeEnumeration(this); 482 } 483 484 /* print utilities */ 485 486 public void printInEdges() { 487 for (SpaceEffGraphEdge in = firstInEdge(); in != null; in = in.getNextIn()) { 488 System.out.println(in.fromNodeString()); 489 } 490 } 491 492 public void printOutEdges() { 493 for (SpaceEffGraphEdge out = firstOutEdge(); out != null; out = out.getNextOut()) { 494 System.out.println(out.toNodeString()); 495 } 496 } 497 498 public void printInNodes() { 499 for (SpaceEffGraphEdge in = firstInEdge(); in != null; in = in.getNextIn()) { 500 System.out.println(in.fromNode()); 501 } 502 } 503 504 public void printOutNodes() { 505 for (SpaceEffGraphEdge out = firstOutEdge(); out != null; out = out.getNextOut()) { 506 System.out.println(out.toNode()); 507 } 508 } 509 510 public void printExtended() { 511 System.out.println(this); 512 } 513 514 ///////////////// 515 // Implementation: the following is not intended for general client use 516 ///////////////// 517 518 protected SpaceEffGraphEdge _outEdgeStart; 519 protected SpaceEffGraphEdge _outEdgeEnd; 520 protected SpaceEffGraphEdge _inEdgeStart; 521 protected SpaceEffGraphEdge _inEdgeEnd; 522 523 // 524 // add an in/out edge from 'node' to this node. 525 // 526 527 // (SJF): I had to make these public to do SSA transformations. 528 // TODO: The CFG data structure should not depend this tightly 529 // on the underlying Graph implementation, but rather should be 530 // designed so that the SSA-like transformations are easy to do. 531 532 protected final void appendInEdge(SpaceEffGraphEdge e) { 533 SpaceEffGraphEdge inEdgeEnd = _inEdgeEnd; 534 if (inEdgeEnd != null) { 535 inEdgeEnd.appendIn(e); 536 } else { 537 _inEdgeStart = e; 538 } 539 _inEdgeEnd = e; 540 } 541 542 protected final void appendOutEdge(SpaceEffGraphEdge e) { 543 SpaceEffGraphEdge outEdgeEnd = _outEdgeEnd; 544 if (outEdgeEnd != null) { 545 outEdgeEnd.appendOut(e); 546 } else { 547 _outEdgeStart = e; 548 } 549 _outEdgeEnd = e; 550 } 551 552 /* remove and edge/node from the in/out set */ 553 554 protected final void removeIn(SpaceEffGraphEdge InEdge) { 555 SpaceEffGraphEdge prev = null; 556 for (SpaceEffGraphEdge edge = _inEdgeStart; edge != null; prev = edge, edge = edge.nextIn) { 557 if (edge == InEdge) { 558 SpaceEffGraphEdge next = edge.nextIn; 559 if (prev == null) { 560 _inEdgeStart = next; 561 } else { 562 prev.appendIn(next); 563 } 564 if (next == null) { 565 _inEdgeEnd = prev; 566 } 567 break; 568 } 569 } 570 } 571 572 protected final SpaceEffGraphEdge removeIn(SpaceEffGraphNode InNode) { 573 SpaceEffGraphEdge edge, prev = null; 574 for (edge = _inEdgeStart; edge != null; prev = edge, edge = edge.nextIn) { 575 if (edge.fromNode() == InNode) { 576 SpaceEffGraphEdge next = edge.nextIn; 577 if (prev == null) { 578 _inEdgeStart = next; 579 } else { 580 prev.appendIn(next); 581 } 582 if (next == null) { 583 _inEdgeEnd = prev; 584 } 585 break; 586 } 587 } 588 return edge; 589 } 590 591 protected final void removeOut(SpaceEffGraphEdge OutEdge) { 592 SpaceEffGraphEdge edge, prev = null; 593 for (edge = _outEdgeStart; edge != null; prev = edge, edge = edge.nextOut) { 594 if (edge == OutEdge) { 595 SpaceEffGraphEdge next = edge.nextOut; 596 if (prev == null) { 597 _outEdgeStart = next; 598 } else { 599 prev.appendOut(next); 600 } 601 if (next == null) { 602 _outEdgeEnd = prev; 603 } 604 break; 605 } 606 } 607 } 608 609 protected final SpaceEffGraphEdge removeOut(SpaceEffGraphNode OutNode) { 610 SpaceEffGraphEdge edge, prev = null; 611 for (edge = _outEdgeStart; edge != null; prev = edge, edge = edge.nextOut) { 612 if (edge.toNode() == OutNode) { 613 SpaceEffGraphEdge next = edge.nextOut; 614 if (prev == null) { 615 _outEdgeStart = next; 616 } else { 617 prev.appendOut(next); 618 } 619 if (next == null) { 620 _outEdgeEnd = prev; 621 } 622 break; 623 } 624 } 625 return edge; 626 } 627 628 static final class InEdgeEnumeration implements GraphEdgeEnumeration<GraphEdge> { 629 private SpaceEffGraphEdge _edge; 630 631 InEdgeEnumeration(SpaceEffGraphNode n) { 632 _edge = n._inEdgeStart; 633 } 634 635 @Override 636 public boolean hasMoreElements() { 637 return _edge != null; 638 } 639 640 @Override 641 public SpaceEffGraphEdge nextElement() { 642 return next(); 643 } 644 645 @Override 646 public SpaceEffGraphEdge next() { 647 SpaceEffGraphEdge e = _edge; 648 _edge = e.nextIn; 649 return e; 650 } 651 } 652 653 static final class InNodeEnumeration implements Enumeration<GraphNode> { 654 private SpaceEffGraphEdge _edge; 655 656 InNodeEnumeration(SpaceEffGraphNode n) { 657 _edge = n._inEdgeStart; 658 } 659 660 @Override 661 public boolean hasMoreElements() { 662 return _edge != null; 663 } 664 665 @Override 666 public GraphNode nextElement() { 667 SpaceEffGraphEdge e = _edge; 668 _edge = e.nextIn; 669 return e.fromNode(); 670 } 671 } 672 673 public static final class OutEdgeEnumeration implements GraphEdgeEnumeration<GraphEdge> { 674 private SpaceEffGraphEdge _edge; 675 676 public OutEdgeEnumeration(SpaceEffGraphNode n) { 677 _edge = n._outEdgeStart; 678 } 679 680 @Override 681 public boolean hasMoreElements() { 682 return _edge != null; 683 } 684 685 @Override 686 public GraphEdge nextElement() { 687 return next(); 688 } 689 690 @Override 691 public GraphEdge next() { 692 SpaceEffGraphEdge e = _edge; 693 _edge = e.nextOut; 694 return e; 695 } 696 } 697 698 static final class OutNodeEnumeration implements Enumeration<GraphNode> { 699 private SpaceEffGraphEdge _edge; 700 701 OutNodeEnumeration(SpaceEffGraphNode n) { 702 _edge = n._outEdgeStart; 703 } 704 705 @Override 706 public boolean hasMoreElements() { 707 return _edge != null; 708 } 709 710 @Override 711 public GraphNode nextElement() { 712 SpaceEffGraphEdge e = _edge; 713 _edge = e.nextOut; 714 return e.toNode(); 715 } 716 } 717 718 /** 719 * Links inlined from DoublyLinkedListElement. 720 */ 721 public SpaceEffGraphNode prev, next; 722 723 /** 724 * Get the next node. 725 * @return next node 726 */ 727 public final SpaceEffGraphNode getNext() { 728 return next; 729 } 730 731 /** 732 * Get the previous node. 733 * @return previous node 734 */ 735 public final SpaceEffGraphNode getPrev() { 736 return prev; 737 } 738 739 /** 740 * Append a given node after this node. 741 * @param n the node to append 742 */ 743 public final void append(SpaceEffGraphNode n) { 744 next = n; 745 n.prev = this; 746 } 747 748 /** 749 * Remove this node from the list. 750 * @return the next node in the list 751 */ 752 public final SpaceEffGraphNode remove() { 753 // copy old links 754 SpaceEffGraphNode Prev = prev, Next = next; 755 756 // reset old links 757 prev = null; 758 next = null; 759 760 // compute new links 761 if (Prev != null) Prev.next = Next; 762 if (Next != null) Next.prev = Prev; 763 764 // return next node 765 return Next; 766 } 767 768}