292 lines
7.6 KiB
Java
292 lines
7.6 KiB
Java
/*******************************************************************************
|
|
* 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.fixedpoint.impl;
|
|
|
|
import java.util.Iterator;
|
|
import java.util.Set;
|
|
|
|
import com.ibm.wala.fixpoint.AbstractStatement;
|
|
import com.ibm.wala.fixpoint.IFixedPointStatement;
|
|
import com.ibm.wala.fixpoint.IFixedPointSystem;
|
|
import com.ibm.wala.fixpoint.IVariable;
|
|
import com.ibm.wala.fixpoint.UnaryStatement;
|
|
import com.ibm.wala.util.collections.EmptyIterator;
|
|
import com.ibm.wala.util.Predicate;
|
|
import com.ibm.wala.util.collections.FilterIterator;
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
import com.ibm.wala.util.debug.UnimplementedError;
|
|
import com.ibm.wala.util.graph.GraphIntegrity;
|
|
import com.ibm.wala.util.graph.INodeWithNumber;
|
|
import com.ibm.wala.util.graph.NumberedGraph;
|
|
import com.ibm.wala.util.graph.impl.SparseNumberedGraph;
|
|
import com.ibm.wala.util.graph.traverse.Topological;
|
|
|
|
/**
|
|
* Default implementation of a dataflow graph
|
|
*/
|
|
public class DefaultFixedPointSystem<T extends IVariable<?>> implements IFixedPointSystem<T> {
|
|
static final boolean DEBUG = false;
|
|
|
|
/**
|
|
* A graph which defines the underlying system of statements and variables
|
|
*/
|
|
private final NumberedGraph<INodeWithNumber> graph;
|
|
|
|
/**
|
|
* We maintain a hash set of equations in order to check for equality with
|
|
* equals() ... the NumberedGraph does not support this. TODO: use a custom
|
|
* NumberedNodeManager to save space
|
|
*/
|
|
final private Set<IFixedPointStatement<?>> equations = HashSetFactory.make();
|
|
|
|
/**
|
|
* We maintain a hash set of variables in order to check for equality with
|
|
* equals() ... the NumberedGraph does not support this. TODO: use a custom
|
|
* NumberedNodeManager to save space
|
|
*/
|
|
final private Set<IVariable<?>> variables = HashSetFactory.make();
|
|
|
|
/**
|
|
* @param expectedOut number of expected out edges in the "usual" case
|
|
* for constraints .. used to tune graph representation
|
|
*/
|
|
public DefaultFixedPointSystem(int expectedOut) {
|
|
super();
|
|
graph = new SparseNumberedGraph<INodeWithNumber>(expectedOut);
|
|
}
|
|
|
|
/**
|
|
* default constructor ... tuned for one use for each def in
|
|
* dataflow graph.
|
|
*/
|
|
public DefaultFixedPointSystem() {
|
|
this(1);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
return graph.equals(obj);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return graph.hashCode();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return graph.toString();
|
|
}
|
|
|
|
@Override
|
|
public void removeStatement(IFixedPointStatement<T> s) {
|
|
graph.removeNodeAndEdges(s);
|
|
}
|
|
|
|
@Override
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
public Iterator<AbstractStatement> getStatements() {
|
|
return new FilterIterator(graph.iterator(), new Predicate() {
|
|
@Override public boolean test(Object x) {
|
|
return x instanceof AbstractStatement;
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
@SuppressWarnings("rawtypes")
|
|
public void addStatement(IFixedPointStatement statement) throws IllegalArgumentException, UnimplementedError {
|
|
if (statement == null) {
|
|
throw new IllegalArgumentException("statement == null");
|
|
}
|
|
if (statement instanceof UnaryStatement) {
|
|
addStatement((UnaryStatement) statement);
|
|
} else if (statement instanceof NullaryStatement) {
|
|
addStatement((NullaryStatement) statement);
|
|
} else if (statement instanceof GeneralStatement) {
|
|
addStatement((GeneralStatement) statement);
|
|
} else {
|
|
Assertions.UNREACHABLE("unexpected: " + statement.getClass());
|
|
}
|
|
}
|
|
|
|
public void addStatement(GeneralStatement<?> s) {
|
|
if (s == null) {
|
|
throw new IllegalArgumentException("s is null");
|
|
}
|
|
IVariable<?>[] rhs = s.getRHS();
|
|
IVariable<?> lhs = s.getLHS();
|
|
|
|
equations.add(s);
|
|
graph.addNode(s);
|
|
if (lhs != null) {
|
|
variables.add(lhs);
|
|
graph.addNode(lhs);
|
|
graph.addEdge(s, lhs);
|
|
}
|
|
for (int i = 0; i < rhs.length; i++) {
|
|
IVariable<?> v = rhs[i];
|
|
IVariable<?> variable = v;
|
|
if (variable != null) {
|
|
variables.add(variable);
|
|
graph.addNode(variable);
|
|
graph.addEdge(variable, s);
|
|
}
|
|
}
|
|
|
|
if (DEBUG) {
|
|
checkGraph();
|
|
}
|
|
}
|
|
|
|
public void addStatement(UnaryStatement<?> s) {
|
|
if (s == null) {
|
|
throw new IllegalArgumentException("s is null");
|
|
}
|
|
IVariable<?> lhs = s.getLHS();
|
|
IVariable<?> rhs = s.getRightHandSide();
|
|
|
|
equations.add(s);
|
|
graph.addNode(s);
|
|
if (lhs != null) {
|
|
variables.add(lhs);
|
|
graph.addNode(lhs);
|
|
graph.addEdge(s, lhs);
|
|
}
|
|
variables.add(rhs);
|
|
graph.addNode(rhs);
|
|
graph.addEdge(rhs, s);
|
|
|
|
if (DEBUG) {
|
|
checkGraph();
|
|
}
|
|
}
|
|
|
|
public void addStatement(NullaryStatement<?> s) {
|
|
if (s == null) {
|
|
throw new IllegalArgumentException("s is null");
|
|
}
|
|
IVariable<?> lhs = s.getLHS();
|
|
|
|
equations.add(s);
|
|
graph.addNode(s);
|
|
if (lhs != null) {
|
|
variables.add(lhs);
|
|
graph.addNode(lhs);
|
|
graph.addEdge(s, lhs);
|
|
}
|
|
|
|
if (DEBUG) {
|
|
checkGraph();
|
|
}
|
|
}
|
|
|
|
public void addVariable(T v) {
|
|
variables.add(v);
|
|
graph.addNode(v);
|
|
if (DEBUG) {
|
|
checkGraph();
|
|
}
|
|
}
|
|
|
|
public AbstractStatement<?,?> getStep(int number) {
|
|
return (AbstractStatement<?,?>) graph.getNode(number);
|
|
}
|
|
|
|
@Override
|
|
public void reorder() {
|
|
if (DEBUG) {
|
|
checkGraph();
|
|
}
|
|
|
|
Iterator<INodeWithNumber> order = Topological.makeTopologicalIter(graph);
|
|
int number = 0;
|
|
while (order.hasNext()) {
|
|
Object elt = order.next();
|
|
if (elt instanceof IVariable) {
|
|
@SuppressWarnings("unchecked")
|
|
T v = (T) elt;
|
|
v.setOrderNumber(number++);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* check that this graph is well-formed
|
|
*/
|
|
private void checkGraph() {
|
|
try {
|
|
GraphIntegrity.check(graph);
|
|
} catch (Throwable e) {
|
|
e.printStackTrace();
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Iterator<?> getStatementsThatUse(T v) {
|
|
return (graph.containsNode(v) ? graph.getSuccNodes(v) : EmptyIterator.instance());
|
|
}
|
|
|
|
@Override
|
|
public Iterator<?> getStatementsThatDef(T v) {
|
|
return (graph.containsNode(v) ? graph.getPredNodes(v) : EmptyIterator.instance());
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public T getVariable(int n) {
|
|
return (T) graph.getNode(n);
|
|
}
|
|
|
|
@Override
|
|
public int getNumberOfStatementsThatUse(T v) {
|
|
return (graph.containsNode(v) ? graph.getSuccNodeCount(v) : 0);
|
|
}
|
|
|
|
@Override
|
|
public int getNumberOfStatementsThatDef(T v) {
|
|
return (graph.containsNode(v) ? graph.getPredNodeCount(v) : 0);
|
|
}
|
|
|
|
@Override
|
|
public Iterator<T> getVariables() {
|
|
return new FilterIterator<T>(graph.iterator(), new Predicate<T>() {
|
|
@Override public boolean test(T x) {
|
|
return x instanceof IVariable;
|
|
}
|
|
});
|
|
}
|
|
|
|
public int getNumberOfNodes() {
|
|
return graph.getNumberOfNodes();
|
|
}
|
|
|
|
public Iterator<? extends INodeWithNumber> getPredNodes(INodeWithNumber n) {
|
|
return graph.getPredNodes(n);
|
|
}
|
|
|
|
|
|
public int getPredNodeCount(INodeWithNumber n) {
|
|
return graph.getPredNodeCount(n);
|
|
}
|
|
|
|
@Override
|
|
public boolean containsStatement(IFixedPointStatement<T> s) {
|
|
return equations.contains(s);
|
|
}
|
|
|
|
@Override
|
|
public boolean containsVariable(T v) {
|
|
return variables.contains(v);
|
|
}
|
|
|
|
} |