/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-1999 Raja Vallee-Rai, Patrick Lam
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
package soot.toolkits.graph;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import soot.G;
import soot.Singletons;
/**
* Provide the pseudo topological order of a graph's nodes. It has same
* functionality as PseudoTopologicalOrderer; however, this class considers the
* order of successors. It runs slower but more precise. Currently it was only
* used by ArrayBoundsCheckerAnalysis to reduce the iteration numbers.
*
* @see: PseudoTopologicalOrderer
*/
public class SlowPseudoTopologicalOrderer implements Orderer {
public SlowPseudoTopologicalOrderer(Singletons.Global g) {
}
public static SlowPseudoTopologicalOrderer v() {
return G.v().soot_toolkits_graph_SlowPseudoTopologicalOrderer();
}
public SlowPseudoTopologicalOrderer() {
}
public SlowPseudoTopologicalOrderer(boolean isReversed) {
mIsReversed = isReversed;
}
private Map<Object,Integer> stmtToColor;
private static final int WHITE = 0, GRAY = 1, BLACK = 2;
private LinkedList order;
private boolean mIsReversed = false;
private DirectedGraph graph;
private List<Object> reverseOrder;
private final HashMap<Object,List> succsMap = new HashMap<Object,List>();
/**
* {@inheritDoc}
*/
public List newList(DirectedGraph g, boolean reverse) {
mIsReversed = reverse;
return computeOrder(g);
}
/**
* Orders in pseudo-topological order.
*
* @param g
* a DirectedGraph instance we want to order the nodes for.
* @return an ordered list of the graph's nodes.
*/
LinkedList computeOrder(DirectedGraph g) {
stmtToColor = new HashMap();
order = new LinkedList();
graph = g;
PseudoTopologicalReverseOrderer orderer = new PseudoTopologicalReverseOrderer();
reverseOrder = orderer.newList(g);
// Color all nodes white
{
Iterator stmtIt = g.iterator();
while (stmtIt.hasNext()) {
Object s = stmtIt.next();
stmtToColor.put(s, new Integer(WHITE));
}
}
// Visit each node
{
Iterator stmtIt = g.iterator();
while (stmtIt.hasNext()) {
Object s = stmtIt.next();
if (stmtToColor.get(s).intValue() == WHITE)
visitNode(s);
}
}
return order;
}
// Unfortunately, the nice recursive solution fails
// because of stack overflows
// Fill in the 'order' list with a pseudo topological order (possibly
// reversed)
// list of statements starting at s. Simulates recursion with a stack.
private void visitNode(Object startStmt) {
LinkedList stmtStack = new LinkedList();
LinkedList<Integer> indexStack = new LinkedList<Integer>();
stmtToColor.put(startStmt, new Integer(GRAY));
stmtStack.addLast(startStmt);
indexStack.addLast(new Integer(-1));
while (!stmtStack.isEmpty()) {
int toVisitIndex = indexStack.removeLast().intValue();
Object toVisitNode = stmtStack.getLast();
toVisitIndex++;
indexStack.addLast(new Integer(toVisitIndex));
if (toVisitIndex >= graph.getSuccsOf(toVisitNode).size()) {
// Visit this node now that we ran out of children
if (mIsReversed)
order.addLast(toVisitNode);
else
order.addFirst(toVisitNode);
stmtToColor.put(toVisitNode, new Integer(BLACK));
// Pop this node off
stmtStack.removeLast();
indexStack.removeLast();
} else {
List<Object> orderedSuccs = succsMap.get(toVisitNode);
if (orderedSuccs == null) {
orderedSuccs = new LinkedList<Object>();
succsMap.put(toVisitNode, orderedSuccs);
/* make ordered succs */
List allsuccs = graph.getSuccsOf(toVisitNode);
for (int i = 0; i < allsuccs.size(); i++) {
Object cur = allsuccs.get(i);
int j = 0;
for (; j < orderedSuccs.size(); j++) {
Object comp = orderedSuccs.get(j);
int idx1 = reverseOrder.indexOf(cur);
int idx2 = reverseOrder.indexOf(comp);
if (idx1 < idx2)
break;
}
orderedSuccs.add(j, cur);
}
}
Object childNode = orderedSuccs.get(toVisitIndex);
// Visit this child next if not already visited (or on stack)
if (stmtToColor.get(childNode).intValue() == WHITE) {
stmtToColor.put(childNode, new Integer(GRAY));
stmtStack.addLast(childNode);
indexStack.addLast(new Integer(-1));
}
}
}
}
private class PseudoTopologicalReverseOrderer {
private Map<Object, Integer> stmtToColor;
private static final int WHITE = 0, GRAY = 1, BLACK = 2;
private LinkedList<Object> order;
private final boolean mIsReversed = false;
private DirectedGraph graph;
/**
* @param g
* a DirectedGraph instance whose nodes we which to order.
* @return a pseudo-topologically ordered list of the graph's nodes.
*/
List<Object> newList(DirectedGraph g) {
return computeOrder(g);
}
/**
* Orders in pseudo-topological order.
*
* @param g
* a DirectedGraph instance we want to order the nodes for.
* @return an ordered list of the graph's nodes.
*/
LinkedList<Object> computeOrder(DirectedGraph g) {
stmtToColor = new HashMap<Object, Integer>();
order = new LinkedList<Object>();
graph = g;
// Color all nodes white
{
Iterator stmtIt = g.iterator();
while (stmtIt.hasNext()) {
Object s = stmtIt.next();
stmtToColor.put(s, new Integer(WHITE));
}
}
// Visit each node
{
Iterator stmtIt = g.iterator();
while (stmtIt.hasNext()) {
Object s = stmtIt.next();
if (stmtToColor.get(s).intValue() == WHITE)
visitNode(s);
}
}
return order;
}
private void visitNode(Object startStmt) {
LinkedList<Object> stmtStack = new LinkedList<Object>();
LinkedList<Integer> indexStack = new LinkedList<Integer>();
stmtToColor.put(startStmt, new Integer(GRAY));
stmtStack.addLast(startStmt);
indexStack.addLast(new Integer(-1));
while (!stmtStack.isEmpty()) {
int toVisitIndex = indexStack.removeLast()
.intValue();
Object toVisitNode = stmtStack.getLast();
toVisitIndex++;
indexStack.addLast(new Integer(toVisitIndex));
if (toVisitIndex >= graph.getPredsOf(toVisitNode).size()) {
// Visit this node now that we ran out of children
if (mIsReversed)
order.addLast(toVisitNode);
else
order.addFirst(toVisitNode);
stmtToColor.put(toVisitNode, new Integer(BLACK));
// Pop this node off
stmtStack.removeLast();
indexStack.removeLast();
} else {
Object childNode = graph.getPredsOf(toVisitNode).get(
toVisitIndex);
// Visit this child next if not already visited (or on
// stack)
if (stmtToColor.get(childNode).intValue() == WHITE) {
stmtToColor.put(childNode, new Integer(GRAY));
stmtStack.addLast(childNode);
indexStack.addLast(new Integer(-1));
}
}
}
}
}
// deprecated methods follow
/**
* @param g
* a DirectedGraph instance whose nodes we wish to order.
* @return a pseudo-topologically ordered list of the graph's nodes.
* @deprecated use {@link #newList(DirectedGraph, boolean))} instead
*/
public List newList(DirectedGraph g) {
return computeOrder(g);
}
/**
* Set the ordering for the orderer.
*
* @param isReverse
* specify if we want reverse pseudo-topological ordering, or
* not.
* @deprecated use {@link #newList(DirectedGraph, boolean))} instead
*/
public void setReverseOrder(boolean isReversed) {
mIsReversed = isReversed;
}
/**
* Check the ordering for the orderer.
*
* @return true if we have reverse pseudo-topological ordering, false
* otherwise.
* @deprecated use {@link #newList(DirectedGraph, boolean))} instead
*/
public boolean isReverseOrder() {
return mIsReversed;
}
}