package soot.jimple.toolkits.scalar;
import soot.*;
import java.util.*;
import soot.toolkits.graph.*;
import soot.toolkits.scalar.*;
import soot.jimple.*;
// EqualLocalsAnalysis written by Richard L. Halpert, 2006-12-04
// Finds equal/equavalent/aliasing locals to a given local at a given statement, on demand
// The answer provided is occasionally suboptimal (but correct) in the event where
// a _re_definition of the given local causes it to become equal to existing locals.
public class EqualLocalsAnalysis extends ForwardFlowAnalysis
{
Local l;
Stmt s;
public EqualLocalsAnalysis(UnitGraph g)
{
super(g);
l = null;
s = null;
// analysis is done on-demand, not now
}
/** Returns a list of EquivalentValue wrapped Locals and Refs that must always be equal to l at s */
public List getCopiesOfAt(Local l, Stmt s)
{
this.l = l;
this.s = s;
doAnalysis();
List aliasList = new ArrayList();
aliasList.addAll(((FlowSet) getFlowBefore(s)).toList());
if(aliasList.contains(new EquivalentValue(l)))
return aliasList;
return new ArrayList();
}
protected void merge(Object in1, Object in2, Object out)
{
FlowSet inSet1 = (FlowSet) in1;
FlowSet inSet2 = (FlowSet) in2;
FlowSet outSet = (FlowSet) out;
inSet1.intersection(inSet2, outSet);
}
protected void flowThrough(Object inValue, Object unit,
Object outValue)
{
FlowSet in = (FlowSet) inValue;
FlowSet out = (FlowSet) outValue;
Stmt stmt = (Stmt) unit;
in.copy(out);
// get list of definitions at this unit
List<EquivalentValue> newDefs = new ArrayList<EquivalentValue>();
Iterator newDefBoxesIt = stmt.getDefBoxes().iterator();
while( newDefBoxesIt.hasNext() )
{
newDefs.add( new EquivalentValue( ((ValueBox) newDefBoxesIt.next()).getValue()) );
}
// If the local of interest was defined in this statement, then we must
// generate a new list of aliases to it starting here
if( newDefs.contains(new EquivalentValue(l)) )
{
List<Object> existingDefStmts = new ArrayList<Object>();
Iterator outIt = out.iterator();
while(outIt.hasNext())
{
Object o = outIt.next();
if(o instanceof Stmt)
existingDefStmts.add(o);
}
out.clear();
Iterator<EquivalentValue> newDefsIt = newDefs.iterator();
while(newDefsIt.hasNext())
out.add( newDefsIt.next() );
if( stmt instanceof DefinitionStmt )
{
if( !stmt.containsInvokeExpr() && !(stmt instanceof IdentityStmt) )
{
out.add( new EquivalentValue(((DefinitionStmt)stmt).getRightOp()) );
}
}
Iterator<Object> existingDefIt = existingDefStmts.iterator();
while(existingDefIt.hasNext())
{
Stmt s = (Stmt) existingDefIt.next();
List sNewDefs = new ArrayList();
Iterator sNewDefBoxesIt = s.getDefBoxes().iterator();
while( sNewDefBoxesIt.hasNext() )
{
sNewDefs.add( ((ValueBox) sNewDefBoxesIt.next()).getValue() );
}
if( s instanceof DefinitionStmt )
{
if( out.contains( new EquivalentValue(((DefinitionStmt)s).getRightOp()) ) )
{
Iterator sNewDefsIt = sNewDefs.iterator();
while(sNewDefsIt.hasNext())
out.add( new EquivalentValue( (Value) sNewDefsIt.next() ) );
}
else
{
Iterator sNewDefsIt = sNewDefs.iterator();
while(sNewDefsIt.hasNext())
out.remove( new EquivalentValue( (Value) sNewDefsIt.next() ) );
}
}
}
}
else
{
if( stmt instanceof DefinitionStmt )
{
if( out.contains( new EquivalentValue(l) ) )
{
if( out.contains( new EquivalentValue(((DefinitionStmt)stmt).getRightOp()) ) )
{
Iterator<EquivalentValue> newDefsIt = newDefs.iterator();
while(newDefsIt.hasNext())
out.add( newDefsIt.next() );
}
else
{
Iterator<EquivalentValue> newDefsIt = newDefs.iterator();
while(newDefsIt.hasNext())
out.remove( newDefsIt.next() );
}
}
else // before finding a def for l, just keep track of all definition statements
// note that if l is redefined, then we'll miss existing values that then
// become equal to l. It is suboptimal but correct to miss these values.
{
out.add( stmt );
}
}
}
}
protected void copy(Object source, Object dest)
{
FlowSet sourceSet = (FlowSet) source;
FlowSet destSet = (FlowSet) dest;
sourceSet.copy(destSet);
}
protected Object entryInitialFlow()
{
return new ArraySparseSet();
}
protected Object newInitialFlow()
{
return new ArraySparseSet();
}
}