use of soot.UnitBox in project soot by Sable.
the class Shimple method redirectToPreds.
/**
* If you are removing a Unit from a Unit chain which contains
* PhiExpr's, you might want to call this utility function in
* order to update any PhiExpr pointers to the Unit to point to
* the Unit's predecessor(s). This function will not modify
* "branch target" UnitBoxes.
*
* <p> Normally you should not have to call this function
* directly, since patching is taken care of Shimple's internal
* implementation of PatchingChain.
*/
public static void redirectToPreds(Body body, Unit remove) {
boolean debug = Options.v().debug();
if (body instanceof ShimpleBody)
debug |= ((ShimpleBody) body).getOptions().debug();
Chain<Unit> units = body.getUnits();
/* Determine whether we should continue processing or not. */
List<UnitBox> boxesPointingToThis = remove.getBoxesPointingToThis();
if (boxesPointingToThis.isEmpty())
return;
for (UnitBox pointer : boxesPointingToThis) {
// continue iteration from where we left off.
if (!pointer.isBranchTarget())
break;
}
/* Ok, continuing... */
Set<Unit> preds = new HashSet<Unit>();
Set<PhiExpr> phis = new HashSet<PhiExpr>();
// find fall-through pred
if (!remove.equals(units.getFirst())) {
Unit possiblePred = (Unit) units.getPredOf(remove);
if (possiblePred.fallsThrough())
preds.add(possiblePred);
}
// find the rest of the preds and all Phi's that point to remove
for (Unit unit : units) {
for (UnitBox targetBox : unit.getUnitBoxes()) {
if (remove.equals(targetBox.getUnit())) {
if (targetBox.isBranchTarget())
preds.add(unit);
else {
PhiExpr phiExpr = Shimple.getPhiExpr(unit);
if (phiExpr != null)
phis.add(phiExpr);
}
}
}
}
if (phis.size() == 0) {
if (debug)
logger.warn("Orphaned UnitBoxes to " + remove + "? Shimple.redirectToPreds is giving up.");
return;
}
if (preds.size() == 0) {
if (debug)
logger.warn("Shimple.redirectToPreds couldn't find any predecessors for " + remove + " in " + body.getMethod() + ".");
if (!remove.equals(units.getFirst())) {
Unit pred = (Unit) units.getPredOf(remove);
if (debug)
logger.warn("Falling back to immediate chain predecessor: " + pred + ".");
preds.add(pred);
} else if (!remove.equals(units.getLast())) {
Unit succ = (Unit) units.getSuccOf(remove);
if (debug)
logger.warn("Falling back to immediate chain successor: " + succ + ".");
preds.add(succ);
} else
throw new RuntimeException("Assertion failed.");
}
/* At this point we have found all the preds and relevant Phi's */
/* Each Phi needs an argument for each pred. */
Iterator<PhiExpr> phiIt = phis.iterator();
while (phiIt.hasNext()) {
PhiExpr phiExpr = phiIt.next();
ValueUnitPair argBox = phiExpr.getArgBox(remove);
if (argBox == null)
throw new RuntimeException("Assertion failed.");
// now we've got the value!
Value arg = argBox.getValue();
phiExpr.removeArg(argBox);
// add new arguments to Phi
Iterator<Unit> predsIt = preds.iterator();
while (predsIt.hasNext()) {
Unit pred = predsIt.next();
phiExpr.addArg(arg, pred);
}
}
}
use of soot.UnitBox in project soot by Sable.
the class BafASMBackend method generateMethodBody.
/*
* (non-Javadoc)
*
* @see soot.AbstractASMBackend#generateMethodBody(org.objectweb.asm.
* MethodVisitor, soot.SootMethod)
*/
@Override
protected void generateMethodBody(MethodVisitor mv, SootMethod method) {
BafBody body = getBafBody(method);
Chain<Unit> instructions = body.getUnits();
/*
* Create a label for each instruction that is the target of some branch
*/
for (UnitBox box : body.getUnitBoxes(true)) {
Unit u = box.getUnit();
if (!branchTargetLabels.containsKey(u)) {
branchTargetLabels.put(u, new Label());
}
}
Label startLabel = null;
if (Options.v().write_local_annotations()) {
startLabel = new Label();
mv.visitLabel(startLabel);
}
/*
* Handle all TRY-CATCH-blocks
*/
for (Trap trap : body.getTraps()) {
// Check if the try-block contains any statement
if (trap.getBeginUnit() != trap.getEndUnit()) {
Label start = branchTargetLabels.get(trap.getBeginUnit());
Label end = branchTargetLabels.get(trap.getEndUnit());
Label handler = branchTargetLabels.get(trap.getHandlerUnit());
String type = slashify(trap.getException().getName());
mv.visitTryCatchBlock(start, end, handler, type);
}
}
/*
* Handle local variable slots for the "this"-local and the parameters
*/
int localCount = 0;
int[] paramSlots = new int[method.getParameterCount()];
Set<Local> assignedLocals = new HashSet<Local>();
/*
* For non-static methods the first parameters and zero-slot is the
* "this"-local
*/
if (!method.isStatic()) {
++localCount;
}
for (int i = 0; i < method.getParameterCount(); ++i) {
paramSlots[i] = localCount;
localCount += sizeOfType(method.getParameterType(i));
}
for (Unit u : instructions) {
if (u instanceof IdentityInst && ((IdentityInst) u).getLeftOp() instanceof Local) {
Local l = (Local) ((IdentityInst) u).getLeftOp();
IdentityRef identity = (IdentityRef) ((IdentityInst) u).getRightOp();
int slot = 0;
if (identity instanceof ThisRef) {
if (method.isStatic())
throw new RuntimeException("Attempting to use 'this' in static method");
} else if (identity instanceof ParameterRef)
slot = paramSlots[((ParameterRef) identity).getIndex()];
else {
// Exception ref. Skip over this
continue;
}
localToSlot.put(l, slot);
assignedLocals.add(l);
}
}
for (Local local : body.getLocals()) {
if (assignedLocals.add(local)) {
localToSlot.put(local, localCount);
localCount += sizeOfType(local.getType());
}
}
// Generate the code
for (Unit u : instructions) {
if (branchTargetLabels.containsKey(u)) {
mv.visitLabel(branchTargetLabels.get(u));
}
if (u.hasTag("LineNumberTag")) {
LineNumberTag lnt = (LineNumberTag) u.getTag("LineNumberTag");
Label l;
if (branchTargetLabels.containsKey(u)) {
l = branchTargetLabels.get(u);
} else {
l = new Label();
mv.visitLabel(l);
}
mv.visitLineNumber(lnt.getLineNumber(), l);
}
generateInstruction(mv, (Inst) u);
}
// Generate the local annotations
if (Options.v().write_local_annotations()) {
Label endLabel = new Label();
mv.visitLabel(endLabel);
for (Local local : body.getLocals()) {
Integer slot = localToSlot.get(local);
if (slot != null) {
BafLocal l = (BafLocal) local;
if (l.getOriginalLocal() != null) {
Local jimpleLocal = l.getOriginalLocal();
if (jimpleLocal != null)
mv.visitLocalVariable(jimpleLocal.getName(), toTypeDesc(jimpleLocal.getType()), null, startLabel, endLabel, slot);
}
}
}
}
}
use of soot.UnitBox in project robovm by robovm.
the class MethodCompiler method getBranchTargets.
private Map<Unit, List<Unit>> getBranchTargets(Body body) {
Map<Unit, List<Unit>> result = new HashMap<Unit, List<Unit>>();
for (Unit unit : body.getUnits()) {
if (unit.branches()) {
List<Unit> targetUnits = new ArrayList<Unit>();
for (UnitBox ub : unit.getUnitBoxes()) {
targetUnits.add(ub.getUnit());
}
if (unit.fallsThrough()) {
targetUnits.add(body.getUnits().getSuccOf(unit));
}
for (Unit targetUnit : targetUnits) {
List<Unit> sourceUnits = result.get(targetUnit);
if (sourceUnits == null) {
sourceUnits = new ArrayList<Unit>();
result.put(targetUnit, sourceUnits);
}
sourceUnits.add(unit);
}
}
}
return result;
}
use of soot.UnitBox in project soot by Sable.
the class SiteInliner method inlineSite.
/**
* Inlines the given site. Note that this method does
* not actually check if it's safe (with respect to access modifiers and special invokes)
* for it to be inlined. That functionality is handled by the InlinerSafetyManager.
*/
public static List inlineSite(SootMethod inlinee, Stmt toInline, SootMethod container, Map options) {
boolean enableNullPointerCheckInsertion = PhaseOptions.getBoolean(options, "insert-null-checks");
boolean enableRedundantCastInsertion = PhaseOptions.getBoolean(options, "insert-redundant-casts");
Hierarchy hierarchy = Scene.v().getActiveHierarchy();
JimpleBody containerB = (JimpleBody) container.getActiveBody();
Chain<Unit> containerUnits = containerB.getUnits();
if (!(inlinee.getDeclaringClass().isApplicationClass() || inlinee.getDeclaringClass().isLibraryClass()))
return null;
Body inlineeB = inlinee.getActiveBody();
Chain<Unit> inlineeUnits = inlineeB.getUnits();
InvokeExpr ie = toInline.getInvokeExpr();
Value thisToAdd = null;
if (ie instanceof InstanceInvokeExpr)
thisToAdd = ((InstanceInvokeExpr) ie).getBase();
// Insert casts to please the verifier.
{
boolean targetUsesThis = true;
if (enableRedundantCastInsertion && ie instanceof InstanceInvokeExpr && targetUsesThis) {
// The verifier will complain if targetUsesThis, and:
// the argument passed to the method is not the same type.
// For instance, Bottle.price_static takes a cost.
// Cost is an interface implemented by Bottle.
SootClass localType, parameterType;
localType = ((RefType) ((InstanceInvokeExpr) ie).getBase().getType()).getSootClass();
parameterType = inlinee.getDeclaringClass();
if (localType.isInterface() || hierarchy.isClassSuperclassOf(localType, parameterType)) {
Local castee = Jimple.v().newLocal("__castee", parameterType.getType());
containerB.getLocals().add(castee);
containerB.getUnits().insertBefore(Jimple.v().newAssignStmt(castee, Jimple.v().newCastExpr(((InstanceInvokeExpr) ie).getBase(), parameterType.getType())), toInline);
thisToAdd = castee;
}
}
}
// (If enabled), add a null pointer check.
{
if (enableNullPointerCheckInsertion && ie instanceof InstanceInvokeExpr) {
boolean caught = TrapManager.isExceptionCaughtAt(Scene.v().getSootClass("java.lang.NullPointerException"), toInline, containerB);
/* Ah ha. Caught again! */
if (caught) {
/* In this case, we don't use throwPoint;
* instead, put the code right there. */
Stmt insertee = Jimple.v().newIfStmt(Jimple.v().newNeExpr(((InstanceInvokeExpr) ie).getBase(), NullConstant.v()), toInline);
containerB.getUnits().insertBefore(insertee, toInline);
// This sucks (but less than before).
((IfStmt) insertee).setTarget(toInline);
ThrowManager.addThrowAfter(containerB, insertee);
} else {
Stmt throwPoint = ThrowManager.getNullPointerExceptionThrower(containerB);
containerB.getUnits().insertBefore(Jimple.v().newIfStmt(Jimple.v().newEqExpr(((InstanceInvokeExpr) ie).getBase(), NullConstant.v()), throwPoint), toInline);
}
}
}
// Add synchronizing stuff.
{
if (inlinee.isSynchronized()) {
// Need to get the class object if ie is a static invoke.
if (ie instanceof InstanceInvokeExpr)
SynchronizerManager.v().synchronizeStmtOn(toInline, containerB, (Local) ((InstanceInvokeExpr) ie).getBase());
else {
// synchronization.
if (!container.getDeclaringClass().isInterface()) {
// Whew!
Local l = SynchronizerManager.v().addStmtsToFetchClassBefore(containerB, toInline);
SynchronizerManager.v().synchronizeStmtOn(toInline, containerB, l);
}
}
}
}
Stmt exitPoint = (Stmt) containerUnits.getSuccOf(toInline);
// First, clone all of the inlinee's units & locals.
HashMap<Local, Local> oldLocalsToNew = new HashMap<Local, Local>();
HashMap<Stmt, Stmt> oldUnitsToNew = new HashMap<Stmt, Stmt>();
{
Stmt cursor = toInline;
for (Iterator<Unit> currIt = inlineeUnits.iterator(); currIt.hasNext(); ) {
final Stmt curr = (Stmt) currIt.next();
Stmt currPrime = (Stmt) curr.clone();
if (currPrime == null)
throw new RuntimeException("getting null from clone!");
currPrime.addAllTagsOf(curr);
containerUnits.insertAfter(currPrime, cursor);
cursor = currPrime;
oldUnitsToNew.put(curr, currPrime);
}
for (Iterator<Local> lIt = inlineeB.getLocals().iterator(); lIt.hasNext(); ) {
final Local l = lIt.next();
Local lPrime = (Local) l.clone();
if (lPrime == null)
throw new RuntimeException("getting null from local clone!");
containerB.getLocals().add(lPrime);
oldLocalsToNew.put(l, lPrime);
}
}
// Backpatch the newly-inserted units using newly-constructed maps.
{
Iterator<Unit> it = containerUnits.iterator(containerUnits.getSuccOf(toInline), containerUnits.getPredOf(exitPoint));
while (it.hasNext()) {
Stmt patchee = (Stmt) it.next();
for (ValueBox box : patchee.getUseAndDefBoxes()) {
if (!(box.getValue() instanceof Local))
continue;
Local lPrime = oldLocalsToNew.get(box.getValue());
if (lPrime != null)
box.setValue(lPrime);
else
throw new RuntimeException("local has no clone!");
}
for (UnitBox box : patchee.getUnitBoxes()) {
Unit uPrime = (oldUnitsToNew.get(box.getUnit()));
if (uPrime != null)
box.setUnit(uPrime);
else
throw new RuntimeException("inlined stmt has no clone!");
}
}
}
// Copy & backpatch the traps; preserve their same order.
{
Trap prevTrap = null;
for (Trap t : inlineeB.getTraps()) {
Stmt newBegin = oldUnitsToNew.get(t.getBeginUnit()), newEnd = oldUnitsToNew.get(t.getEndUnit()), newHandler = oldUnitsToNew.get(t.getHandlerUnit());
if (newBegin == null || newEnd == null || newHandler == null)
throw new RuntimeException("couldn't map trap!");
Trap trap = Jimple.v().newTrap(t.getException(), newBegin, newEnd, newHandler);
if (prevTrap == null)
containerB.getTraps().addFirst(trap);
else
containerB.getTraps().insertAfter(trap, prevTrap);
prevTrap = trap;
}
}
// Handle identity stmt's and returns.
{
Iterator<Unit> it = containerUnits.iterator(containerUnits.getSuccOf(toInline), containerUnits.getPredOf(exitPoint));
ArrayList<Unit> cuCopy = new ArrayList<Unit>();
while (it.hasNext()) {
cuCopy.add(it.next());
}
for (Unit u : cuCopy) {
Stmt s = (Stmt) u;
if (s instanceof IdentityStmt) {
IdentityRef rhs = (IdentityRef) ((IdentityStmt) s).getRightOp();
if (rhs instanceof CaughtExceptionRef)
continue;
else if (rhs instanceof ThisRef) {
if (!(ie instanceof InstanceInvokeExpr))
throw new RuntimeException("thisref with no receiver!");
containerUnits.swapWith(s, Jimple.v().newAssignStmt(((IdentityStmt) s).getLeftOp(), thisToAdd));
} else if (rhs instanceof ParameterRef) {
ParameterRef pref = (ParameterRef) rhs;
containerUnits.swapWith(s, Jimple.v().newAssignStmt(((IdentityStmt) s).getLeftOp(), ie.getArg(pref.getIndex())));
}
} else if (s instanceof ReturnStmt) {
if (toInline instanceof InvokeStmt) {
// munch, munch.
containerUnits.swapWith(s, Jimple.v().newGotoStmt(exitPoint));
continue;
}
if (!(toInline instanceof AssignStmt))
throw new RuntimeException("invoking stmt neither InvokeStmt nor AssignStmt!??!?!");
Value ro = ((ReturnStmt) s).getOp();
Value lhs = ((AssignStmt) toInline).getLeftOp();
AssignStmt as = Jimple.v().newAssignStmt(lhs, ro);
containerUnits.insertBefore(as, s);
containerUnits.swapWith(s, Jimple.v().newGotoStmt(exitPoint));
} else if (s instanceof ReturnVoidStmt)
containerUnits.swapWith(s, Jimple.v().newGotoStmt(exitPoint));
}
}
List<Unit> newStmts = new ArrayList<Unit>();
for (Iterator<Unit> i = containerUnits.iterator(containerUnits.getSuccOf(toInline), containerUnits.getPredOf(exitPoint)); i.hasNext(); ) {
newStmts.add(i.next());
}
// Remove the original statement toInline.
containerUnits.remove(toInline);
// Resolve name collisions.
LocalNameStandardizer.v().transform(containerB, "ji.lns");
return newStmts;
}
use of soot.UnitBox in project soot by Sable.
the class Shimple method redirectPointers.
/**
* Redirects PhiExpr pointers to the given Unit to the new Unit.
*
* <p> Normally you should not have to call this function
* directly, since patching is taken care of Shimple's internal
* implementation of PatchingChain.
*/
public static void redirectPointers(Unit oldLocation, Unit newLocation) {
List<UnitBox> boxesPointing = oldLocation.getBoxesPointingToThis();
// important to change this to an array to have a static copy
UnitBox[] boxes = boxesPointing.toArray(new UnitBox[boxesPointing.size()]);
for (UnitBox box : boxes) {
if (box.getUnit() != oldLocation)
throw new RuntimeException("Something weird's happening");
if (!box.isBranchTarget())
box.setUnit(newLocation);
}
}
Aggregations