soot.jimple.toolkits.graph.CriticalEdgeRemover Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
The newest version!
package soot.jimple.toolkits.graph;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2002 Florian Loitsch
* %%
* 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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import soot.Body;
import soot.BodyTransformer;
import soot.G;
import soot.Singletons;
import soot.Unit;
import soot.UnitBox;
import soot.jimple.Jimple;
import soot.options.Options;
import soot.util.Chain;
/**
* removes all critical edges.
* A critical edge is an edge from Block A to block B, if B has more than one predecessor and A has more the one successor.
*
* As an example: If we wanted a computation to be only on the path A->B this computation must be directly on the edge.
* Otherwise it is either executed on the path through the second predecessor of A or throught the second successor of B.
* Our critical edge-remover overcomes this problem by introducing synthetic nodes on this critical edges.
* Exceptions will be ignored.
*/
public class CriticalEdgeRemover extends BodyTransformer {
private static final Logger logger = LoggerFactory.getLogger(CriticalEdgeRemover.class);
public CriticalEdgeRemover(Singletons.Global g) {
}
public static CriticalEdgeRemover v() {
return G.v().soot_jimple_toolkits_graph_CriticalEdgeRemover();
}
/**
* performs critical edge-removing.
*/
@Override
protected void internalTransform(Body b, String phaseName, Map options) {
if (Options.v().verbose()) {
logger.debug("[" + b.getMethod().getName() + "] Removing Critical Edges...");
}
removeCriticalEdges(b);
if (Options.v().verbose()) {
logger.debug("[" + b.getMethod().getName() + "] Removing Critical Edges done.");
}
}
/**
* inserts a JimpleGoto
to target, directly after
* node
in the given unitChain
.
* As we use JGoto
the chain must contain Jimple-stmts.
*
* @param unitChain
* the Chain where we will insert the Goto
.
* @param node
* the Goto
will be inserted just after this node.
* @param target
* is the Unit the goto
will jump to.
* @return the newly inserted Goto
*/
private static Unit insertGotoAfter(Chain unitChain, Unit node, Unit target) {
Unit newGoto = Jimple.v().newGotoStmt(target);
unitChain.insertAfter(newGoto, node);
return newGoto;
}
/**
* inserts a JimpleGoto
to target, directly before
* node
in the given unitChain
.
* As we use JGoto
the chain must contain Jimple-stmts.
*
* @param unitChain
* the Chain where we will insert the Goto
.
* @param node
* the Goto
will be inserted just before this node.
* @param target
* is the Unit the goto
will jump to.
* @return the newly inserted Goto
*/
/* note, that this method has slightly more overhead than the insertGotoAfter */
private static Unit insertGotoBefore(Chain unitChain, Unit node, Unit target) {
Unit newGoto = Jimple.v().newGotoStmt(target);
unitChain.insertBefore(newGoto, node);
newGoto.redirectJumpsToThisTo(node);
return newGoto;
}
/**
* takes node
and redirects all branches to oldTarget
to newTarget
.
*
* @param node
* the Unit where we redirect
* @param oldTarget
* @param newTarget
*/
private static void redirectBranch(Unit node, Unit oldTarget, Unit newTarget) {
for (UnitBox targetBox : node.getUnitBoxes()) {
if (targetBox.getUnit() == oldTarget) {
targetBox.setUnit(newTarget);
}
}
}
/**
* Splits critical edges by introducing synthetic nodes.
* This method will modify the UnitGraph
of the body. Synthetic nodes are always JGoto
s.
* Therefore the body must be in Jimple.
* As a side-effect, after the transformation, the direct predecessor of a block/node with multiple predecessors will will
* not fall through anymore. This simplifies the algorithm and is nice to work with afterwards.
*
* Note, that critical edges can only appear on edges between blocks!. Our algorithm will *not* take into account
* exceptions. (this is nearly impossible anyways)
*
* @param b
* the Jimple-body that will be physicly modified so that there are no critical edges anymore.
*/
private void removeCriticalEdges(Body b) {
final Chain unitChain = b.getUnits();
final Map> predecessors = new HashMap>(2 * unitChain.size() + 1, 0.7f);
// First get the predecessors of each node (although direct predecessors are
// predecessors too, we'll not include them in the lists)
for (Iterator unitIt = unitChain.snapshotIterator(); unitIt.hasNext();) {
Unit currentUnit = unitIt.next();
for (UnitBox ub : currentUnit.getUnitBoxes()) {
Unit target = ub.getUnit();
List predList = predecessors.get(target);
if (predList == null) {
predecessors.put(target, predList = new ArrayList());
}
predList.add(currentUnit);
}
}
{
// for each node: if we have more than two predecessors, split these edges
// if the node at the other end has more than one successor.
Unit currentUnit = null;
for (Iterator unitIt = unitChain.snapshotIterator(); unitIt.hasNext();) {
Unit directPredecessor = currentUnit;
currentUnit = unitIt.next();
List predList = predecessors.get(currentUnit);
int nbPreds = (predList == null) ? 0 : predList.size();
if (directPredecessor != null && directPredecessor.fallsThrough()) {
nbPreds++;
}
if (nbPreds >= 2) {
assert (predList != null);
// redirect the directPredecessor (if it falls through), so we can easily insert the synthetic nodes. This
// redirection might not be necessary, but is pleasant anyways (see the Javadoc for this method)
if (directPredecessor != null && directPredecessor.fallsThrough()) {
directPredecessor = insertGotoAfter(unitChain, directPredecessor, currentUnit);
}
// if the predecessors have more than one successor insert the synthetic node.
for (Unit predecessor : predList) {
// Although in Jimple there should be only two ways of having more
// than one successor (If and Case) we'll do it the hard way :)
int nbSuccs = predecessor.getUnitBoxes().size() + (predecessor.fallsThrough() ? 1 : 0);
if (nbSuccs >= 2) {
// insert synthetic node (insertGotoAfter should be slightly faster)
if (directPredecessor == null) {
directPredecessor = insertGotoBefore(unitChain, currentUnit, currentUnit);
} else {
directPredecessor = insertGotoAfter(unitChain, directPredecessor, currentUnit);
}
// update the branch
redirectBranch(predecessor, currentUnit, directPredecessor);
}
}
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy