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

soot.toolkits.graph.UnitGraph 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.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import soot.Body;
import soot.SootMethod;
import soot.Unit;
import soot.UnitBox;
import soot.options.Options;
import soot.util.Chain;

/**
 * 

* Represents a CFG where the nodes are {@link Unit} instances and edges represent unexceptional and (possibly) exceptional * control flow between Units. *

* *

* This is an abstract class, providing the facilities used to build CFGs for specific purposes. *

*/ public abstract class UnitGraph implements DirectedGraph { private static final Logger logger = LoggerFactory.getLogger(UnitGraph.class); protected List heads; protected List tails; protected Map> unitToSuccs; protected Map> unitToPreds; protected SootMethod method; protected Body body; protected Chain unitChain; /** * Performs the work that is required to construct any sort of UnitGraph. * * @param body * The body of the method for which to construct a control flow graph. */ protected UnitGraph(Body body) { this.body = body; unitChain = body.getUnits(); method = body.getMethod(); if (Options.v().verbose()) { logger.debug("[" + method.getName() + "] Constructing " + this.getClass().getName() + "..."); } } /** * Utility method for UnitGraph constructors. It computes the edges corresponding to unexceptional control flow. * * @param unitToSuccs * A {@link Map} from {@link Unit}s to {@link List}s of {@link Unit}s. This is an ``out parameter''; callers must * pass an empty {@link Map}. buildUnexceptionalEdges will add a mapping for every Unit in the * body to a list of its unexceptional successors. * * @param unitToPreds * A {@link Map} from {@link Unit}s to {@link List}s of {@link Unit}s. This is an ``out parameter''; callers must * pass an empty {@link Map}. buildUnexceptionalEdges will add a mapping for every Unit in the * body to a list of its unexceptional predecessors. */ protected void buildUnexceptionalEdges(Map> unitToSuccs, Map> unitToPreds) { Iterator unitIt = unitChain.iterator(); Unit currentUnit, nextUnit; nextUnit = unitIt.hasNext() ? (Unit) unitIt.next() : null; while (nextUnit != null) { currentUnit = nextUnit; nextUnit = unitIt.hasNext() ? (Unit) unitIt.next() : null; ArrayList successors = new ArrayList(); if (currentUnit.fallsThrough()) { // Add the next unit as the successor if (nextUnit != null) { successors.add(nextUnit); List preds = unitToPreds.get(nextUnit); if (preds == null) { preds = new ArrayList(); unitToPreds.put(nextUnit, preds); } preds.add(currentUnit); } } if (currentUnit.branches()) { for (UnitBox targetBox : currentUnit.getUnitBoxes()) { Unit target = targetBox.getUnit(); // Arbitrary bytecode can branch to the same // target it falls through to, so we screen for duplicates: if (!successors.contains(target)) { successors.add(target); List preds = unitToPreds.get(target); if (preds == null) { preds = new ArrayList(); unitToPreds.put(target, preds); } preds.add(currentUnit); } } } // Store away successors if (!successors.isEmpty()) { successors.trimToSize(); unitToSuccs.put(currentUnit, successors); } } } /** *

* Utility method used in the construction of {@link UnitGraph}s, to be called only after the unitToPreds and unitToSuccs * maps have been built. *

* *

* UnitGraph provides an implementation of buildHeadsAndTails() which defines the graph's set of * heads to include the first {@link Unit} in the graph's body, together with any other Unit which has no * predecessors. It defines the graph's set of tails to include all Units with no successors. Subclasses of * UnitGraph may override this method to change the criteria for classifying a node as a head or tail. *

*/ protected void buildHeadsAndTails() { tails = new ArrayList(); heads = new ArrayList(); for (Unit s : unitChain) { List succs = unitToSuccs.get(s); if (succs == null || succs.isEmpty()) { tails.add(s); } List preds = unitToPreds.get(s); if (preds == null || preds.isEmpty()) { heads.add(s); } } // Add the first Unit, even if it is the target of // a branch. if (!unitChain.isEmpty()) { Unit entryPoint = unitChain.getFirst(); if (!heads.contains(entryPoint)) { heads.add(entryPoint); } } } /** * Utility method that produces a new map from the {@link Unit}s of this graph's body to the union of the values stored in * the two argument {@link Map}s, used to combine the maps of exceptional and unexceptional predecessors and successors * into maps of all predecessors and successors. The values stored in both argument maps must be {@link List}s of * {@link Unit}s, which are assumed not to contain any duplicate Units. * * @param mapA * The first map to be combined. * * @param mapB * The second map to be combined. */ protected Map> combineMapValues(Map> mapA, Map> mapB) { // The duplicate screen Map> result = new HashMap>(mapA.size() * 2 + 1, 0.7f); for (Unit unit : unitChain) { List listA = mapA.get(unit); if (listA == null) { listA = Collections.emptyList(); } List listB = mapB.get(unit); if (listB == null) { listB = Collections.emptyList(); } int resultSize = listA.size() + listB.size(); if (resultSize == 0) { result.put(unit, Collections.emptyList()); } else { List resultList = new ArrayList(resultSize); List list = null; // As a minor optimization of the duplicate screening, // copy the longer list first. if (listA.size() >= listB.size()) { resultList.addAll(listA); list = listB; } else { resultList.addAll(listB); list = listA; } for (Unit element : list) { // It is possible for there to be both an exceptional // and an unexceptional edge connecting two Units // (though probably not in a class generated by // javac), so we need to screen for duplicates. On the // other hand, we expect most of these lists to have // only one or two elements, so it doesn't seem worth // the cost to build a Set to do the screening. if (!resultList.contains(element)) { resultList.add(element); } } result.put(unit, resultList); } } return result; } /** * Utility method for adding an edge to maps representing the CFG. * * @param unitToSuccs * The {@link Map} from {@link Unit}s to {@link List}s of their successors. * * @param unitToPreds * The {@link Map} from {@link Unit}s to {@link List}s of their successors. * * @param head * The {@link Unit} from which the edge starts. * * @param tail * The {@link Unit} to which the edge flows. */ protected void addEdge(Map> unitToSuccs, Map> unitToPreds, Unit head, Unit tail) { List headsSuccs = unitToSuccs.get(head); if (headsSuccs == null) { headsSuccs = new ArrayList(3); // We expect this list to // remain short. unitToSuccs.put(head, headsSuccs); } if (!headsSuccs.contains(tail)) { headsSuccs.add(tail); List tailsPreds = unitToPreds.get(tail); if (tailsPreds == null) { tailsPreds = new ArrayList(); unitToPreds.put(tail, tailsPreds); } tailsPreds.add(head); } } /** * @return The body from which this UnitGraph was built. * * @see Body */ public Body getBody() { return body; } /** * Look for a path in graph, from def to use. This path has to lie inside an extended basic block (and this property * implies uniqueness.). The path returned includes from and to. * * @param from * start point for the path. * @param to * end point for the path. * @return null if there is no such path. */ public List getExtendedBasicBlockPathBetween(Unit from, Unit to) { UnitGraph g = this; // if this holds, we're doomed to failure!!! if (g.getPredsOf(to).size() > 1) { return null; } // pathStack := list of succs lists // pathStackIndex := last visited index in pathStack LinkedList pathStack = new LinkedList(); LinkedList pathStackIndex = new LinkedList(); pathStack.add(from); pathStackIndex.add(new Integer(0)); int psiMax = (g.getSuccsOf(pathStack.get(0))).size(); int level = 0; while (pathStackIndex.get(0).intValue() != psiMax) { int p = (pathStackIndex.get(level)).intValue(); List succs = g.getSuccsOf((pathStack.get(level))); if (p >= succs.size()) { // no more succs - backtrack to previous level. pathStack.remove(level); pathStackIndex.remove(level); level--; int q = pathStackIndex.get(level).intValue(); pathStackIndex.set(level, new Integer(q + 1)); continue; } Unit betweenUnit = (Unit) (succs.get(p)); // we win! if (betweenUnit == to) { pathStack.add(to); return pathStack; } // check preds of betweenUnit to see if we should visit its kids. if (g.getPredsOf(betweenUnit).size() > 1) { pathStackIndex.set(level, new Integer(p + 1)); continue; } // visit kids of betweenUnit. level++; pathStackIndex.add(new Integer(0)); pathStack.add(betweenUnit); } return null; } /* DirectedGraph implementation */ public List getHeads() { return heads; } public List getTails() { return tails; } public List getPredsOf(Unit u) { List l = unitToPreds.get(u); if (l == null) { return Collections.emptyList(); } return l; } public List getSuccsOf(Unit u) { List l = unitToSuccs.get(u); if (l == null) { return Collections.emptyList(); } return l; } public int size() { return unitChain.size(); } public Iterator iterator() { return unitChain.iterator(); } public String toString() { StringBuilder buf = new StringBuilder(); for (Unit u : unitChain) { buf.append("// preds: ").append(getPredsOf(u)).append('\n'); buf.append(u).append('\n'); buf.append("// succs ").append(getSuccsOf(u)).append('\n'); } return buf.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy