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

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

There is a newer version: 1.12.0
Show newest version
/* Soot - a J*va Optimization Framework
 * Copyright (C) 1999 Patrice Pominville, 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-2003.  
 * See the 'credits' file distributed with Soot for the complete list of
 * contributors.  (Soot is distributed at http://www.sable.mcgill.ca/soot)
 */


package soot.toolkits.graph;

import java.util.*;

import soot.*;
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)) { 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