Package soot.toolkits.graph.pdg

Source Code of soot.toolkits.graph.pdg.HashMutablePDG

/* 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.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import soot.Body;
import soot.SootClass;
import soot.toolkits.graph.Block;
import soot.toolkits.graph.BlockGraph;
import soot.toolkits.graph.DominatorNode;
import soot.toolkits.graph.DominatorTree;
import soot.toolkits.graph.HashMutableEdgeLabelledDirectedGraph;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.graph.pdg.IRegion;


/**
*
* This class implements a Program Dependence Graph as defined in
*
* Ferrante, J., Ottenstein, K. J., and Warren, J. D. 1987.
* The program dependence graph and its use in optimization.
* ACM Trans. Program. Lang. Syst. 9, 3 (Jul. 1987), 319-349.
* DOI= http://doi.acm.org/10.1145/24039.24041
*
* Note: the implementation is not exactly as in the above paper. It first finds
* the regions of control dependence then uses part of the algorithm given in
* the above paper to build the graph.
*
* The constructor accepts a UnitGraph, which can be a BriefUnitGraph, an ExceptionalUnitGraph,
* or an EnhancedUnitGraph. At the absence of exception handling constructs in
* a method, all of these work the same. However, at the presence of exception handling
* constructs, BriefUnitGraph is multi-headed and potentially multi-tailed which makes
* the results of RegionAnalysis and PDG construction unreliable (It's not clear if
* it would be useful anyway); Also, ExceptionalGraph's usefulness when exception handling
* is present is not so clear since almost every unit can throw exception hence the
* dependency is affected. Currently, the PDG is based on a UnitGraph (BlockGraph) and does
* not care whether flow is exceptional or not.
*
* The nodes in a PDG are of type PDGNode and the edges can have three labels: "dependency",
* "dependency-back", and "controlflow"; however, the "controlflow" edges are auxiliary
* and the dependencies are represented by the labels beginning with "dependency".
* Other labels can be added later for application
* or domain-specific cases.
*
*
* To support methods that contain exception-handling and multiple-heads or tails, use EnhancedUnitGraph.
* It does not represent exceptional flow in the way ExceptionalUnitGraph does, but it integrates
* them in a concise way. Also, it adds START/STOP nodes to graph if necessary to make the graph
* single entry single exit.
*
*
* @author Hossein Sadat-Mohtasham
* Sep 2009
*/

public class HashMutablePDG extends HashMutableEdgeLabelledDirectedGraph implements ProgramDependenceGraph {
 
  protected Body m_body = null;
  protected SootClass m_class = null;
  protected UnitGraph m_cfg = null;
  protected BlockGraph m_blockCFG = null;
  protected Hashtable<Object, PDGNode> m_obj2pdgNode = new Hashtable<Object, PDGNode>();
  protected List<Region> m_weakRegions = null;
  protected List<Region> m_strongRegions = null;
  protected PDGNode m_startNode = null;
  protected List<PDGRegion> m_pdgRegions = null;
  private RegionAnalysis m_regionAnalysis = null;
  private int m_strongRegionStartID;

 
  public HashMutablePDG(UnitGraph cfg)
  {
    this.m_body = cfg.getBody();
    this.m_class = this.m_body.getMethod().getDeclaringClass();
    this.m_cfg = cfg;
       
    this.m_regionAnalysis = new RegionAnalysis(this.m_cfg, this.m_body.getMethod(), this.m_class);
   
    /*
     * Get the weak regions and save a copy. Note that the strong regions list is
     * initially cloned from the weak region to be later modified.
     */
    this.m_strongRegions = this.m_regionAnalysis.getRegions();
    this.m_weakRegions = this.cloneRegions(this.m_strongRegions);
    this.m_blockCFG = this.m_regionAnalysis.getBlockCFG();
   
    //Construct the PDG
    this.constructPDG();
    this.m_pdgRegions = HashMutablePDG.computePDGRegions(this.m_startNode);

   
    /*This is needed to convert the initially Region-typed inner node of the PDG's head
      to a PDGRegion-typed one after the whole graph is computed.
      The root PDGRegion is the one with no parent.
    */

    IRegion r = this.m_pdgRegions.get(0);
    while(r.getParent() != null)
      r = r.getParent();
   
    this.m_startNode.setNode(r);
   
  }
 
  /**
   * This is the heart of the PDG contruction. It is huge and definitely needs
   * some refactorings, but since it's been evlovong to cover some boundary cases
   * it has become hard to rafactor.
   *
   * It uses the list of weak regions, along with the dominator and post-dominator
   * trees to construct the PDG nodes.
   */
  @SuppressWarnings("unchecked")
  protected void constructPDG()
  {
    Hashtable<Block, Region> block2region = this.m_regionAnalysis.getBlock2RegionMap();
    DominatorTree pdom = this.m_regionAnalysis.getPostDominatorTree();
    DominatorTree dom = this.m_regionAnalysis.getDominatorTree();
       
    List<Region> regions2process = new LinkedList<Region>();
    Region topLevelRegion = this.m_regionAnalysis.getTopLevelRegion();
    m_strongRegionStartID = m_weakRegions.size();
   
    //This becomes the top-level region (or ENTRY region node)
    PDGNode pdgnode = new PDGNode(topLevelRegion, PDGNode.Type.REGION);
    this.addNode(pdgnode);
    this.m_obj2pdgNode.put(topLevelRegion, pdgnode);
    this.m_startNode = pdgnode;
    topLevelRegion.setParent(null);
   
    regions2process.add(topLevelRegion);
   
    //while there's a (weak) region to process
    while(!regions2process.isEmpty())
    {
      Region r = regions2process.remove(0);
     
      //get the corresponding pdgnode
      pdgnode = this.m_obj2pdgNode.get(r);
     
      /*
       * For all the CFG nodes in the region, create the corresponding PDG node and edges, and
       * process them if they are in the dependence set of other regions, i.e. other regions
       * depend on them.
       */
      List<Block> blocks = r.getBlocks();
      Hashtable<Region, List<Block>> toBeRemoved = new Hashtable<Region, List<Block>>();
      PDGNode prevPDGNodeInRegion = null;
      PDGNode curNodeInRegion = null;
      for(Iterator<Block> itr = blocks.iterator(); itr.hasNext();)
      {
        /*
         * Add the PDG node corresponding to the CFG block node.
         */
        Block a = itr.next();
        PDGNode pdgNodeOfA = null;
        if(!this.m_obj2pdgNode.containsKey(a))
        {
          pdgNodeOfA = new PDGNode(a, PDGNode.Type.CFGNODE);
          this.addNode(pdgNodeOfA);
          this.m_obj2pdgNode.put(a, pdgNodeOfA);
        }
        else
          pdgNodeOfA = this.m_obj2pdgNode.get(a);
               
        this.addEdge(pdgnode, pdgNodeOfA, "dependency");
        pdgnode.addDependent(pdgNodeOfA);
        //
       
        curNodeInRegion = pdgNodeOfA;
       
        /*
         * For each successor B of A, if B does not post-dominate A, add all the
         * nodes on the path from B to the L in the post-dominator tree, where L is the least
         * common ancestor of A and B in the post-dominator tree (L will be either A itself or
         * the parent of A.).
         */
       
        List<Block> bs = this.m_blockCFG.getSuccsOf(a);
        for(Iterator<Block> bItr = bs.iterator(); bItr.hasNext();)
        {
          List<Block> dependents = new ArrayList<Block>();
         
          Block b = bItr.next();
         
          if(b.equals(a))
            throw new RuntimeException("PDG construction: A and B are not supposed to be the same node!");
         
         
          DominatorNode aDode = pdom.getDode(a);
          DominatorNode bDode = pdom.getDode(b);
         
          //If B post-dominates A, go to the next successor.
          if(pdom.isDominatorOf(bDode, aDode))
            continue;
         
          //FIXME: what if the parent is null?!!
          DominatorNode aParentDode = aDode.getParent();
         
          DominatorNode dode = bDode;
          while(dode != aParentDode)
          {
            dependents.add((Block)dode.getGode());
           
            //This occurs if the CFG is multi-tailed and therefore the pdom is a forest.
            if(dode.getParent() == null)
              //throw new RuntimeException("parent dode in pdom is null: dode is " + aDode);
              break;
            dode = dode.getParent();           
          }
         
          /*
           * If node A is in the dependent list of A, then A is the header of a loop.
           * Otherwise, A could still be the header of a loop or just a simple predicate.
           */
         
          //first make A's pdg node be a conditional (predicate) pdgnode, if it's not already.         
          if(pdgNodeOfA.getAttrib() != PDGNode.Attribute.CONDHEADER)
          {
            PDGNode oldA = pdgNodeOfA;
            pdgNodeOfA = new ConditionalPDGNode(pdgNodeOfA);
            this.replaceInGraph(pdgNodeOfA, oldA);
            pdgnode.removeDependent(oldA);
            this.m_obj2pdgNode.put(a, pdgNodeOfA);
            pdgnode.addDependent(pdgNodeOfA);
            pdgNodeOfA.setAttrib(PDGNode.Attribute.CONDHEADER);
           
            curNodeInRegion = pdgNodeOfA;
          }   
         
          List<Block> copyOfDependents = new ArrayList<Block>();
          copyOfDependents.addAll(dependents);
         
          //First, add the dependency for B and its corresponding region.
          Region regionOfB = block2region.get(b);
          PDGNode pdgnodeOfBRegion = null;
          if(!this.m_obj2pdgNode.containsKey(regionOfB))
          {
            pdgnodeOfBRegion = new PDGNode(regionOfB, PDGNode.Type.REGION);
            this.addNode(pdgnodeOfBRegion);
            this.m_obj2pdgNode.put(regionOfB, pdgnodeOfBRegion);
           
          }
          else
            pdgnodeOfBRegion = this.m_obj2pdgNode.get(regionOfB);
         
          //set the region hierarchy
          regionOfB.setParent(r);
          r.addChildRegion(regionOfB);
         
          //add the dependency edges
          this.addEdge(pdgNodeOfA, pdgnodeOfBRegion, "dependency");
          pdgNodeOfA.addDependent(pdgnodeOfBRegion);
          regions2process.add(regionOfB);
          //now remove b and all the nodes in the same weak region from the list of dependents
          copyOfDependents.remove(b);
          copyOfDependents.removeAll(regionOfB.getBlocks());
       
         
          /* What remains here in the dependence set needs to be processed separately. For
           * each node X remained in the dependency set, find the corresponding PDG region node
           * and add a dependency edge from the region of B to the region of X. If X's weak
           * region contains other nodes not in the dependency set of A, create a new region
           * for X and add the proper dependency edges (this actually happens if X is the header
           * of a loop and B is a predicate guarding a break/continue.)
           *
           * Note: it seems the only case that there is a node remained in the dependents is when there
           * is a path from b to the header of a loop.
           */
         
          while(!copyOfDependents.isEmpty())
          {
            Block depB = copyOfDependents.remove(0);
            Region rdepB = block2region.get(depB);
           
            /*
             * Actually, there are cases when depB is not the header of a loop and therefore would not dominate the current node
             * (A) and therefore might not have been created yet. This has happened when an inner loop breaks out of the outer
             * loop but could have other cases too.
             */
            PDGNode depBPDGNode = this.m_obj2pdgNode.get(depB);
            if(depBPDGNode == null)
            {           
              //First, add the dependency for depB and its corresponding region.
             
              PDGNode pdgnodeOfdepBRegion = null;
              if(!this.m_obj2pdgNode.containsKey(rdepB))
              {
                pdgnodeOfdepBRegion = new PDGNode(rdepB, PDGNode.Type.REGION);
                this.addNode(pdgnodeOfdepBRegion);
                this.m_obj2pdgNode.put(rdepB, pdgnodeOfdepBRegion);
               
              }
              else
                pdgnodeOfdepBRegion = this.m_obj2pdgNode.get(rdepB);
             
              //set the region hierarchy
              rdepB.setParent(regionOfB);
              regionOfB.addChildRegion(rdepB);
             
              //add the dependency edges
              this.addEdge(pdgnodeOfBRegion, pdgnodeOfdepBRegion, "dependency");
              pdgnodeOfBRegion.addDependent(pdgnodeOfdepBRegion);
              regions2process.add(rdepB);
             
              //now remove all the nodes in the same weak region from the list of dependents
             
              copyOfDependents.removeAll(rdepB.getBlocks());
             
              continue;

            }
           
            /**
             * If all the nodes in the weak region of depB are dependent on A, then add
             * an edge from the region of B to the region of depB.
             *
             * else, a new region has to be created to contain the dependences of depB, if
             * not already created.
             */
            if(dependents.containsAll(rdepB.getBlocks()))
            {
              /*
               * Just add an edge to the pdg node of the existing depB region.
               *
               */
              //add the dependency edges
              //First, add the dependency for depB and its corresponding region.
             
              PDGNode pdgnodeOfdepBRegion = null;
              if(!this.m_obj2pdgNode.containsKey(rdepB))
              {
                pdgnodeOfdepBRegion = new PDGNode(rdepB, PDGNode.Type.REGION);
                this.addNode(pdgnodeOfdepBRegion);
                this.m_obj2pdgNode.put(rdepB, pdgnodeOfdepBRegion);
               
              }
              else
                pdgnodeOfdepBRegion = this.m_obj2pdgNode.get(rdepB);
             
              //set the region hierarchy
              //Do not set this because the region was created before so must have the
              //proper parent already.
              //rdepB.setParent(regionOfB);
              //regionOfB.addChildRegion(rdepB);
             
              this.addEdge(pdgnodeOfBRegion, pdgnodeOfdepBRegion, "dependency");
              pdgnodeOfBRegion.addDependent(pdgnodeOfdepBRegion);
              regions2process.add(rdepB);
             
              //now remove all the nodes in the same weak region from the list of dependents
             
              copyOfDependents.removeAll(rdepB.getBlocks());
 
              continue;
            }
            else
            {
              PDGNode predPDGofdepB = (PDGNode) this.getPredsOf(depBPDGNode).get(0);
              assert(this.m_obj2pdgNode.containsKey(rdepB));             
              PDGNode pdgnodeOfdepBRegion = this.m_obj2pdgNode.get(rdepB);
              //If the loop header has not been separated from its weak region yet
              if(predPDGofdepB == pdgnodeOfdepBRegion)
              {
                /*
                 * Create a new region to represent the whole loop. In fact, this is a strong
                 * region as opposed to the weak regions that were created in the RegionAnalysis.
                 * This strong region only contains the header of the loop, A, and is dependent
                 * on it. Also, A is dependent on this strong region as well.
                 */
               
                Region newRegion = new Region(this.m_strongRegionStartID++, topLevelRegion.getSootMethod(), topLevelRegion.getSootClass(), this.m_cfg);
                newRegion.add(depB);
               
                this.m_strongRegions.add(newRegion);
                               
                //toBeRemoved.add(depB);
                List<Block> blocks2BRemoved;
                if(toBeRemoved.contains(predPDGofdepB))
                  blocks2BRemoved = toBeRemoved.get(predPDGofdepB);
                else
                {
                  blocks2BRemoved = new ArrayList<Block>();
                  toBeRemoved.put(rdepB, blocks2BRemoved);
                }
                blocks2BRemoved.add(depB);
               
               
               
                PDGNode newpdgnode = new LoopedPDGNode(newRegion, PDGNode.Type.REGION, depBPDGNode);
                this.addNode(newpdgnode);
                this.m_obj2pdgNode.put(newRegion, newpdgnode);
                newpdgnode.setAttrib(PDGNode.Attribute.LOOPHEADER);
                depBPDGNode.setAttrib(PDGNode.Attribute.LOOPHEADER);
               
                this.removeEdge(pdgnodeOfdepBRegion, depBPDGNode, "dependency");
                pdgnodeOfdepBRegion.removeDependent(depBPDGNode);
                this.addEdge(pdgnodeOfdepBRegion, newpdgnode, "dependency");
                this.addEdge(newpdgnode, depBPDGNode, "dependency");
                pdgnodeOfdepBRegion.addDependent(newpdgnode);
                newpdgnode.addDependent(depBPDGNode);
               
               
               
                //If a is dependent on itself (simple loop)
                if(depB == a)
                {
                  PDGNode loopBodyPDGNode = (PDGNode) this.getSuccsOf(depBPDGNode).get(0);
                  this.addEdge(depBPDGNode, newpdgnode, "dependency-back");
                  ((LoopedPDGNode)newpdgnode).setBody(loopBodyPDGNode);
                 
                  depBPDGNode.addBackDependent(newpdgnode);
                 
                  //This is needed to correctly adjust the prev/next pointers for the new loop node. We should not need
                  //to adjust the old loop header node because the prev/next should not have been set previously for it.
                  curNodeInRegion = newpdgnode;
                 
                }
                else
                {
                 
                  //this is a back-dependency
                  pdgnodeOfBRegion.addBackDependent(newpdgnode);
                  this.addEdge(pdgnodeOfBRegion, newpdgnode, "dependency-back");
                 
                  //DEtermine which dependent of the loop header is actually the loop body region
                  PDGNode loopBodyPDGNode = null;
                  List<PDGNode> successors = this.getSuccsOf(depBPDGNode);
                  Iterator<PDGNode> succItr = successors.iterator();
                  while(succItr.hasNext())
                  {
                    PDGNode succRPDGNode = succItr.next();
                   
                    assert(succRPDGNode.getType() == PDGNode.Type.REGION);
                    Region succR = (Region) succRPDGNode.getNode();
                    Block h = succR.getBlocks().get(0);
                   
                    DominatorNode hdode = dom.getDode(h);
                    DominatorNode adode = dom.getDode(a);
                   
                    if(dom.isDominatorOf(hdode, adode))
                    {
                      loopBodyPDGNode = succRPDGNode;
                      break;
                    }
                   
                  }
                  assert(loopBodyPDGNode != null);
                  ((LoopedPDGNode)newpdgnode).setBody(loopBodyPDGNode);
                 
                 
                  PDGNode prev = depBPDGNode.getPrev();
                  if(prev != null)
                  {
                    this.removeEdge(prev, depBPDGNode, "controlflow");
                    this.addEdge(prev, newpdgnode, "controlflow");
                    prev.setNext(newpdgnode);
                    newpdgnode.setPrev(prev);
                    depBPDGNode.setPrev(null);
                   
                  }
                 
                  PDGNode next = depBPDGNode.getNext();
                  if(next != null)
                  {
                    this.removeEdge(depBPDGNode, next, "controlflow");
                    this.addEdge(newpdgnode, next, "controlflow");
                    newpdgnode.setNext(next);
                    next.setPrev(newpdgnode);
                    depBPDGNode.setNext(null);
                   
                  }
                }
               
              }
              else
              {
                /*
                 * The strong region for the header has already been created and its
                 * corresponding PDGNode exist. Just add the dependency edge.
                 */
                this.addEdge(pdgnodeOfBRegion, predPDGofdepB, "dependency-back");
                //this is a back-dependency
                pdgnodeOfBRegion.addBackDependent(predPDGofdepB);
               
              }
             
            }   
           
          }
   
        } 
     
     

        /* If there is a previous node in this region, add a control flow edge to indicate the
         * the correct direction of control flow in the region.
         */
        if(prevPDGNodeInRegion != null)
        {
          this.addEdge(prevPDGNodeInRegion, curNodeInRegion, "controlflow");
          prevPDGNodeInRegion.setNext(curNodeInRegion);
          curNodeInRegion.setPrev(prevPDGNodeInRegion);
         
        }
       
        prevPDGNodeInRegion = curNodeInRegion;

      }
     
      //remove all the blocks marked to be removed from the region (to change a weak region
      //to a strong region.)
     
     
      Enumeration<Region> itr1 = toBeRemoved.keys();
      while(itr1.hasMoreElements())
      {
        Region region = itr1.nextElement();
       
        Iterator<Block> blockItr = toBeRemoved.get(region).iterator();
        while(blockItr.hasNext())
          region.remove(blockItr.next());
         
      }

    }
   
  }
 
  private List<Region> cloneRegions(List<Region> weak)
  {
    List<Region> strong = new ArrayList<Region>();
    Iterator<Region> itr = weak.iterator();
    while(itr.hasNext())
    {
      Region r = itr.next();
      strong.add((Region)r.clone());
    }
    return strong;
  }
 
  /**
   *
   * @return The Corresponding UnitGraph
   */
  public UnitGraph getCFG()
  {
    return this.m_cfg;
  }
 
  /**
   * {@inheritDoc}
   */

  public List<Region> getWeakRegions()
  {
    return this.m_weakRegions;
  }
 
  /**
   * {@inheritDoc}
   */

  public List<Region> getStrongRegions()
  {
    return this.m_strongRegions;
  }
 
  /**
   * {@inheritDoc}
   */
  public IRegion GetStartRegion()
  {
    return this.m_pdgRegions.get(0);
  }
 
  /**
   * {@inheritDoc}
   */
  public PDGNode GetStartNode()
  {
    return this.m_startNode;
  }

  public static List<IRegion> getPreorderRegionList(IRegion r)
  {
    List<IRegion> list = new ArrayList<IRegion>();

   
    Queue<IRegion> toProcess = new LinkedList<IRegion>();
    toProcess.add(r);
    while(!toProcess.isEmpty())
    {
      IRegion reg = toProcess.poll();
      list.add(reg);
      for(Iterator<IRegion> itr = reg.getChildRegions().iterator(); itr.hasNext(); )
        toProcess.add((Region)itr.next());
     
    }
   
    return list;
  }
 
  public static List<IRegion> getPostorderRegionList(IRegion r)
  {
    List<IRegion> list = new ArrayList<IRegion>();     
    postorder(r, list);
   
    return list;
  }
 
  private static List<IRegion> postorder(IRegion r, List<IRegion> list)
  {
    //If there are children, push the children to the stack
    if(!r.getChildRegions().isEmpty())
      for(Iterator<IRegion> itr = r.getChildRegions().iterator(); itr.hasNext(); )
        postorder(itr.next(), list);
   
    list.add(r);
    return list;
  }
 
  /**
   * {@inheritDoc}
   */
  public List<PDGRegion> getPDGRegions()
  {
    return this.m_pdgRegions;
  }
 
  /**
   * This method returns a list of regions obtained by post-order
   * traversal of the region hierarchy. This takes advantage of the hierarchical
   * (parent/child) information encoded within the PDGNodes at construction
   * time; it should be noted that, we have not counted the strong regions
   * that represent the loop header as a separate region; instead, a PDGRegion
   * that represents both the loop header and its body are counted.
   * @param The root from which the traversal should begin.
   * @return The list of regions obtained thru post-order traversal of the
   * region hierarchy.
   */
  public static List<PDGRegion> getPostorderPDGRegionList(PDGNode r)
  {
    return computePDGRegions(r);
   
  }
 
  private static Hashtable<PDGNode, PDGRegion> node2Region = new Hashtable<PDGNode, PDGRegion>();
  //compute the pdg region list with in post order
  private static List<PDGRegion> computePDGRegions(PDGNode root)
  {
    List<PDGRegion> regions = new ArrayList<PDGRegion>();
       
    node2Region.clear();
    pdgpostorder(root, regions);
   
    return regions;
  }
 
 
 
  private static PDGRegion pdgpostorder(PDGNode node, List<PDGRegion> list)
  {
    node.setVisited(true);
   
    PDGRegion region = null;
    if(!node2Region.containsKey(node))
    {
      region = new PDGRegion(node);
      node2Region.put(node, region);
    }
    else
      region = node2Region.get(node);
   
   
    //If there are children, push the children to the stack
    List<PDGNode> dependents = node.getDependets();
    if(!dependents.isEmpty())
      for(Iterator<PDGNode> itr = dependents.iterator(); itr.hasNext(); )
      {
        PDGNode curNode = (PDGNode) itr.next();
        if(curNode.getVisited())
          continue;
       
        region.addPDGNode(curNode);
       
        if(curNode instanceof LoopedPDGNode)
        {
          PDGNode body = ((LoopedPDGNode)curNode).getBody();
          PDGRegion kid = pdgpostorder(body, list);
          kid.setParent(region);
          region.addChildRegion(kid);
         
          //This sets the node from the old Region into a PDGRegion
          body.setNode(kid);
         
        }
        else if(curNode instanceof ConditionalPDGNode)
        {
          List<PDGNode> childs = curNode.getDependets();
          Iterator<PDGNode> condItr = childs.iterator();
          while(condItr.hasNext())
          {
            PDGNode child = (PDGNode)condItr.next();
            PDGRegion kid = pdgpostorder(child, list);
            kid.setParent(region);
            region.addChildRegion(kid);
            //This sets the node from the old Region into a PDGRegion

            child.setNode(kid);
           
          }

        }
         
      }
   
    list.add(region);
    return region;
  }
 
  /**
   * {@inheritDoc}
   */
  public boolean dependentOn(PDGNode node1, PDGNode node2)
  {
    return node2.getDependets().contains(node1);
  }
 
  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public List<PDGNode> getDependents(PDGNode node)
  {
    return this.getSuccsOf(node);
    //Or return node.getDependents();
  }
 
  /**
   * {@inheritDoc}
   */
  public PDGNode getPDGNode(Object cfgNode)
  {
    if(cfgNode != null && cfgNode instanceof Block)
      if(this.m_obj2pdgNode.containsKey(cfgNode))
        return this.m_obj2pdgNode.get(cfgNode);
   
    return null;
  }
 
  @SuppressWarnings("unchecked")
  private void replaceInGraph(PDGNode newnode, PDGNode oldnode)
  {   
    this.addNode(newnode);
   
    HashMutableEdgeLabelledDirectedGraph graph = (HashMutableEdgeLabelledDirectedGraph) this.clone();
       
    List succs = graph.getSuccsOf(oldnode);
    List preds = graph.getPredsOf(oldnode);
   
    Iterator<Object> itr = succs.iterator();
    while(itr.hasNext())
    {
      PDGNode succ = (PDGNode) itr.next();
      List<Object> labels = graph.getLabelsForEdges(oldnode, succ);
      for(Iterator<Object> labelItr = labels.iterator(); labelItr.hasNext(); )
      {
        Object label = labelItr.next();
        this.addEdge(newnode, succ, new String(label.toString()))
     
    }
     
    itr = preds.iterator();
    while(itr.hasNext())
    {
      PDGNode pred = (PDGNode) itr.next();
      List<Object> labels = graph.getLabelsForEdges(pred, oldnode);
      for(Iterator<Object> labelItr = labels.iterator(); labelItr.hasNext(); )
      {
        Object label = labelItr.next();
        this.addEdge(pred, newnode, new String(label.toString()));
      }   
    }
   
    this.removeNode(oldnode);
 
  }
  /**
   * The existing removeAllEdges in the parent class seems to be throwing concurrentmodification exception
   * most of the time. Here is a version that doesn't throw that exception.
   *
   */
    @SuppressWarnings("unchecked")
  public void removeAllEdges(Object from, Object to)
  {
        if (!containsAnyEdge(from, to))
            return;
           
        List labels = this.getLabelsForEdges(from, to);
       
        List lablesClone = new ArrayList();
        lablesClone.addAll(labels);
       
        for(Object label : lablesClone)
        {       
          this.removeEdge(from, to, label);
      }
  }

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public String toString()
  {
    String s = new String("\nProgram Dependence Graph for Method " + this.m_body.getMethod().getName());
    s += "\n*********CFG******** \n" + this.m_regionAnalysis.CFGtoString(this.m_blockCFG, true);
    s += "\n*********PDG******** \n";
   
    List<PDGNode> processed = new ArrayList<PDGNode>();
    Queue nodes = new LinkedList();
    nodes.offer(this.m_startNode);
   
    while(nodes.peek() != null)
    {
      PDGNode node = (PDGNode) nodes.remove();
      processed.add(node);
     
      s += "\n Begin PDGNode: " + node;
      List succs = this.getSuccsOf(node);
      s += "\n has " + succs.size() + " successors:\n";
     
      int i = 0;
      Iterator itr = succs.iterator();
      while(itr.hasNext())
      {
        PDGNode succ = (PDGNode)itr.next();
        List labels = this.getLabelsForEdges(node, succ);
       
        s += i++;
        s += ": Edge's label: " + labels + " \n";
        s += "   Target: " + succ.toShortString();
        s += "\n";
       
        if(labels.get(0).equals("dependency"))
        if(!processed.contains(succ))
          nodes.offer(succ);
       
      }
     
      s += "\n End PDGNode.";
     
    }
    return s;
   
  }

 
 
}
TOP

Related Classes of soot.toolkits.graph.pdg.HashMutablePDG

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.