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

soot.toolkits.graph.BlockGraph Maven / Gradle / Ivy

package soot.toolkits.graph;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 1999 Patrice Pominville, Raja Vallee-Rai
 * %%
 * This program 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 program 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import soot.Body;
import soot.Trap;
import soot.Unit;
import soot.jimple.NopStmt;
import soot.util.Chain;

/**
 * 

* Represents the control flow graph of a {@link Body} at the basic block level. Each node of the graph is a {@link Block} * while the edges represent the flow of control from one basic block to the next. *

* *

* This is an abstract base class for different variants of {@link BlockGraph}, where the variants differ in how they analyze * the control flow between individual units (represented by passing different variants of {@link UnitGraph} to the * BlockGraph constructor) and in how they identify block leaders (represented by overriding * BlockGraph's definition of {@link computeLeaders()}. */ public abstract class BlockGraph implements DirectedGraph { protected Body mBody; protected Chain mUnits; protected List mBlocks; protected List mHeads = new ArrayList(); protected List mTails = new ArrayList(); /** * Create a BlockGraph representing at the basic block level the control flow specified, at the * Unit level, by a given {@link UnitGraph}. * * @param unitGraph * A representation of the control flow at the level of individual {@link Unit}s. */ protected BlockGraph(UnitGraph unitGraph) { mBody = unitGraph.getBody(); mUnits = mBody.getUnits(); Set leaders = computeLeaders(unitGraph); buildBlocks(leaders, unitGraph); } /** *

* Utility method for computing the basic block leaders for a {@link Body}, given its {@link UnitGraph} (i.e., the * instructions which begin new basic blocks). *

* *

* This implementation designates as basic block leaders : * *

    * *
  • Any Unit which has zero predecessors (e.g. the Unit following a return or unconditional * branch) or more than one predecessor (e.g. a merge point).
  • * *
  • Units which are the target of any branch (even if they have no other predecessors and the branch has no * other successors, which is possible for the targets of unconditional branches or degenerate conditional branches which * both branch and fall through to the same Unit).
  • * *
  • All successors of any Unit which has more than one successor (this includes the successors of * Units which may throw an exception that gets caught within the Body, as well the successors of * conditional branches).
  • * *
  • The first Unit in any Trap handler. (Strictly speaking, if unitGraph were a * ExceptionalUnitGraph that included only a single unexceptional predecessor for some handler—because * no trapped unit could possibly throw the exception that the handler catches, while the code preceding the handler fell * through to the handler's code—then you could merge the handler into the predecessor's basic block; but such * situations occur only in carefully contrived bytecode.) * *
*

* * @param unitGraph * is the Unit-level CFG which is to be split into basic blocks. * * @return the {@link Set} of {@link Unit}s in unitGraph which are block leaders. */ protected Set computeLeaders(UnitGraph unitGraph) { Body body = unitGraph.getBody(); if (body != mBody) { throw new RuntimeException("BlockGraph.computeLeaders() called with a UnitGraph that doesn't match its mBody."); } Set leaders = new HashSet(); // Trap handlers start new basic blocks, no matter how many // predecessors they have. Chain traps = body.getTraps(); for (Iterator trapIt = traps.iterator(); trapIt.hasNext();) { Trap trap = trapIt.next(); leaders.add(trap.getHandlerUnit()); } for (Iterator unitIt = body.getUnits().iterator(); unitIt.hasNext();) { Unit u = unitIt.next(); List predecessors = unitGraph.getPredsOf(u); int predCount = predecessors.size(); List successors = unitGraph.getSuccsOf(u); int succCount = successors.size(); if (predCount != 1) { // If predCount == 1 but the predecessor leaders.add(u); // is a branch, u will get added by that } // branch's successor test. if ((succCount > 1) || (u.branches())) { for (Iterator it = successors.iterator(); it.hasNext();) { leaders.add((Unit) it.next()); // The cast is an } // assertion check. } } return leaders; } /** *

* A utility method that does most of the work of constructing basic blocks, once the set of block leaders has been * determined, and which designates the heads and tails of the graph. *

* *

* BlockGraph provides an implementation of buildBlocks() which splits the {@link Unit}s in * unitGraph so that each Unit in the passed set of block leaders is the first unit in a block. * It defines as heads the blocks which begin with Units which are heads in unitGraph, and * defines as tails the blocks which end with Units which are tails in unitGraph. Subclasses * might override this behavior. * * @param leaders * Contains Units which are to be block leaders. * * @param unitGraph * Provides information about the predecessors and successors of each Unit in the Body, * for determining the predecessors and successors of each created {@link Block}. * * @return a {@link Map} from {@link Unit}s which begin or end a block to the block which contains them. */ protected Map buildBlocks(Set leaders, UnitGraph unitGraph) { List blockList = new ArrayList(leaders.size()); Map unitToBlock = new HashMap(); // Maps head // and tail // units to // their blocks, for building // predecessor and successor lists. Unit blockHead = null; int blockLength = 0; Iterator unitIt = mUnits.iterator(); if (unitIt.hasNext()) { blockHead = unitIt.next(); if (!leaders.contains(blockHead)) { throw new RuntimeException("BlockGraph: first unit not a leader!"); } blockLength++; } Unit blockTail = blockHead; int indexInMethod = 0; while (unitIt.hasNext()) { Unit u = unitIt.next(); if (leaders.contains(u)) { addBlock(blockHead, blockTail, indexInMethod, blockLength, blockList, unitToBlock); indexInMethod++; blockHead = u; blockLength = 0; } blockTail = u; blockLength++; } if (blockLength > 0) { // Add final block. addBlock(blockHead, blockTail, indexInMethod, blockLength, blockList, unitToBlock); } // The underlying UnitGraph defines heads and tails. for (Iterator it = unitGraph.getHeads().iterator(); it.hasNext();) { Unit headUnit = (Unit) it.next(); Block headBlock = unitToBlock.get(headUnit); if (headBlock.getHead() == headUnit) { mHeads.add(headBlock); } else { throw new RuntimeException("BlockGraph(): head Unit is not the first unit in the corresponding Block!"); } } for (Iterator it = unitGraph.getTails().iterator(); it.hasNext();) { Unit tailUnit = (Unit) it.next(); Block tailBlock = unitToBlock.get(tailUnit); if (tailBlock.getTail() == tailUnit) { mTails.add(tailBlock); } else { throw new RuntimeException("BlockGraph(): tail Unit is not the last unit in the corresponding Block!"); } } for (Iterator blockIt = blockList.iterator(); blockIt.hasNext();) { Block block = blockIt.next(); List predUnits = unitGraph.getPredsOf(block.getHead()); List predBlocks = new ArrayList(predUnits.size()); for (Iterator predIt = predUnits.iterator(); predIt.hasNext();) { Unit predUnit = predIt.next(); Block predBlock = unitToBlock.get(predUnit); if (predBlock == null) { throw new RuntimeException("BlockGraph(): block head mapped to null block!"); } predBlocks.add(predBlock); } if (predBlocks.size() == 0) { block.setPreds(Collections.emptyList()); // If the UnreachableCodeEliminator is not eliminating // unreachable handlers, then they will have no // predecessors, yet not be heads. /* * if (! mHeads.contains(block)) { throw new RuntimeException("Block with no predecessors is not a head!" ); * * // Note that a block can be a head even if it has // predecessors: a handler that might catch an exception // * thrown by the first Unit in the method. } */ } else { block.setPreds(Collections.unmodifiableList(predBlocks)); if (block.getHead() == mUnits.getFirst()) { mHeads.add(block); // Make the first block a head // even if the Body is one huge loop. } } List succUnits = unitGraph.getSuccsOf(block.getTail()); List succBlocks = new ArrayList(succUnits.size()); for (Iterator succIt = succUnits.iterator(); succIt.hasNext();) { Unit succUnit = succIt.next(); Block succBlock = unitToBlock.get(succUnit); if (succBlock == null) { throw new RuntimeException("BlockGraph(): block tail mapped to null block!"); } succBlocks.add(succBlock); } if (succBlocks.size() == 0) { block.setSuccs(Collections.emptyList()); if (!mTails.contains(block)) { // if this block is totally empty and unreachable, we remove it if (block.getPreds().isEmpty() && block.getHead() == block.getTail() && block.getHead() instanceof NopStmt) { blockIt.remove(); } else { throw new RuntimeException("Block with no successors is not a tail!: " + block.toString()); // Note that a block can be a tail even if it has // successors: a return that throws a caught exception. } } } else { block.setSuccs(Collections.unmodifiableList(succBlocks)); } } mBlocks = Collections.unmodifiableList(blockList); mHeads = Collections.unmodifiableList(mHeads); if (mTails.size() == 0) { mTails = Collections.emptyList(); } else { mTails = Collections.unmodifiableList(mTails); } return unitToBlock; } /** * A utility method which creates a new block and adds information about it to data structures used to build the graph. * * @param head * The first unit in the block. * @param tail * The last unit in the block. * @param index * The index of this block this {@link Body}. * @param length * The number of units in this block. * @param blockList * The list of blocks for this method. addBlock() will add the newly created block to this list. * @param unitToBlock * A map from units to blocks. addBlock() will add mappings from head and * tail to the new block */ private void addBlock(Unit head, Unit tail, int index, int length, List blockList, Map unitToBlock) { Block block = new Block(head, tail, mBody, index, length, this); blockList.add(block); unitToBlock.put(tail, block); unitToBlock.put(head, block); } /** * Returns the {@link Body} this {@link BlockGraph} is derived from. * * @return The {@link Body} this {@link BlockGraph} is derived from. */ public Body getBody() { return mBody; } /** * Returns a list of the Blocks composing this graph. * * @return A list of the blocks composing this graph in the same order as they partition underlying Body instance's unit * chain. * @see Block */ public List getBlocks() { return mBlocks; } public String toString() { Iterator it = mBlocks.iterator(); StringBuffer buf = new StringBuffer(); while (it.hasNext()) { Block someBlock = it.next(); buf.append(someBlock.toString() + '\n'); } return buf.toString(); } /* DirectedGraph implementation */ public List getHeads() { return mHeads; } public List getTails() { return mTails; } public List getPredsOf(Block b) { return b.getPreds(); } public List getSuccsOf(Block b) { return b.getSuccs(); } public int size() { return mBlocks.size(); } public Iterator iterator() { return mBlocks.iterator(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy