use of soot.Unit in project soot by Sable.
the class DexReturnInliner method internalTransform.
@Override
protected void internalTransform(final Body body, String phaseName, Map<String, String> options) {
Set<Unit> duplicateIfTargets = getFallThroughReturns(body);
Iterator<Unit> it = body.getUnits().snapshotIterator();
boolean mayBeMore = false;
Unit last = null;
do {
mayBeMore = false;
while (it.hasNext()) {
Unit u = it.next();
if (u instanceof GotoStmt) {
GotoStmt gtStmt = (GotoStmt) u;
if (isInstanceofReturn(gtStmt.getTarget())) {
Stmt stmt = (Stmt) gtStmt.getTarget().clone();
for (Trap t : body.getTraps()) for (UnitBox ubox : t.getUnitBoxes()) if (ubox.getUnit() == u)
ubox.setUnit(stmt);
while (!u.getBoxesPointingToThis().isEmpty()) u.getBoxesPointingToThis().get(0).setUnit(stmt);
// the cloned return stmt gets the tags of u
stmt.addAllTagsOf(u);
body.getUnits().swapWith(u, stmt);
mayBeMore = true;
}
} else if (u instanceof IfStmt) {
IfStmt ifstmt = (IfStmt) u;
Unit t = ifstmt.getTarget();
if (isInstanceofReturn(t)) {
// once, otherwise we will end up with unused copies
if (duplicateIfTargets == null)
duplicateIfTargets = new HashSet<Unit>();
if (!duplicateIfTargets.add(t)) {
Unit newTarget = (Unit) t.clone();
body.getUnits().addLast(newTarget);
ifstmt.setTarget(newTarget);
}
}
} else if (isInstanceofReturn(u)) {
// the original return stmt gets the tags of its predecessor
if (last != null) {
u.removeAllTags();
u.addAllTagsOf(last);
}
}
last = u;
}
} while (mayBeMore);
}
use of soot.Unit in project soot by Sable.
the class DexReturnValuePropagator method isRedefined.
/**
* Checks whether the given local has been redefined between the original
* definition unitDef and the use unitUse.
* @param l The local for which to check for redefinitions
* @param unitUse The unit that uses the local
* @param unitDef The unit that defines the local
* @param graph The unit graph to use for the check
* @return True if there is at least one path between unitDef and unitUse on
* which local l gets redefined, otherwise false
*/
private boolean isRedefined(Local l, Unit unitUse, AssignStmt unitDef, UnitGraph graph) {
List<Unit> workList = new ArrayList<Unit>();
workList.add(unitUse);
Set<Unit> doneSet = new HashSet<Unit>();
// Check for redefinitions of the local between definition and use
while (!workList.isEmpty()) {
Unit curStmt = workList.remove(0);
if (!doneSet.add(curStmt))
continue;
for (Unit u : graph.getPredsOf(curStmt)) {
if (u != unitDef) {
if (u instanceof DefinitionStmt) {
DefinitionStmt defStmt = (DefinitionStmt) u;
if (defStmt.getLeftOp() == l)
return true;
}
workList.add(u);
}
}
}
return false;
}
use of soot.Unit in project soot by Sable.
the class DexArrayInitReducer method internalTransform.
@Override
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
// Make sure that we only have linear control flow
if (!b.getTraps().isEmpty())
return;
// Look for a chain of two constant assignments followed by an array put
Unit u1 = null, u2 = null;
for (Iterator<Unit> uIt = b.getUnits().snapshotIterator(); uIt.hasNext(); ) {
Unit u = uIt.next();
// If this is not an assignment, it does not matter.
if (!(u instanceof AssignStmt) || !((Stmt) u).getBoxesPointingToThis().isEmpty()) {
u1 = null;
u2 = null;
continue;
}
// If this is an assignment to an array, we must already have two
// preceding constant assignments
AssignStmt assignStmt = (AssignStmt) u;
if (assignStmt.getLeftOp() instanceof ArrayRef) {
if (u1 != null && u2 != null && u2.getBoxesPointingToThis().isEmpty() && assignStmt.getBoxesPointingToThis().isEmpty()) {
ArrayRef arrayRef = (ArrayRef) assignStmt.getLeftOp();
Value u1val = u1.getDefBoxes().get(0).getValue();
Value u2val = u2.getDefBoxes().get(0).getValue();
// index
if (arrayRef.getIndex() == u1val)
arrayRef.setIndex(((AssignStmt) u1).getRightOp());
else if (arrayRef.getIndex() == u2val)
arrayRef.setIndex(((AssignStmt) u2).getRightOp());
// value
if (assignStmt.getRightOp() == u1val)
assignStmt.setRightOp(((AssignStmt) u1).getRightOp());
else if (assignStmt.getRightOp() == u2val)
assignStmt.setRightOp(((AssignStmt) u2).getRightOp());
// Remove the unnecessary assignments
Unit checkU = u;
boolean foundU1 = false, foundU2 = false, doneU1 = false, doneU2 = false;
while (!(doneU1 && doneU2) && !(foundU1 && foundU2) && checkU != null) {
// Does the current statement use the value?
for (ValueBox vb : checkU.getUseBoxes()) {
if (!doneU1 && vb.getValue() == u1val)
foundU1 = true;
if (!doneU2 && vb.getValue() == u2val)
foundU2 = true;
}
// Does the current statement overwrite the value?
for (ValueBox vb : checkU.getDefBoxes()) {
if (vb.getValue() == u1val)
doneU1 = true;
else if (vb.getValue() == u2val)
doneU2 = true;
}
// If this statement branches, we abort
if (checkU.branches()) {
foundU1 = true;
foundU2 = true;
break;
}
// Get the next statement
checkU = b.getUnits().getSuccOf(checkU);
}
if (!foundU1) {
// only remove constant assignment if the left value is Local
if (u1val instanceof Local) {
b.getUnits().remove(u1);
if (Options.v().verbose()) {
logger.debug("[" + b.getMethod().getName() + "] remove 1 " + u1);
}
}
}
if (!foundU2) {
// only remove constant assignment if the left value is Local
if (u2val instanceof Local) {
b.getUnits().remove(u2);
if (Options.v().verbose()) {
logger.debug("[" + b.getMethod().getName() + "] remove 2 " + u2);
}
}
}
u1 = null;
u2 = null;
} else {
// No proper initialization before
u1 = null;
u2 = null;
continue;
}
}
// value.
if (!(assignStmt.getRightOp() instanceof Constant)) {
u1 = null;
u2 = null;
continue;
}
if (u1 == null) {
u1 = assignStmt;
} else if (u2 == null) {
u2 = assignStmt;
// If the last value is overwritten again, we start again at the beginning
if (u1 != null) {
Value op1 = ((AssignStmt) u1).getLeftOp();
if (op1 == ((AssignStmt) u2).getLeftOp()) {
u1 = u2;
u2 = null;
}
}
} else {
u1 = u2;
u2 = assignStmt;
}
}
// Remove all locals that are no longer necessary
UnusedLocalEliminator.v().transform(b);
}
use of soot.Unit in project soot by Sable.
the class DexPrinter method toMethodImplementation.
private MethodImplementation toMethodImplementation(SootMethod m) {
if (m.isAbstract() || m.isNative()) {
return null;
}
Body activeBody = m.retrieveActiveBody();
// when installing the app
if (m.getName().contains("<") || m.getName().equals(">"))
if (!m.getName().equals("<init>") && !m.getName().equals("<clinit>"))
throw new RuntimeException("Invalid method name: " + m.getName());
// Switch statements may not be empty in dex, so we have to fix this
// first
EmptySwitchEliminator.v().transform(activeBody);
// Dalvik requires synchronized methods to have explicit monitor calls,
// so we insert them here. See
// http://milk.com/kodebase/dalvik-docs-mirror/docs/debugger.html
// We cannot place this upon the developer since it is only required
// for Dalvik, but not for other targets.
SynchronizedMethodTransformer.v().transform(activeBody);
// Tries may not start or end at units which have no corresponding
// Dalvik
// instructions such as IdentityStmts. We reduce the traps to start at
// the
// first "real" instruction. We could also use a TrapTigthener, but that
// would be too expensive for what we need here.
FastDexTrapTightener.v().transform(activeBody);
// Look for sequences of array element assignments that we can collapse
// into bulk initializations
DexArrayInitDetector initDetector = new DexArrayInitDetector();
initDetector.constructArrayInitializations(activeBody);
initDetector.fixTraps(activeBody);
// Split the tries since Dalvik does not supported nested try/catch
// blocks
TrapSplitter.v().transform(activeBody);
// word count of incoming parameters
int inWords = SootToDexUtils.getDexWords(m.getParameterTypes());
if (!m.isStatic()) {
// extra word for "this"
inWords++;
}
// word count of max outgoing parameters
Collection<Unit> units = activeBody.getUnits();
// register count = parameters + additional registers, depending on the
// dex instructions generated (e.g. locals used and constants loaded)
StmtVisitor stmtV = new StmtVisitor(m, initDetector);
Chain<Trap> traps = activeBody.getTraps();
Set<Unit> trapReferences = new HashSet<Unit>(traps.size() * 3);
for (Trap t : activeBody.getTraps()) {
trapReferences.add(t.getBeginUnit());
trapReferences.add(t.getEndUnit());
trapReferences.add(t.getHandlerUnit());
}
toInstructions(units, stmtV, trapReferences);
int registerCount = stmtV.getRegisterCount();
if (inWords > registerCount) {
/*
* as the Dalvik VM moves the parameters into the last registers, the "in" word
* count must be at least equal to the register count. a smaller register count
* could occur if soot generated the method body, see e.g. the handling of
* phantom refs in SootMethodRefImpl.resolve(StringBuffer): the body has no
* locals for the ParameterRefs, it just throws an error.
*
* we satisfy the verifier by just increasing the register count, since calling
* phantom refs will lead to an error anyway.
*/
registerCount = inWords;
}
MethodImplementationBuilder builder = new MethodImplementationBuilder(registerCount);
LabelAssigner labelAssinger = new LabelAssigner(builder);
List<BuilderInstruction> instructions = stmtV.getRealInsns(labelAssinger);
fixLongJumps(instructions, labelAssinger, stmtV);
Map<Local, Integer> seenRegisters = new HashMap<Local, Integer>();
Map<Instruction, LocalRegisterAssignmentInformation> instructionRegisterMap = stmtV.getInstructionRegisterMap();
if (Options.v().write_local_annotations()) {
for (LocalRegisterAssignmentInformation assignment : stmtV.getParameterInstructionsList()) {
// (at least not if it exists with exactly this name)
if (assignment.getLocal().getName().equals("this"))
continue;
addRegisterAssignmentDebugInfo(assignment, seenRegisters, builder);
}
}
for (BuilderInstruction ins : instructions) {
Stmt origStmt = stmtV.getStmtForInstruction(ins);
// If this is a switch payload, we need to place the label
if (stmtV.getInstructionPayloadMap().containsKey(ins))
builder.addLabel(labelAssinger.getLabelName(stmtV.getInstructionPayloadMap().get(ins)));
if (origStmt != null) {
// Do we need a label here because this a trap handler?
if (trapReferences.contains(origStmt))
labelAssinger.getOrCreateLabel(origStmt);
// Add the label if the statement has one
String labelName = labelAssinger.getLabelName(origStmt);
if (labelName != null && !builder.getLabel(labelName).isPlaced())
builder.addLabel(labelName);
// Add the tags
if (stmtV.getStmtForInstruction(ins) != null) {
List<Tag> tags = origStmt.getTags();
for (Tag t : tags) {
if (t instanceof LineNumberTag) {
LineNumberTag lnt = (LineNumberTag) t;
builder.addLineNumber(lnt.getLineNumber());
} else if (t instanceof SourceFileTag) {
SourceFileTag sft = (SourceFileTag) t;
builder.addSetSourceFile(new ImmutableStringReference(sft.getSourceFile()));
}
}
}
}
builder.addInstruction(ins);
LocalRegisterAssignmentInformation registerAssignmentTag = instructionRegisterMap.get(ins);
if (registerAssignmentTag != null) {
// Add start local debugging information: Register -> Local
// assignment
addRegisterAssignmentDebugInfo(registerAssignmentTag, seenRegisters, builder);
}
}
for (int registersLeft : seenRegisters.values()) builder.addEndLocal(registersLeft);
toTries(activeBody.getTraps(), stmtV, builder, labelAssinger);
// Make sure that all labels have been placed by now
for (Label lbl : labelAssinger.getAllLabels()) if (!lbl.isPlaced())
throw new RuntimeException("Label not placed: " + lbl);
return builder.getMethodImplementation();
}
use of soot.Unit in project soot by Sable.
the class FastDexTrapTightener method internalTransform.
@Override
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
for (Iterator<Trap> trapIt = b.getTraps().snapshotIterator(); trapIt.hasNext(); ) {
Trap t = trapIt.next();
Unit beginUnit;
while (!isDexInstruction(beginUnit = t.getBeginUnit()) && t.getBeginUnit() != t.getEndUnit()) t.setBeginUnit(b.getUnits().getSuccOf(beginUnit));
// If the trap is empty, we remove it
if (t.getBeginUnit() == t.getEndUnit())
trapIt.remove();
}
}
Aggregations