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 */ 013 package org.jikesrvm.compilers.opt.util; 014 015 import java.util.Enumeration; 016 import java.util.HashSet; 017 018 019 /** 020 * SpaceEffGraph package implements a generic directed graph that can 021 * be a multigraph. It uses Lists to model nodes and edges information.<p> 022 * 023 * SpaceEffGraph is a generic graph. Extend to implement specific 024 * graph types. 025 */ 026 public class SpaceEffGraph implements Graph, TopSortInterface { 027 /** 028 * First node 029 */ 030 protected SpaceEffGraphNode _firstNode; 031 /** 032 * Last node 033 */ 034 protected SpaceEffGraphNode _lastNode; 035 /** 036 * Nodes with no predecessors 037 */ 038 private SpaceEffGraphNodeListHeader _rootNodes; 039 /** 040 * Topological sort order 041 */ 042 private SpaceEffGraphNodeListHeader _topSortNodes; // top sort order. 043 044 /** 045 * Number of nodes 046 */ 047 protected int numberOfNodes; 048 049 @Override 050 public final int numberOfNodes() { return numberOfNodes; } 051 052 /** 053 * Set number of nodes 054 * @param n new number of nodes 055 */ 056 public final void setNumberOfNodes(int n) { numberOfNodes = n; } 057 058 /** 059 * Get the next node number 060 * @return the node number 061 */ 062 public final int allocateNodeNumber() { return numberOfNodes++; } 063 064 /** 065 * Renumber the nodes densely from 0...numberOfNodes-1. 066 */ 067 @Override 068 public void compactNodeNumbering() { 069 int number = 0; 070 for (SpaceEffGraphNode n = _firstNode; n != null; n = n.getNext()) { 071 n.setNumber(number++); 072 } 073 numberOfNodes = number; 074 } 075 076 /** 077 * Enumerate the nodes in no particular order 078 */ 079 @Override 080 public Enumeration<GraphNode> enumerateNodes() { 081 return new NodeEnumeration(_firstNode); 082 } 083 084 ////////////////// 085 // The following are to implement TopSortInterface. 086 ////////////////// 087 088 @Override 089 public SortedGraphNode startNode(boolean forward) { 090 if (forward) { 091 return (SortedGraphNode) _firstNode; 092 } else { 093 return (SortedGraphNode) _lastNode; 094 } 095 } 096 097 @Override 098 public boolean isTopSorted(boolean forward) { 099 if (forward) { 100 return forwardTopSorted; 101 } else { 102 return backwardTopSorted; 103 } 104 } 105 106 @Override 107 public void setTopSorted(boolean forward) { 108 if (forward) { 109 forwardTopSorted = true; 110 } else { 111 backwardTopSorted = true; 112 } 113 } 114 115 @Override 116 public void resetTopSorted() { 117 forwardTopSorted = false; 118 backwardTopSorted = false; 119 } 120 121 public boolean forwardTopSorted = false, backwardTopSorted = false; 122 123 ////////////////// 124 // End of TopSortInterface implementation 125 ////////////////// 126 127 /** 128 * @param inode node to add 129 */ 130 @Override 131 public final void addGraphNode(GraphNode inode) { 132 SpaceEffGraphNode node = (SpaceEffGraphNode) inode; 133 //_nodes.add(node); 134 if (_firstNode == null) { 135 _firstNode = node; 136 _lastNode = node; 137 } else { 138 _lastNode.append(node); // this is cheaper than add() call. 139 _lastNode = node; 140 } 141 numberOfNodes++; 142 } 143 144 /** 145 * Remove a node from the graph. 146 * @param node node to remove 147 */ 148 public final void removeGraphNode(SpaceEffGraphNode node) { 149 if (node == _firstNode) { 150 if (node == _lastNode) { 151 _firstNode = _lastNode = null; 152 } else { 153 _firstNode = node.getNext(); 154 } 155 } else if (node == _lastNode) { 156 _lastNode = node.getPrev(); 157 } 158 node.remove(); 159 numberOfNodes--; 160 } 161 162 /** 163 * Add an edge to the graph. 164 * @param from start node 165 * @param to end node 166 * @see #addGraphEdge(SpaceEffGraphEdge) 167 */ 168 @Override 169 public void addGraphEdge(GraphNode from, GraphNode to) { 170 ((SpaceEffGraphNode) from).insertOut((SpaceEffGraphNode) to); 171 } 172 173 /** 174 * Add an edge to the graph. 175 * @param e edge to insert 176 * @see #addGraphEdge(GraphNode,GraphNode) 177 */ 178 public void addGraphEdge(SpaceEffGraphEdge e) { 179 e.fromNode().appendOutEdge(e); 180 e.toNode().appendInEdge(e); 181 } 182 183 /** 184 * Reset the list of nodes of the graph. 185 * WARNING!!! Use with caution if you know what you are doing. 186 * @param firstNode new value of the node list 187 */ 188 public final void setFirstNode(SpaceEffGraphNode firstNode) { 189 _firstNode = firstNode; 190 } 191 192 /** 193 * Reset the list of nodes of the graph. 194 * WARNING!!! Use with caution if you know what you are doing. 195 * @param lastNode new value of the node list 196 */ 197 public final void setLastNode(SpaceEffGraphNode lastNode) { 198 _lastNode = lastNode; 199 } 200 /** 201 * Get the list of nodes. 202 * @return list of nodes 203 */ 204 public final SpaceEffGraphNode firstNode() { 205 return _firstNode; 206 } 207 208 /** 209 * Get the end of the list of nodes. 210 * @return end of the list of nodes 211 */ 212 public final SpaceEffGraphNode lastNode() { 213 return _lastNode; 214 } 215 216 /** 217 * Add a root node to the graph. 218 * @param root a node to add 219 */ 220 public final void addRootNode(SpaceEffGraphNode root) { 221 //_rootNodes.add(root); 222 if (_rootNodes == null) { 223 _rootNodes = new SpaceEffGraphNodeListHeader(); 224 } 225 _rootNodes.append(root); 226 } 227 228 /** 229 * Get the list of root nodes. 230 * @return list of root nodes 231 */ 232 public final SpaceEffGraphNodeList rootNodes() { 233 return _rootNodes.first(); 234 } 235 236 /** 237 * Get the topological order of nodes. 238 * @return topological order of nodes 239 */ 240 public final SpaceEffGraphNodeList topSortOrder() { 241 return _topSortNodes.first(); 242 } 243 244 /** 245 * Clear the DFS flags. 246 */ 247 public final void clearDFS() { 248 for (SpaceEffGraphNode n = firstNode(); n != null; n = n.getNext()) { 249 n.clearDfsVisited(); 250 } 251 } 252 253 /** 254 * Build a topological sort of this graph 255 */ 256 public void buildTopSort() { 257 if (!forwardTopSorted) { 258 //SortedGraphNode node = 259 TopSort.buildTopological(this, true); 260 // currently, no one cares about the return value, so we don't return it 261 } 262 } 263 264 /** 265 * Build a reverse topological sort of this graph 266 * @return a node if we build a new order, null if we reused the old 267 */ 268 public SortedGraphNode buildRevTopSort() { 269 if (!backwardTopSorted) { 270 return TopSort.buildTopological(this, false); 271 } else { 272 return null; 273 } 274 } 275 276 /////////////////////// 277 // Starting with the root nodes, topologically sort them using 278 // the out edge information. Builds the _topSortNodes list. 279 // TODO: figure out how this works and add comments (IP) 280 /////////////////////// 281 282 protected void initTopSort() { 283 _topSortNodes = new SpaceEffGraphNodeListHeader(); 284 } 285 286 protected void addTopSortNode(SpaceEffGraphNode node) { 287 _topSortNodes.append(node); 288 } 289 290 public void topSort() { 291 initTopSort(); 292 for (SpaceEffGraphNode n = firstNode(); n != null; n = n.getNext()) { 293 if (n.firstInEdge() == null) { // no predecessors 294 n.setDfsVisited(); 295 n.setOnStack(); 296 dfs(n); 297 addTopSortNode(n); 298 } 299 } 300 } 301 302 private void dfs(SpaceEffGraphNode node) { 303 for (SpaceEffGraphEdge edge = node.firstOutEdge(); edge != null; edge = edge.getNextOut()) { 304 SpaceEffGraphNode succ = edge.toNode(); 305 if (!succ.dfsVisited()) { 306 succ.setDfsVisited(); 307 succ.setOnStack(); 308 dfs(succ); 309 } else if (succ.onStack() || succ == node) { 310 edge.setBackEdge(); 311 } 312 } 313 node.clearOnStack(); 314 for (SpaceEffGraphEdge edge = node.firstOutEdge(); edge != null; edge = edge.getNextOut()) { 315 SpaceEffGraphNode succ = edge.toNode(); 316 if (!succ.topVisited() && !edge.backEdge()) { 317 addTopSortNode(succ); 318 succ.setTopVisited(); 319 } 320 } 321 } 322 323 /** 324 * Return a string representation of this graph. 325 * @return a string representation of the graph 326 */ 327 @Override 328 public String toString() { 329 StringBuilder res = new StringBuilder(); 330 for (SpaceEffGraphNode n = firstNode(); n != null; n = n.getNext()) { 331 HashSet<SpaceEffGraphEdge> visitedNodes = new HashSet<SpaceEffGraphEdge>(); 332 int duplicatedNodes = 0; 333 res.append("\nNode: ").append(n).append("\n"); 334 res.append("In nodes:\n"); 335 for (SpaceEffGraphEdge inEdge = n.firstInEdge(); inEdge != null; inEdge = inEdge.getNextIn()) { 336 if (visitedNodes.contains(inEdge)) { 337 duplicatedNodes ++; 338 res.append("(Duplicated edge " + inEdge.toNodeString() + ")"); 339 if (duplicatedNodes > 5) { 340 break; 341 } 342 } else { 343 visitedNodes.add(inEdge); 344 res.append(inEdge.getTypeString()); 345 res.append(" "); 346 res.append(inEdge.fromNode()); 347 res.append("\n"); 348 } 349 } 350 res.append("\n"); 351 visitedNodes.clear(); 352 duplicatedNodes=0; 353 res.append("Out nodes:\n"); 354 for (SpaceEffGraphEdge out = n.firstOutEdge(); out != null; out = out.getNextOut()) { 355 if (visitedNodes.contains(out)) { 356 duplicatedNodes ++; 357 res.append("(Duplicated edge " + out.toNodeString() + ")"); 358 if (duplicatedNodes > 5) { 359 break; 360 } 361 } else { 362 res.append(out.getTypeString()); 363 res.append(" "); 364 res.append(out.toNode()); 365 res.append("\n"); 366 } 367 } 368 if (res.length() > 50000) { 369 res.append("....(giving up too long)\n"); 370 break; 371 } 372 } 373 return res.toString(); 374 } 375 376 //////////////////// 377 // Return a breadth-first enumeration of the nodes in this CFG. 378 // Note that this is different than topological ordering. 379 // TODO: figure out how this works and add comments (IP) 380 //////////////////// 381 382 /** 383 * Print, to System.out, the basic blocks in depth first order. 384 */ 385 public void printDepthFirst() { 386 print(new DepthFirstEnumerator(_firstNode)); 387 } 388 389 /** 390 * Print, to System.out, the basic blocks in the order given in 391 * the supplied enumeration. 392 * @param e enumeration order to print blocks 393 */ 394 private void print(Enumeration<GraphNode> e) { 395 while (e.hasMoreElements()) { 396 SpaceEffGraphNode bb = (SpaceEffGraphNode) e.nextElement(); 397 bb.printExtended(); 398 } 399 } 400 401 private static final class NodeEnumeration implements Enumeration<GraphNode> { 402 private SpaceEffGraphNode _node; 403 404 public NodeEnumeration(SpaceEffGraphNode n) { _node = n; } 405 406 @Override 407 public boolean hasMoreElements() { return _node != null; } 408 409 @Override 410 public GraphNode nextElement() { 411 SpaceEffGraphNode n = _node; 412 _node = n.getNext(); 413 return n; 414 } 415 } 416 } 417