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