Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package soot.shimple.internal;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2003 Navindra Umanee
* %%
* 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.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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import soot.Body;
import soot.TrapManager;
import soot.Unit;
import soot.UnitBox;
import soot.UnitPatchingChain;
import soot.options.Options;
import soot.shimple.PhiExpr;
import soot.shimple.Shimple;
import soot.shimple.ShimpleBody;
import soot.util.Chain;
import soot.util.HashMultiMap;
import soot.util.MultiMap;
/**
* Internal Shimple extension of PatchingChain.
*
* @author Navindra Umanee
* @see soot.PatchingChain
**/
public class SPatchingChain extends UnitPatchingChain {
private static final Logger logger = LoggerFactory.getLogger(SPatchingChain.class);
/**
* Needed to find non-trapped Units of the body.
**/
Body body = null;
boolean debug;
public SPatchingChain(Body aBody, Chain aChain) {
super(aChain);
this.body = aBody;
this.debug = Options.v().debug();
if (aBody instanceof ShimpleBody) {
debug |= ((ShimpleBody) aBody).getOptions().debug();
}
}
@Override
public boolean add(Unit o) {
processPhiNode(o);
return super.add(o);
}
@Override
public void swapWith(Unit out, Unit in) {
// Ensure that branching statements are swapped correctly.
// The normal swapWith implementation would still work
// correctly but redirectToPreds performed during the remove
// would be more expensive and might print warnings if no
// actual CFG predecessors for out was found due to the
// insertion of branching statement in.
processPhiNode(in);
Shimple.redirectPointers(out, in);
super.insertBefore(in, out);
super.remove(out);
}
@Override
public void insertAfter(Unit toInsert, Unit point) {
// important to do these before the patching, so that
// computeNeedsPatching works properly
processPhiNode(toInsert);
super.insertAfter(toInsert, point);
Unit unit = point;
// update any pointers from Phi nodes only if the unit
// being inserted is in the same basic block as point, or if
// control flows through to the Phi node
patchpointers: {
// no need to move the pointers
if (!unit.fallsThrough()) {
break patchpointers;
}
// move pointers unconditionally, needed as a special case
if (!unit.branches()) {
Set trappedUnits = Collections.emptySet();
if (body != null) {
trappedUnits = TrapManager.getTrappedUnitsOf(body);
}
if (!trappedUnits.contains(unit)) {
Shimple.redirectPointers(unit, toInsert);
break patchpointers;
}
}
/* handle each UnitBox individually */
UnitBox[] boxes = unit.getBoxesPointingToThis().toArray(new UnitBox[0]);
for (UnitBox ub : boxes) {
if (ub.getUnit() != unit) {
throw new RuntimeException("Assertion failed.");
}
if (ub.isBranchTarget()) {
continue;
}
SUnitBox box = getSBox(ub);
Boolean needsPatching = boxToNeedsPatching.get(box);
if (needsPatching == null || box.isUnitChanged()) {
// if boxes were added or removed to the known Phi
if (!boxToPhiNode.containsKey(box)) {
reprocessPhiNodes();
// *** FIXME: Disabling this allows us to have
// PiExpr that have UnitBox pointers.
// I think this means that any changes
// to the relevant Unit will be ignored by
// SPatchingChain.
//
// Hopefully this also means that any
// transformation that moves/removes/modifies
// a Unit pointed at by a PiExpr knows what
// it's doing.
if (!boxToPhiNode.containsKey(box) && debug) {
throw new RuntimeException("SPatchingChain has pointers from a Phi node that has never been seen.");
}
}
computeNeedsPatching();
needsPatching = boxToNeedsPatching.get(box);
if (needsPatching == null) {
// maybe the user forgot to clearUnitBoxes()
// when removing a Phi node, or the user removed
// a Phi node and hasn't put it back yet
if (debug) {
logger.warn("Orphaned UnitBox to " + unit + "? SPatchingChain will not move the pointer.");
}
continue;
}
}
if (needsPatching) {
box.setUnit(toInsert);
box.setUnitChanged(false);
}
}
}
}
@Override
public void insertAfter(List toInsert, Unit point) {
for (Unit unit : toInsert) {
processPhiNode(unit);
}
super.insertAfter(toInsert, point);
}
@Override
public void insertBefore(List toInsert, Unit point) {
for (Unit unit : toInsert) {
processPhiNode(unit);
}
super.insertBefore(toInsert, point);
}
@Override
public void insertBefore(Unit toInsert, Unit point) {
processPhiNode(toInsert);
super.insertBefore(toInsert, point);
}
@Override
public void addFirst(Unit u) {
processPhiNode(u);
super.addFirst(u);
}
@Override
public void addLast(Unit u) {
processPhiNode(u);
super.addLast(u);
}
public boolean remove(Unit obj) {
if (contains(obj)) {
Shimple.redirectToPreds(body, obj);
}
return super.remove(obj);
}
/**
* Map from UnitBox to the Phi node owning it.
**/
protected Map boxToPhiNode = new HashMap();
/**
* Set of the values of boxToPhiNode. Used to allow O(1) contains() on the values.
**/
protected Set phiNodeSet = new HashSet();
/**
* Flag that indicates whether control flow falls through from the box to the Phi node. null indicates we probably need a
* call to computeInternal().
**/
protected Map boxToNeedsPatching = new HashMap();
protected void processPhiNode(Unit o) {
Unit phiNode = o;
PhiExpr phi = Shimple.getPhiExpr(phiNode);
// not a Phi node
if (phi == null) {
return;
}
// already processed previously, unit chain manipulations?
if (phiNodeSet.contains(phiNode)) {
return;
}
for (UnitBox box : phi.getUnitBoxes()) {
boxToPhiNode.put(box, phiNode);
phiNodeSet.add(phiNode);
}
}
protected void reprocessPhiNodes() {
Set phiNodes = new HashSet(boxToPhiNode.values());
boxToPhiNode = new HashMap();
phiNodeSet = new HashSet();
boxToNeedsPatching = new HashMap();
Iterator phiNodesIt = phiNodes.iterator();
while (phiNodesIt.hasNext()) {
processPhiNode(phiNodesIt.next());
}
}
/**
* NOTE: This will *miss* all the Phi nodes outside a chain. So make sure you know what you are doing if you remove a Phi
* node from a chain and don't put it back or call clearUnitBoxes() on it.
**/
protected void computeNeedsPatching() {
{
Set boxes = boxToPhiNode.keySet();
if (boxes.isEmpty()) {
return;
}
}
// we track the fallthrough control flow from boxes to the
// corresponding Phi statements. trackedPhi provides a
// mapping from the Phi being tracked to its relevant boxes.
MultiMap trackedPhiToBoxes = new HashMultiMap();
// consider:
//
// if blah goto label1
// label1:
//
// Here control flow both fallsthrough and branches to label1.
// If such an if statement is encountered, we do not want to
// move any UnitBox pointers beyond the if statement.
Set trackedBranchTargets = new HashSet();
for (Unit u : this) {
// update trackedPhiToBoxes
List boxesToTrack = u.getBoxesPointingToThis();
if (boxesToTrack != null) {
for (UnitBox boxToTrack : boxesToTrack) {
if (!boxToTrack.isBranchTarget()) {
trackedPhiToBoxes.put(boxToPhiNode.get(boxToTrack), boxToTrack);
}
}
}
// update trackedBranchTargets
if (u.fallsThrough() && u.branches()) {
trackedBranchTargets.addAll(u.getUnitBoxes());
}
// the tracked Phi nodes may be reached through branching.
// (note: if u is a Phi node and not a trackedBranchTarget,
// this is not triggered since u would fall through in that
// case.)
if (!u.fallsThrough() || trackedBranchTargets.contains(u)) {
Iterator boxesIt = trackedPhiToBoxes.values().iterator();
while (boxesIt.hasNext()) {
SUnitBox box = getSBox(boxesIt.next());
boxToNeedsPatching.put(box, Boolean.FALSE);
box.setUnitChanged(false);
}
trackedPhiToBoxes = new HashMultiMap();
continue;
}
// we found one of the Phi nodes pointing to a Unit
Set boxes = trackedPhiToBoxes.get(u);
if (boxes != null) {
for (UnitBox ub : boxes) {
SUnitBox box = getSBox(ub);
// falls through
boxToNeedsPatching.put(box, Boolean.TRUE);
box.setUnitChanged(false);
}
trackedPhiToBoxes.remove(u);
}
}
// after the iteration, the rest do not fall through
Iterator boxesIt = trackedPhiToBoxes.values().iterator();
while (boxesIt.hasNext()) {
SUnitBox box = getSBox(boxesIt.next());
boxToNeedsPatching.put(box, Boolean.FALSE);
box.setUnitChanged(false);
}
}
protected SUnitBox getSBox(UnitBox box) {
if (!(box instanceof SUnitBox)) {
throw new RuntimeException("Shimple box not an SUnitBox?");
}
return (SUnitBox) box;
}
protected class SPatchingIterator extends PatchingIterator {
SPatchingIterator(Chain innerChain) {
super(innerChain);
}
SPatchingIterator(Chain innerChain, Unit u) {
super(innerChain, u);
}
SPatchingIterator(Chain innerChain, Unit head, Unit tail) {
super(innerChain, head, tail);
}
@Override
public void remove() {
Unit victim = lastObject;
if (!state) {
throw new IllegalStateException("remove called before first next() call");
}
Shimple.redirectToPreds(SPatchingChain.this.body, victim);
// work around for inadequate inner class support in javac 1.2
// super.remove();
Unit successor;
if ((successor = getSuccOf(victim)) == null) {
successor = getPredOf(victim);
}
innerIterator.remove();
victim.redirectJumpsToThisTo(successor);
}
}
@Override
public Iterator iterator() {
return new SPatchingIterator(innerChain);
}
@Override
public Iterator iterator(Unit u) {
return new SPatchingIterator(innerChain, u);
}
@Override
public Iterator iterator(Unit head, Unit tail) {
return new SPatchingIterator(innerChain, head, tail);
}
}