All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.jimple.toolkits.scalar.EqualLocalsAnalysis Maven / Gradle / Ivy

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 newDefs = new ArrayList();
		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 existingDefStmts = new ArrayList();
			Iterator outIt = out.iterator();
			while(outIt.hasNext())
			{
				Object o = outIt.next();
				if(o instanceof Stmt)
					existingDefStmts.add(o);
			}
			out.clear();
			Iterator 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 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 newDefsIt = newDefs.iterator();
						while(newDefsIt.hasNext())
							out.add( newDefsIt.next() );
					}
					else
					{
						Iterator 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();
	}	
}