soot.jimple.toolkits.scalar.pre.EarliestnessComputation Maven / Gradle / Ivy
Show all versions of soot Show documentation
package soot.jimple.toolkits.scalar.pre;
/*-
* #%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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import soot.EquivalentValue;
import soot.SideEffectTester;
import soot.Unit;
import soot.Value;
import soot.ValueBox;
import soot.jimple.FieldRef;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.ArraySparseSet;
import soot.toolkits.scalar.FlowSet;
/**
* Computes the earliest points for the given expressions.
* This basically finds the highest point in the flow-graph where we can put each computation, without introducing new
* computations on any path.
* More technically: A computation is earliest, if at the current point the computation is down-safe, and if either:
*
* - any of the predecessors is not transparent, or
*
- if any predecessors is not "safe" (ie. the insertion of this computation would insert it on a path, where it was not
* before).
*
*
* Intuitively: If the one predecessor is not transparent, we can't push the computation further up. If one of the
* predecessor is not safe, we would introduce a new computation on its path. Hence we can't push further up.
*
* Note that this computation is linear in the number of units, as we don't need to find any fixed-point.
*
* @see UpSafetyAnalysis
* @see DownSafetyAnalysis
*/
public class EarliestnessComputation {
private final Map> unitToEarliest;
/**
* given an UpSafetyAnalysis and a DownSafetyAnalysis, performs the earliest-computation.
*
* @param unitGraph
* the Unitgraph we'll work on.
* @param upSafe
* a UpSafetyAnalysis of unitGraph
* @param downSafe
* a DownSafetyAnalysis of unitGraph
* @param sideEffect
* the SideEffectTester that will tell if a node is transparent or not.
*/
public EarliestnessComputation(UnitGraph unitGraph, UpSafetyAnalysis upSafe, DownSafetyAnalysis downSafe,
SideEffectTester sideEffect) {
this(unitGraph, upSafe, downSafe, sideEffect, new ArraySparseSet());
}
/**
* given an UpSafetyAnalysis and a DownSafetyAnalysis, performs the earliest-computation.
* allows to share sets over multiple analyses (set-operations are usually more efficient, if the sets come from the same
* source).
*
* @param unitGraph
* the Unitgraph we'll work on.
* @param upSafe
* a UpSafetyAnalysis of unitGraph
* @param downSafe
* a DownSafetyAnalysis of unitGraph
* @param sideEffect
* the SideEffectTester that will tell if a node is transparent or not.
* @param set
* the shared set.
*/
public EarliestnessComputation(UnitGraph unitGraph, UpSafetyAnalysis upSafe, DownSafetyAnalysis downSafe,
SideEffectTester sideEffect, FlowSet set) {
this.unitToEarliest = new HashMap>(unitGraph.size() + 1, 0.7f);
for (Unit currentUnit : unitGraph) {
/* create a new Earliest-list for each unit */
FlowSet earliest = set.emptySet();
unitToEarliest.put(currentUnit, earliest);
/* get a copy of the downSafe-set at the current unit */
FlowSet downSafeSet = downSafe.getFlowBefore(currentUnit).clone();
List predList = unitGraph.getPredsOf(currentUnit);
if (predList.isEmpty()) { // no predecessor
/*
* we are obviously at the earliest position for any downsafe computation
*/
earliest.union(downSafeSet);
} else {
for (Unit predecessor : predList) {
{ /*
* if a predecessor is not transparent for a certain computation, that is downsafe here, we can't push the
* computation further up, and the earliest computation is before the current point.
*/
/*
* for each element in the downSafe-set, look if it passes through the predecessor
*/
for (Iterator downSafeIt = downSafeSet.iterator(); downSafeIt.hasNext();) {
EquivalentValue equiVal = downSafeIt.next();
Value avail = equiVal.getValue();
if (avail instanceof FieldRef) {
if (sideEffect.unitCanWriteTo(predecessor, avail)) {
earliest.add(equiVal);
downSafeIt.remove();
}
} else {
// iterate over uses in each avail.
for (ValueBox useBox : avail.getUseBoxes()) {
Value use = useBox.getValue();
if (sideEffect.unitCanWriteTo(predecessor, use)) {
earliest.add(equiVal);
downSafeIt.remove();
break;
}
}
}
}
}
{ /*
* look if one of the expressions is not upsafe and not downsafe in one of the predecessors
*/
for (Iterator downSafeIt = downSafeSet.iterator(); downSafeIt.hasNext();) {
EquivalentValue equiVal = downSafeIt.next();
FlowSet preDown = downSafe.getFlowBefore(predecessor);
FlowSet preUp = upSafe.getFlowBefore(predecessor);
if (!preDown.contains(equiVal) && !preUp.contains(equiVal)) {
earliest.add(equiVal);
downSafeIt.remove();
}
}
}
}
}
}
}
/**
* returns the FlowSet of expressions, that have their earliest computation just before node
.
*
* @param node
* a Object of the flow-graph (in our case always a Unit).
* @return a FlowSet containing the expressions.
*/
public FlowSet getFlowBefore(Object node) {
return unitToEarliest.get(node);
}
}