/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.dataflow.IFDS;
import java.util.Iterator;
import com.ibm.wala.util.Predicate;
import com.ibm.wala.util.collections.FilterIterator;
import com.ibm.wala.util.collections.Iterator2Collection;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.debug.UnimplementedError;
import com.ibm.wala.util.graph.Graph;
import com.ibm.wala.util.intset.IntSet;
/**
* A "reversed" supergraph for backwards analysis.
*
* In this view, a return is treated like a call, and vice-versa. All normal edges are reversed.
*/
public class BackwardsSupergraph<T, P> implements ISupergraph<T, P> {
/**
* DEBUG_LEVEL:
* <ul>
* <li>0 No output
* <li>1 Print some simple stats and warning information
* <li>2 Detailed debugging
* </ul>
*/
static final int DEBUG_LEVEL = 0;
private final ISupergraph<T, P> delegate;
private final ExitFilter exitFilter = new ExitFilter();
/**
* @param forwardGraph the graph to ``reverse''
*/
protected BackwardsSupergraph(ISupergraph<T, P> forwardGraph) {
if (forwardGraph == null) {
throw new IllegalArgumentException("null forwardGraph");
}
this.delegate = forwardGraph;
}
public static <T, P> BackwardsSupergraph<T, P> make(ISupergraph<T, P> forwardGraph) {
return new BackwardsSupergraph<T, P>(forwardGraph);
}
/**
* TODO: for now, this is not inverted.
*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getProcedureGraph()
*/
@Override
public Graph<? extends P> getProcedureGraph() {
return delegate.getProcedureGraph();
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#isCall(java.lang.Object)
*/
@Override
public boolean isCall(T n) {
return delegate.isReturn(n);
}
/**
* a filter that accepts only exit nodes from the original graph.
*/
private class ExitFilter extends Predicate {
/*
* @see com.ibm.wala.util.Filter#accepts(java.lang.Object)
*/
@Override
@SuppressWarnings("unchecked")
public boolean test(Object o) {
return delegate.isExit((T) o);
}
}
/**
* get the "called" (sic) nodes for a return site; i.e., the exit nodes that flow directly to this return site.
*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCalledNodes(java.lang.Object)
*/
@Override
public Iterator<T> getCalledNodes(T ret) {
if (DEBUG_LEVEL > 1) {
System.err.println(getClass() + " getCalledNodes " + ret);
System.err.println("called nodes: "
+ Iterator2Collection.toSet(new FilterIterator<Object>(getSuccNodes(ret), exitFilter)));
}
return new FilterIterator<T>(getSuccNodes(ret), exitFilter);
}
/**
* get the "normal" successors (sic) for a return site; i.e., the "normal" CFG predecessors that are not call nodes.
*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCalledNodes(java.lang.Object)
*/
@Override
public Iterator<T> getNormalSuccessors(final T ret) {
Iterator<? extends Object> allPreds = delegate.getPredNodes(ret);
Predicate sameProc = new Predicate<T>() {
@Override public boolean test(T o) {
// throw out the exit node, which can be a predecessor due to tail recursion.
return getProcOf(ret).equals(getProcOf(o)) && !delegate.isExit(o);
}
};
Iterator<Object> sameProcPreds = new FilterIterator<Object>(allPreds, sameProc);
Predicate notCall = new Predicate<T>() {
@Override public boolean test(T o) {
return !delegate.isCall(o);
}
};
return new FilterIterator<T>(sameProcPreds, notCall);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object)
*/
@Override
public Iterator<? extends T> getReturnSites(T c, P callee) {
return delegate.getCallSites(c, callee);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#isExit(java.lang.Object)
*/
@Override
public boolean isExit(T n) {
return delegate.isEntry(n);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getProcOf(java.lang.Object)
*/
@Override
public P getProcOf(T n) {
return delegate.getProcOf(n);
}
/*
* @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object)
*/
@Override
public void removeNodeAndEdges(Object N) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Iterator<T> iterator() {
return delegate.iterator();
}
/*
* @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes()
*/
@Override
public int getNumberOfNodes() {
return delegate.getNumberOfNodes();
}
/*
* @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object)
*/
@Override
public void addNode(Object n) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/*
* @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object)
*/
@Override
public void removeNode(Object n) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/*
* @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object)
*/
@Override
public boolean containsNode(T N) {
return delegate.containsNode(N);
}
/*
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object)
*/
@Override
public Iterator<T> getPredNodes(T N) {
return delegate.getSuccNodes(N);
}
/*
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object)
*/
@Override
public int getPredNodeCount(T N) {
return delegate.getSuccNodeCount(N);
}
/*
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object)
*/
@Override
public Iterator<T> getSuccNodes(T N) {
return delegate.getPredNodes(N);
}
@Override
public boolean hasEdge(T src, T dst) {
return delegate.hasEdge(dst, src);
}
/*
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object)
*/
@Override
public int getSuccNodeCount(T N) {
return delegate.getPredNodeCount(N);
}
/*
* @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object)
*/
@Override
public void addEdge(Object src, Object dst) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public void removeEdge(Object src, Object dst) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/*
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object)
*/
@Override
public void removeAllIncidentEdges(Object node) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getEntriesForProcedure(java.lang.Object)
*/
@Override
public T[] getEntriesForProcedure(P object) {
return delegate.getExitsForProcedure(object);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getEntriesForProcedure(java.lang.Object)
*/
@Override
public T[] getExitsForProcedure(P object) {
return delegate.getEntriesForProcedure(object);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#isReturn(java.lang.Object)
*/
@Override
public boolean isReturn(T n) throws UnimplementedError {
return delegate.isCall(n);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object)
*/
@Override
public Iterator<? extends T> getCallSites(T r, P callee) {
return delegate.getReturnSites(r, callee);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#isEntry(java.lang.Object)
*/
@Override
public boolean isEntry(T n) {
return delegate.isExit(n);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#classifyEdge(java.lang.Object, java.lang.Object)
*/
@Override
public byte classifyEdge(T src, T dest) {
byte d = delegate.classifyEdge(dest, src);
switch (d) {
case CALL_EDGE:
return RETURN_EDGE;
case RETURN_EDGE:
return CALL_EDGE;
case OTHER:
return OTHER;
case CALL_TO_RETURN_EDGE:
return CALL_TO_RETURN_EDGE;
default:
Assertions.UNREACHABLE();
return -1;
}
}
@Override
public String toString() {
return "Backwards of delegate\n" + delegate;
}
@Override
public void removeIncomingEdges(Object node) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public void removeOutgoingEdges(T node) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getNumberOfBlocks(java.lang.Object)
*/
@Override
public int getNumberOfBlocks(P procedure) {
return delegate.getNumberOfBlocks(procedure);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getLocalBlockNumber(java.lang.Object)
*/
@Override
public int getLocalBlockNumber(T n) {
return delegate.getLocalBlockNumber(n);
}
/*
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getLocalBlock(java.lang.Object, int)
*/
@Override
public T getLocalBlock(P procedure, int i) {
return delegate.getLocalBlock(procedure, i);
}
@Override
public int getNumber(T N) {
return delegate.getNumber(N);
}
@Override
public T getNode(int number) {
return delegate.getNode(number);
}
@Override
public int getMaxNumber() {
return delegate.getMaxNumber();
}
@Override
public Iterator<T> iterateNodes(IntSet s) throws UnimplementedError {
Assertions.UNREACHABLE();
return null;
}
@Override
public IntSet getSuccNodeNumbers(T node) {
return delegate.getPredNodeNumbers(node);
}
@Override
public IntSet getPredNodeNumbers(Object node) throws UnimplementedError {
Assertions.UNREACHABLE();
return null;
}
}