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

soot.toolkits.graph.pdg.RegionAnalysis Maven / Gradle / Ivy

There is a newer version: 1.12.0
Show newest version
/* Soot - a J*va Optimization Framework
 * Copyright (C) 1999-2010 Hossein Sadat-Mohtasham
 *
 * 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.
 */
package soot.toolkits.graph.pdg;


import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import soot.Body;
import soot.G;
import soot.SootClass;
import soot.SootMethod;
import soot.Unit;
import soot.options.Options;
import soot.toolkits.graph.Block;
import soot.toolkits.graph.BlockGraph;
import soot.toolkits.graph.BriefBlockGraph;
import soot.toolkits.graph.BriefUnitGraph;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.DominatorNode;
import soot.toolkits.graph.DominatorTree;
import soot.toolkits.graph.ExceptionalBlockGraph;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.MHGDominatorsFinder;
import soot.toolkits.graph.MHGPostDominatorsFinder;
import soot.toolkits.graph.UnitGraph;

/**
 * This class computes the set of weak regions for a given method. It is based on the
 * algorithm given in the following paper:
 * 
 * Ball, T. 1993. What's in a region?: or computing control dependence regions in near-linear 
 * time for reducible control flow. ACM Lett. Program. Lang. Syst. 2, 1-4 (Mar. 1993), 
 * 1-16. DOI= http://doi.acm.org/10.1145/176454.176456
 * 
 * @author Hossein Sadat-Mohtasham
 * Jan 2009
 */

@SuppressWarnings("unchecked")
public class RegionAnalysis{
	
	protected SootClass m_class = null;
	protected SootMethod m_method = null;
	protected Body m_methodBody;
	protected UnitGraph m_cfg;
	protected UnitGraph m_reverseCFG;
	protected BlockGraph m_blockCFG;
	protected BlockGraph m_reverseBlockCFG;
	protected Hashtable m_regions = new Hashtable();
	protected List m_regionsList = null;
	private int m_regCount = 0;
	private MHGDominatorTree m_dom;
	//this would actually be the postdominator tree in the original CFG
	private MHGDominatorTree m_pdom;	
	protected Region m_topLevelRegion = null;
	protected Hashtable m_block2region = null;

	
	public RegionAnalysis(UnitGraph  cfg, SootMethod m, SootClass c)
	{
		this.m_methodBody = cfg.getBody();
		this.m_cfg = cfg;
		this.m_method = m;
		this.m_class = c;

		if(Options.v().verbose())
			G.v().out.println("[RegionAnalysis]~~~~~~~~~~~~~~~ Begin Region Analsis for method: " + m.getName() +" ~~~~~~~~~~~~~~~~~~~~");
		this.findWeakRegions();
		if(Options.v().verbose())
			G.v().out.println("[RegionAnalysis]~~~~~~~~~~~~~~~ End:" + m.getName() +" ~~~~~~~~~~~~~~~~~~~~");
	}
	
	
	private void findWeakRegions()
	{

		/*
		 * Check to see what kind of CFG has been passed in and create
		 * the appropriate block CFG. Note that almost all of the processing
		 * is done on the block CFG.
		 */
		
		if(this.m_cfg instanceof ExceptionalUnitGraph)
			this.m_blockCFG = new ExceptionalBlockGraph((ExceptionalUnitGraph)this.m_cfg);
		else if(this.m_cfg instanceof EnhancedUnitGraph)
			this.m_blockCFG = new EnhancedBlockGraph((EnhancedUnitGraph)this.m_cfg);
		else if(this.m_cfg instanceof BriefUnitGraph)
			this.m_blockCFG = new BriefBlockGraph((BriefUnitGraph)this.m_cfg);
		else
			throw new RuntimeException("Unsupported CFG passed into the RegionAnalyis constructor!");
		
	
		
		this.m_dom = new MHGDominatorTree(new MHGDominatorsFinder(this.m_blockCFG));
					
		
		String s = dominatorTreeToString(this.m_dom, this.m_dom.getHead());

		if(Options.v().verbose())
			G.v().out.println("[RegionAnalysis] Dominator tree: " + s);
		
				
		
		try{
		
			this.m_pdom = new MHGDominatorTree(new MHGPostDominatorsFinder(m_blockCFG));
		
			if(Options.v().verbose())
				G.v().out.println("[RegionAnalysis] PostDominator tree: ");
			
			List heads = this.m_pdom.getHeads();
			
			for(Iterator headItr = heads.iterator(); headItr.hasNext(); )
			{
				s = dominatorTreeToString(this.m_pdom, (DominatorNode) headItr.next());
				if(Options.v().verbose())
					G.v().out.println(s);	
			}
			
					
			this.m_regCount = -1;
			
			
			/*
			 * If a Brief graph or Exceptional graph is used, the CFG might be multi-headed and/or
			 * multi-tailed, which in turn, could result in a post-dominator forest instead of tree.
			 * If the post-dominator tree has multiple heads, the weakRegionDFS does not work correctly
			 * because it is designed based on the assumption that there is an auxiliary STOP node in the
			 * CFG that post-dominates all other nodes. In fact, most of the CFG algorithms augment
			 * the control flow graph with two nodes: ENTRY and EXIT (or START and STOP) nodes. We have
			 * not added these nodes since the CFG here is created from the Jimple code and to be 
			 * consistent we'd have to transform the code to reflect these nodes. Instead, we implemted
			 * the EnhancedUnitGraph (EnhancedBlockGraph) which is guaranteed to be single-headed single-tailed.
			 * But note that EnhancedUnitGraph represents exceptional flow differently.
			 * 
			 * 
			 */

		
			if(this.m_blockCFG.getHeads().size() == 1)
			{
				this.m_regCount++;
				this.m_regions.put(new Integer(this.m_regCount), this.createRegion(this.m_regCount));
				this.weakRegionDFS2((Block)this.m_blockCFG.getHeads().get(0), this.m_regCount);
			}
			else if(this.m_blockCFG.getTails().size() == 1)
			{
				this.m_regCount++;
				this.m_regions.put(new Integer(this.m_regCount), this.createRegion(this.m_regCount));
				this.weakRegionDFS((Block)this.m_blockCFG.getTails().get(0), this.m_regCount);
			
			}
			else 
			{
				if(Options.v().verbose())
					G.v().out.println("WARNING: RegionAnalysis: the CFG is multi-headed and tailed, so, the results of this analysis might not be reliable!");
				
				for(int i = 0; i < this.m_blockCFG.getTails().size(); i++)
				{
					this.m_regCount++;
					this.m_regions.put(new Integer(this.m_regCount), this.createRegion(this.m_regCount));
					this.weakRegionDFS((Block)this.m_blockCFG.getTails().get(i), this.m_regCount);
				
				}
				//throw new RuntimeException("RegionAnalysis: cannot properly deal with multi-headed and tailed CFG!");
			}
			
		
		}
		catch(RuntimeException e)
		{
			G.v().out.println("[RegionAnalysis] Exception in findWeakRegions: " + e);			
		}
		
		
	}
	
	/**
	 * This algorithms assumes that the first time it's called with a tail of the CFG. Then for each 
	 * child node w of v in the post-dominator tree, it compares the parent of v in the dominator tree
	 * with w and if they are the same, that means w belongs to the same region as v, so  weakRegionDFS
	 * is recursively called with w and the same region id as v.
	 * If the comparison fails, then a new region is created and weakRegionDFS is called recursively with
	 * w but this time with the newly created region id.
	 * 
	 * @param v
	 * @param r
	 */
	private void weakRegionDFS(Block v, int r)
	{
		try{
			//System.out.println("##entered weakRegionDFS for region " + r);
			this.m_regions.get(new Integer(r)).add(v);
			
			DominatorNode parentOfV = this.m_dom.getParentOf(this.m_dom.getDode(v));
			Block u2 = (parentOfV == null) ? null : (Block)parentOfV.getGode();
			
			List children = this.m_pdom.getChildrenOf(this.m_pdom.getDode(v));
			for(int i = 0; i < children.size(); i++)
			{
				DominatorNode w = (DominatorNode)children.get(i);
				Block u1 = (Block)w.getGode();
	
				if(u2 != null && u1.equals(u2))
				{
					this.weakRegionDFS((Block)w.getGode(), r);			
				}
				else
				{
					this.m_regCount++;
					this.m_regions.put(new Integer(this.m_regCount), this.createRegion(this.m_regCount));
					this.weakRegionDFS((Block)w.getGode(), this.m_regCount);			
				}	
			}	
		}
		catch(RuntimeException e)
		{
			G.v().out.println("[RegionAnalysis] Exception in weakRegionDFS: " + e);
			G.v().out.println("v is  " + v.toShortString() + " in region " + r);
			G.v().out.flush();
		}
	}
	/**
	 * This algorithm starts from a head node in the CFG and is exactly the same as the above
	 * with the difference that post dominator and dominator trees switch positions.
	 * @param v
	 * @param r
	 */
	private void weakRegionDFS2(Block v, int r)
	{
		//regions keep an implicit order of the contained blocks so it matters where blocks are added
		//below.
		this.m_regions.get(new Integer(r)).add2Back(v);
		
		DominatorNode parentOfV = this.m_pdom.getParentOf(this.m_pdom.getDode(v));
		Block u2 = (parentOfV == null) ? null : (Block)parentOfV.getGode();
		
		List children = this.m_dom.getChildrenOf(this.m_dom.getDode(v));
		for(int i = 0; i < children.size(); i++)
		{
			DominatorNode w = (DominatorNode)children.get(i);
			Block u1 = (Block)w.getGode();
			
			if(u2 != null && u1.equals(u2))
			{
				this.weakRegionDFS2((Block)w.getGode(), r);			
			}
			else
			{
				this.m_regCount++;
				this.m_regions.put(new Integer(this.m_regCount), this.createRegion(this.m_regCount));
				this.weakRegionDFS2((Block)w.getGode(), this.m_regCount);			
			}	
		}	

	}
	public List getRegions()
	{

		if(this.m_regionsList == null)
		{
			this.m_regionsList = new ArrayList();
			Collection values = this.m_regions.values();
			for(Iterator itr = values.iterator(); itr.hasNext();)
			{
				Region region = (Region) itr.next();
				this.m_regionsList.add(region);
			}
		}
		
		return this.m_regionsList;
		
	}
	
	public Hashtable getUnit2RegionMap()
	{
		Hashtable unit2region = new Hashtable();
		List regions = this.getRegions();
		
		for(Iterator itr = regions.iterator(); itr.hasNext();)
		{
			Region r = itr.next();
			List units = r.getUnits();
			for (Iterator itr1 = units.iterator(); itr1.hasNext();) 
			{
				Unit u = itr1.next();
				unit2region.put(u, r);
				
			}
		}
		
		return unit2region;
	}
	
	public Hashtable getBlock2RegionMap()
	{
		if(this.m_block2region == null)
		{
			this.m_block2region = new Hashtable();
		
			List regions = this.getRegions();
		
			for(Iterator itr = regions.iterator(); itr.hasNext();)
			{
				Region r = itr.next();
				List blocks = r.getBlocks();
				for (Iterator itr1 = blocks.iterator(); itr1.hasNext();) 
				{
					Block u = itr1.next();
					m_block2region.put(u, r);
				
				}
			}
		}
		return this.m_block2region;
		
	}
	
	public BlockGraph getBlockCFG()
	{
		return this.m_blockCFG;
	}
	
	public DominatorTree getPostDominatorTree()
	{
		return this.m_pdom;
	}
	
	public DominatorTree getDominatorTree()
	{
		return this.m_dom;
	}
	
	public void reset()
	{
		this.m_regions.clear();
		this.m_regionsList.clear();
		this.m_regionsList = null;
		this.m_block2region.clear();
		this.m_block2region = null;
		
		m_regCount = 0;
	}

	
	/**
	 * Create a region 
	 */
	
	protected Region createRegion(int id)
	{
		Region region = new Region(id, this.m_method, this.m_class, this.m_cfg);
		if(id == 0)
			this.m_topLevelRegion = region;
		
		return region;
	}
	
	public Region getTopLevelRegion()
	{
		return this.m_topLevelRegion;
	}
	
	public String CFGtoString(DirectedGraph cfg, boolean blockDetail)
	{
		String s = new String("");
		s += "Headers: " + cfg.getHeads().size() + " " + cfg.getHeads();
		for (Iterator it = cfg.iterator(); it.hasNext(); ) 
		{
		    Block node = it.next();
		    s += "Node = " + node.toShortString() + "\n";
		    s += "Preds:\n";
		    for (Iterator predsIt = cfg.getPredsOf(node).iterator(); predsIt.hasNext(); ) 
		    {
		    	s += "     ";
		    	s += predsIt.next().toShortString() + "\n";
		    }
		    s += "Succs:\n";
		    for (Iterator succsIt = cfg.getSuccsOf(node).iterator(); succsIt.hasNext(); ) 
		    {
		    	s += "     ";
		    	s += succsIt.next().toShortString() + "\n";
		    }
		}
		
		if(blockDetail)
		{
			s += "Blocks Detail:";
			for (Iterator it = cfg.iterator(); it.hasNext(); ) 
			{
			    Block node = it.next();
			    s += node + "\n";
			}
			
		}
		
		return s;

	}
	
	private String dominatorTreeToString(DominatorTree dom, DominatorNode root)
	{
		String s = new String();
		s += "\n Begin " + ((Block)root.getGode()).toShortString() + " ( ";
		List children = dom.getChildrenOf(root);
		
		for(int i = 0; i < children.size(); i++)
		{
			s += dominatorTreeToString(dom, (DominatorNode) children.get(i));
		
		}
		s += " ) end of " + ((Block)root.getGode()).toShortString();
		
		return s;
		
		
	}
	
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy