/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-2000 Raja Vallee-Rai
*
* 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-2000.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
/*
2000, March 20 - Updated code provided by Patrick Lam
<plam@sable.mcgill.ca>
from 1.beta.4.dev.60
to 1.beta.6.dev.34
Plus some bug fixes.
-- Janus <janus@place.org>
KNOWN LIMITATION: the analysis doesn't handle traps since traps
handler statements have predecessors, but they
don't have the trap handler as successor. This
might be a limitation of the CompleteUnitGraph
tho.
*/
package soot.toolkits.scalar;
import soot.*;
import soot.toolkits.graph.*;
import soot.util.*;
import java.util.*;
import soot.toolkits.graph.interaction.*;
import soot.options.*;
/** Abstract class providing an engine for branched forward flow analysis.
* WARNING: This does not handle exceptional flow as branches!
* */
public abstract class ForwardBranchedFlowAnalysis<A> extends BranchedFlowAnalysis<Unit, A>
{
public ForwardBranchedFlowAnalysis(UnitGraph graph)
{
super(graph);
}
protected boolean isForward()
{
return true;
}
// Accumulate the previous afterFlow sets.
private void accumulateAfterFlowSets(Unit s, A[] flowRepositories, List<Object> previousAfterFlows)
{
int repCount = 0;
previousAfterFlows.clear();
if (s.fallsThrough())
{
copy(unitToAfterFallFlow.get(s).get(0), flowRepositories[repCount]);
previousAfterFlows.add(flowRepositories[repCount++]);
}
if (s.branches())
{
List<A> l = (unitToAfterBranchFlow.get(s));
Iterator<A> it = l.iterator();
while (it.hasNext())
{
A fs = (it.next());
copy(fs, flowRepositories[repCount]);
previousAfterFlows.add(flowRepositories[repCount++]);
}
}
} // end accumulateAfterFlowSets
protected void doAnalysis()
{
final Map<Unit, Integer> numbers = new HashMap<Unit, Integer>();
List orderedUnits = new PseudoTopologicalOrderer().newList(graph,false);
{
int i = 1;
for( Iterator uIt = orderedUnits.iterator(); uIt.hasNext(); ) {
final Unit u = (Unit) uIt.next();
numbers.put(u, new Integer(i));
i++;
}
}
TreeSet<Unit> changedUnits = new TreeSet<Unit>( new Comparator() {
public int compare(Object o1, Object o2) {
Integer i1 = numbers.get(o1);
Integer i2 = numbers.get(o2);
return (i1.intValue() - i2.intValue());
}
} );
Map<Unit, ArrayList> unitToIncomingFlowSets = new HashMap<Unit, ArrayList>(graph.size() * 2 + 1, 0.7f);
List heads = graph.getHeads();
int numNodes = graph.size();
int numComputations = 0;
int maxBranchSize = 0;
// initialize unitToIncomingFlowSets
{
Iterator it = graph.iterator();
while (it.hasNext())
{
Unit s = (Unit) it.next();
unitToIncomingFlowSets.put(s, new ArrayList());
}
}
// Set initial values and nodes to visit.
// WARNING: DO NOT HANDLE THE CASE OF THE TRAPS
{
Chain sl = ((UnitGraph)graph).getBody().getUnits();
Iterator it = graph.iterator();
while(it.hasNext())
{
Unit s = (Unit) it.next();
changedUnits.add(s);
unitToBeforeFlow.put(s, newInitialFlow());
if (s.fallsThrough())
{
ArrayList<A> fl = new ArrayList<A>();
fl.add((newInitialFlow()));
unitToAfterFallFlow.put(s, fl);
Unit succ=(Unit) sl.getSuccOf(s);
// it's possible for someone to insert some (dead)
// fall through code at the very end of a method body
if(succ!=null) {
List<Object> l = (unitToIncomingFlowSets.get(sl.getSuccOf(s)));
l.addAll(fl);
}
}
else
unitToAfterFallFlow.put(s, new ArrayList<A>());
if (s.branches())
{
ArrayList<A> l = new ArrayList<A>();
List<A> incList;
Iterator boxIt = s.getUnitBoxes().iterator();
while (boxIt.hasNext())
{
A f = (newInitialFlow());
l.add(f);
Unit ss = ((UnitBox) (boxIt.next())).getUnit();
incList = (unitToIncomingFlowSets.get(ss));
incList.add(f);
}
unitToAfterBranchFlow.put(s, l);
}
else
unitToAfterBranchFlow.put(s, new ArrayList<A>());
if (s.getUnitBoxes().size() > maxBranchSize)
maxBranchSize = s.getUnitBoxes().size();
}
}
// Feng Qian: March 07, 2002
// init entry points
{
Iterator<Unit> it = heads.iterator();
while (it.hasNext()) {
Unit s = it.next();
// this is a forward flow analysis
unitToBeforeFlow.put(s, entryInitialFlow());
}
}
if (treatTrapHandlersAsEntries())
{
Iterator trapIt = ((UnitGraph)graph).getBody().
getTraps().iterator();
while(trapIt.hasNext()) {
Trap trap = (Trap) trapIt.next();
Unit handler = trap.getHandlerUnit();
unitToBeforeFlow.put(handler, entryInitialFlow());
}
}
// Perform fixed point flow analysis
{
List<Object> previousAfterFlows = new ArrayList<Object>();
List<Object> afterFlows = new ArrayList<Object>();
A[] flowRepositories = (A[]) new Object[maxBranchSize+1];
for (int i = 0; i < maxBranchSize+1; i++)
flowRepositories[i] = newInitialFlow();
A[] previousFlowRepositories = (A[])new Object[maxBranchSize+1];
for (int i = 0; i < maxBranchSize+1; i++)
previousFlowRepositories[i] = newInitialFlow();
while(!changedUnits.isEmpty())
{
A beforeFlow;
Unit s = changedUnits.first();
changedUnits.remove(s);
boolean isHead = heads.contains(s);
accumulateAfterFlowSets(s, previousFlowRepositories, previousAfterFlows);
// Compute and store beforeFlow
{
List<A> preds = unitToIncomingFlowSets.get(s);
beforeFlow = unitToBeforeFlow.get(s);
if(preds.size() == 1)
copy(preds.get(0), beforeFlow);
else if(preds.size() != 0)
{
Iterator<A> predIt = preds.iterator();
copy(predIt.next(), beforeFlow);
while(predIt.hasNext())
{
A otherBranchFlow = predIt.next();
A newBeforeFlow = newInitialFlow();
merge(s, beforeFlow, otherBranchFlow, newBeforeFlow);
copy(newBeforeFlow, beforeFlow);
}
}
if(isHead && preds.size() != 0)
mergeInto(s, beforeFlow, entryInitialFlow());
}
// Compute afterFlow and store it.
{
ArrayList<A> afterFallFlow = unitToAfterFallFlow.get(s);
ArrayList<A> afterBranchFlow = unitToAfterBranchFlow.get(s);
if (Options.v().interactive_mode()){
A savedFlow = newInitialFlow();
copy(beforeFlow, savedFlow);
FlowInfo fi = new FlowInfo(savedFlow, s, true);
if (InteractionHandler.v().getStopUnitList() != null && InteractionHandler.v().getStopUnitList().contains(s)){
InteractionHandler.v().handleStopAtNodeEvent(s);
}
InteractionHandler.v().handleBeforeAnalysisEvent(fi);
}
flowThrough(beforeFlow, s, (List) afterFallFlow, (List) afterBranchFlow);
if (Options.v().interactive_mode()){
ArrayList l = new ArrayList();
if (!((List)afterFallFlow).isEmpty()){
l.addAll((List)afterFallFlow);
}
if (!((List)afterBranchFlow).isEmpty()){
l.addAll((List)afterBranchFlow);
}
/*if (s instanceof soot.jimple.IfStmt){
l.addAll((List)afterFallFlow);
l.addAll((List)afterBranchFlow);
}
else {
l.addAll((List)afterFallFlow);
}*/
FlowInfo fi = new FlowInfo(l, s, false);
InteractionHandler.v().handleAfterAnalysisEvent(fi);
}
numComputations++;
}
accumulateAfterFlowSets(s, flowRepositories, afterFlows);
// Update queue appropriately
if(!afterFlows.equals(previousAfterFlows))
{
Iterator succIt = graph.getSuccsOf(s).iterator();
while(succIt.hasNext())
{
Unit succ = (Unit) succIt.next();
changedUnits.add(succ);
}
}
}
}
// G.v().out.println(graph.getBody().getMethod().getSignature() + " numNodes: " + numNodes +
// " numComputations: " + numComputations + " avg: " + Main.truncatedOf((double) numComputations / numNodes, 2));
Timers.v().totalFlowNodes += numNodes;
Timers.v().totalFlowComputations += numComputations;
} // end doAnalysis
} // end class ForwardBranchedFlowAnalysis