use of soot.jimple.AssignStmt in project soot by Sable.
the class DexBody method jimplify.
/**
* Return the jimple equivalent of this body.
*
* @param m
* the SootMethod that contains this body
*/
public Body jimplify(Body b, SootMethod m) {
final Jimple jimple = Jimple.v();
final UnknownType unknownType = UnknownType.v();
final NullConstant nullConstant = NullConstant.v();
final Options options = Options.v();
/*
* Timer t_whole_jimplification = new Timer(); Timer t_num = new
* Timer(); Timer t_null = new Timer();
*
* t_whole_jimplification.start();
*/
jBody = (JimpleBody) b;
deferredInstructions = new ArrayList<DeferableInstruction>();
instructionsToRetype = new HashSet<RetypeableInstruction>();
if (IDalvikTyper.ENABLE_DVKTYPER) {
DalvikTyper.v().clear();
}
// process method parameters and generate Jimple locals from Dalvik
// registers
List<Local> paramLocals = new LinkedList<Local>();
if (!isStatic) {
int thisRegister = numRegisters - numParameterRegisters - 1;
// generateLocal(UnknownType.v());
Local thisLocal = jimple.newLocal("$u" + thisRegister, unknownType);
jBody.getLocals().add(thisLocal);
registerLocals[thisRegister] = thisLocal;
JIdentityStmt idStmt = (JIdentityStmt) jimple.newIdentityStmt(thisLocal, jimple.newThisRef(declaringClassType));
add(idStmt);
paramLocals.add(thisLocal);
if (IDalvikTyper.ENABLE_DVKTYPER) {
DalvikTyper.v().setType(idStmt.leftBox, jBody.getMethod().getDeclaringClass().getType(), false);
}
}
{
// index of parameter type
int i = 0;
// index
int parameterRegister = numRegisters - numParameterRegisters;
// register
for (Type t : parameterTypes) {
// may
Local gen = jimple.newLocal("$u" + parameterRegister, unknownType);
// only
// use
// UnknownType
// here
// because
// the
// local
// may
// be
// reused
// with
// a
// different
// type
// later
// (before
// splitting)
jBody.getLocals().add(gen);
registerLocals[parameterRegister] = gen;
JIdentityStmt idStmt = (JIdentityStmt) jimple.newIdentityStmt(gen, jimple.newParameterRef(t, i++));
add(idStmt);
paramLocals.add(gen);
if (IDalvikTyper.ENABLE_DVKTYPER) {
DalvikTyper.v().setType(idStmt.leftBox, t, false);
}
// used later in the Dalvik bytecode
if (t instanceof LongType || t instanceof DoubleType) {
parameterRegister++;
// may
Local g = jimple.newLocal("$u" + parameterRegister, unknownType);
// only
// use
// UnknownType
// here
// because
// the
// local
// may
// be
// reused
// with
// a
// different
// type
// later
// (before
// splitting)
jBody.getLocals().add(g);
registerLocals[parameterRegister] = g;
}
parameterRegister++;
}
}
for (int i = 0; i < (numRegisters - numParameterRegisters - (isStatic ? 0 : 1)); i++) {
registerLocals[i] = jimple.newLocal("$u" + i, unknownType);
jBody.getLocals().add(registerLocals[i]);
}
// add local to store intermediate results
storeResultLocal = jimple.newLocal("$u-1", unknownType);
jBody.getLocals().add(storeResultLocal);
// process bytecode instructions
final boolean isOdex = dexFile instanceof DexBackedDexFile ? ((DexBackedDexFile) dexFile).isOdexFile() : false;
ClassPath cp = null;
if (isOdex) {
String[] sootClasspath = options.soot_classpath().split(File.pathSeparator);
List<String> classpathList = new ArrayList<String>();
for (String str : sootClasspath) classpathList.add(str);
try {
ClassPathResolver resolver = new ClassPathResolver(classpathList, classpathList, classpathList, dexFile);
cp = new ClassPath(resolver.getResolvedClassProviders().toArray(new ClassProvider[0]));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
int prevLineNumber = -1;
for (DexlibAbstractInstruction instruction : instructions) {
if (isOdex && instruction instanceof OdexInstruction)
((OdexInstruction) instruction).deOdex(dexFile, method, cp);
if (dangling != null) {
dangling.finalize(this, instruction);
dangling = null;
}
instruction.jimplify(this);
if (instruction.getLineNumber() > 0)
prevLineNumber = instruction.getLineNumber();
else {
instruction.setLineNumber(prevLineNumber);
}
}
for (DeferableInstruction instruction : deferredInstructions) {
instruction.deferredJimplify(this);
}
if (tries != null)
addTraps();
int prevLn = -1;
final boolean keepLineNumber = options.keep_line_number();
for (DexlibAbstractInstruction instruction : instructions) {
Unit unit = instruction.getUnit();
int lineNumber = unit.getJavaSourceStartLineNumber();
if (keepLineNumber && lineNumber < 0) {
if (prevLn >= 0) {
unit.addTag(new LineNumberTag(prevLn));
unit.addTag(new SourceLineNumberTag(prevLn));
}
} else {
prevLn = lineNumber;
}
}
// At this point Jimple code is generated
// Cleaning...
instructions = null;
// registerLocals = null;
// storeResultLocal = null;
instructionAtAddress.clear();
// localGenerator = null;
deferredInstructions = null;
// instructionsToRetype = null;
dangling = null;
tries = null;
/*
* We eliminate dead code. Dead code has been shown to occur under the
* following circumstances.
*
* 0006ec: 0d00 |00a2: move-exception v0 ... 0006f2: 0d00 |00a5:
* move-exception v0 ... 0x0041 - 0x008a Ljava/lang/Throwable; -> 0x00a5
* <any> -> 0x00a2
*
* Here there are two traps both over the same region. But the same
* always fires, hence rendering the code at a2 unreachable. Dead code
* yields problems during local splitting because locals within dead
* code will not be split. Hence we remove all dead code here.
*/
// Fix traps that do not catch exceptions
DexTrapStackFixer.v().transform(jBody);
// Sort out jump chains
DexJumpChainShortener.v().transform(jBody);
// Make sure that we don't have any overlapping uses due to returns
DexReturnInliner.v().transform(jBody);
// Shortcut: Reduce array initializations
DexArrayInitReducer.v().transform(jBody);
// split first to find undefined uses
getLocalSplitter().transform(jBody);
// Remove dead code and the corresponding locals before assigning types
getUnreachableCodeEliminator().transform(jBody);
DeadAssignmentEliminator.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
for (RetypeableInstruction i : instructionsToRetype) i.retype(jBody);
if (IDalvikTyper.ENABLE_DVKTYPER) {
DexReturnValuePropagator.v().transform(jBody);
getCopyPopagator().transform(jBody);
DexNullThrowTransformer.v().transform(jBody);
DalvikTyper.v().typeUntypedConstrantInDiv(jBody);
DeadAssignmentEliminator.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
DalvikTyper.v().assignType(jBody);
// jBody.validate();
jBody.validateUses();
jBody.validateValueBoxes();
// jBody.checkInit();
// Validate.validateArrays(jBody);
// jBody.checkTypes();
// jBody.checkLocals();
} else {
// t_num.start();
DexNumTransformer.v().transform(jBody);
// t_num.end();
DexReturnValuePropagator.v().transform(jBody);
getCopyPopagator().transform(jBody);
DexNullThrowTransformer.v().transform(jBody);
// t_null.start();
DexNullTransformer.v().transform(jBody);
// t_null.end();
DexIfTransformer.v().transform(jBody);
DeadAssignmentEliminator.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
// DexRefsChecker.v().transform(jBody);
DexNullArrayRefTransformer.v().transform(jBody);
}
if (IDalvikTyper.ENABLE_DVKTYPER) {
for (Local l : jBody.getLocals()) {
l.setType(unknownType);
}
}
// Remove "instanceof" checks on the null constant
DexNullInstanceofTransformer.v().transform(jBody);
TypeAssigner.v().transform(jBody);
final RefType objectType = RefType.v("java.lang.Object");
if (IDalvikTyper.ENABLE_DVKTYPER) {
for (Unit u : jBody.getUnits()) {
if (u instanceof IfStmt) {
ConditionExpr expr = (ConditionExpr) ((IfStmt) u).getCondition();
if (((expr instanceof EqExpr) || (expr instanceof NeExpr))) {
Value op1 = expr.getOp1();
Value op2 = expr.getOp2();
if (op1 instanceof Constant && op2 instanceof Local) {
Local l = (Local) op2;
Type ltype = l.getType();
if (ltype instanceof PrimType)
continue;
if (// by default
!(op1 instanceof IntConstant))
// in Dalvik
continue;
IntConstant icst = (IntConstant) op1;
int val = icst.value;
if (val != 0)
continue;
expr.setOp1(nullConstant);
} else if (op1 instanceof Local && op2 instanceof Constant) {
Local l = (Local) op1;
Type ltype = l.getType();
if (ltype instanceof PrimType)
continue;
if (// by default
!(op2 instanceof IntConstant))
// in Dalvik
continue;
IntConstant icst = (IntConstant) op2;
int val = icst.value;
if (val != 0)
continue;
expr.setOp2(nullConstant);
} else if (op1 instanceof Local && op2 instanceof Local) {
// nothing to do
} else if (op1 instanceof Constant && op2 instanceof Constant) {
if (op1 instanceof NullConstant && op2 instanceof NumericConstant) {
IntConstant nc = (IntConstant) op2;
if (nc.value != 0)
throw new RuntimeException("expected value 0 for int constant. Got " + expr);
expr.setOp2(NullConstant.v());
} else if (op2 instanceof NullConstant && op1 instanceof NumericConstant) {
IntConstant nc = (IntConstant) op1;
if (nc.value != 0)
throw new RuntimeException("expected value 0 for int constant. Got " + expr);
expr.setOp1(nullConstant);
}
} else {
throw new RuntimeException("error: do not handle if: " + u);
}
}
}
}
// For null_type locals: replace their use by NullConstant()
List<ValueBox> uses = jBody.getUseBoxes();
// List<ValueBox> defs = jBody.getDefBoxes();
List<ValueBox> toNullConstantify = new ArrayList<ValueBox>();
List<Local> toRemove = new ArrayList<Local>();
for (Local l : jBody.getLocals()) {
if (l.getType() instanceof NullType) {
toRemove.add(l);
for (ValueBox vb : uses) {
Value v = vb.getValue();
if (v == l)
toNullConstantify.add(vb);
}
}
}
for (ValueBox vb : toNullConstantify) {
System.out.println("replace valuebox '" + vb + " with null constant");
vb.setValue(nullConstant);
}
for (Local l : toRemove) {
System.out.println("removing null_type local " + l);
l.setType(objectType);
}
}
// We pack locals that are not used in overlapping regions. This may
// again lead to unused locals which we have to remove.
LocalPacker.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
LocalNameStandardizer.v().transform(jBody);
// on the fly.
if (options.wrong_staticness() == Options.wrong_staticness_fix) {
FieldStaticnessCorrector.v().transform(jBody);
MethodStaticnessCorrector.v().transform(jBody);
}
// Inline PackManager.v().getPack("jb").apply(jBody);
// Keep only transformations that have not been done
// at this point.
TrapTightener.v().transform(jBody);
TrapMinimizer.v().transform(jBody);
// LocalSplitter.v().transform(jBody);
Aggregator.v().transform(jBody);
// UnusedLocalEliminator.v().transform(jBody);
// TypeAssigner.v().transform(jBody);
// LocalPacker.v().transform(jBody);
// LocalNameStandardizer.v().transform(jBody);
// Remove if (null == null) goto x else <madness>. We can only do this
// after we have run the constant propagation as we might not be able
// to statically decide the conditions earlier.
ConditionalBranchFolder.v().transform(jBody);
// Remove unnecessary typecasts
ConstantCastEliminator.v().transform(jBody);
IdentityCastEliminator.v().transform(jBody);
// Remove unnecessary logic operations
IdentityOperationEliminator.v().transform(jBody);
// We need to run this transformer since the conditional branch folder
// might have rendered some code unreachable (well, it was unreachable
// before as well, but we didn't know).
UnreachableCodeEliminator.v().transform(jBody);
// Not sure whether we need this even though we do it earlier on as
// the earlier pass does not have type information
// CopyPropagator.v().transform(jBody);
// we might have gotten new dead assignments and unused locals through
// copy propagation and unreachable code elimination, so we have to do
// this again
DeadAssignmentEliminator.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
NopEliminator.v().transform(jBody);
// Remove unnecessary chains of return statements
DexReturnPacker.v().transform(jBody);
for (Unit u : jBody.getUnits()) {
if (u instanceof AssignStmt) {
AssignStmt ass = (AssignStmt) u;
if (ass.getRightOp() instanceof CastExpr) {
CastExpr c = (CastExpr) ass.getRightOp();
if (c.getType() instanceof NullType) {
ass.setRightOp(nullConstant);
}
}
}
if (u instanceof DefinitionStmt) {
DefinitionStmt def = (DefinitionStmt) u;
// we must manually fix the hierarchy
if (def.getLeftOp() instanceof Local && def.getRightOp() instanceof CaughtExceptionRef) {
Type t = def.getLeftOp().getType();
if (t instanceof RefType) {
RefType rt = (RefType) t;
if (rt.getSootClass().isPhantom() && !rt.getSootClass().hasSuperclass() && !rt.getSootClass().getName().equals("java.lang.Throwable"))
rt.getSootClass().setSuperclass(Scene.v().getSootClass("java.lang.Throwable"));
}
}
}
}
//
for (Local l : jBody.getLocals()) {
Type t = l.getType();
if (t instanceof NullType) {
l.setType(objectType);
}
}
return jBody;
}
use of soot.jimple.AssignStmt in project soot by Sable.
the class DexIfTransformer method internalTransform.
@Override
protected void internalTransform(final Body body, String phaseName, Map<String, String> options) {
final DexDefUseAnalysis localDefs = new DexDefUseAnalysis(body);
Set<IfStmt> ifSet = getNullIfCandidates(body);
for (IfStmt ifs : ifSet) {
ConditionExpr ifCondition = (ConditionExpr) ifs.getCondition();
Local[] twoIfLocals = new Local[] { (Local) ifCondition.getOp1(), (Local) ifCondition.getOp2() };
usedAsObject = false;
for (Local loc : twoIfLocals) {
Set<Unit> defs = localDefs.collectDefinitionsWithAliases(loc);
// process normally
doBreak = false;
for (Unit u : defs) {
// put correct local in l
if (u instanceof DefinitionStmt) {
l = (Local) ((DefinitionStmt) u).getLeftOp();
} else {
throw new RuntimeException("ERROR: def can not be something else than Assign or Identity statement! (def: " + u + " class: " + u.getClass() + "");
}
// check defs
u.apply(new // Alex: should also end
AbstractStmtSwitch() {
// as soon as detected
// as not used as an
// object
@Override
public void caseAssignStmt(AssignStmt stmt) {
Value r = stmt.getRightOp();
if (r instanceof FieldRef) {
usedAsObject = isObject(((FieldRef) r).getFieldRef().type());
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) r;
if (ar.getType() instanceof UnknownType) {
// isObject
usedAsObject = stmt.hasTag("ObjectOpTag");
// (findArrayType
// (g,
// localDefs,
// localUses,
// stmt));
} else {
usedAsObject = isObject(ar.getType());
}
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof StringConstant || r instanceof NewExpr || r instanceof NewArrayExpr) {
usedAsObject = true;
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof CastExpr) {
usedAsObject = isObject(((CastExpr) r).getCastType());
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof InvokeExpr) {
usedAsObject = isObject(((InvokeExpr) r).getType());
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof LengthExpr) {
usedAsObject = false;
if (usedAsObject)
doBreak = true;
return;
}
}
@Override
public void caseIdentityStmt(IdentityStmt stmt) {
if (stmt.getLeftOp() == l) {
usedAsObject = isObject(stmt.getRightOp().getType());
if (usedAsObject)
doBreak = true;
return;
}
}
});
if (doBreak)
break;
// check uses
for (Unit use : localDefs.getUsesOf(l)) {
use.apply(new AbstractStmtSwitch() {
private boolean examineInvokeExpr(InvokeExpr e) {
List<Value> args = e.getArgs();
List<Type> argTypes = e.getMethodRef().parameterTypes();
assert args.size() == argTypes.size();
for (int i = 0; i < args.size(); i++) {
if (args.get(i) == l && isObject(argTypes.get(i))) {
return true;
}
}
// check for base
SootMethodRef sm = e.getMethodRef();
if (!sm.isStatic()) {
if (e instanceof AbstractInvokeExpr) {
AbstractInstanceInvokeExpr aiiexpr = (AbstractInstanceInvokeExpr) e;
Value b = aiiexpr.getBase();
if (b == l) {
return true;
}
}
}
return false;
}
@Override
public void caseInvokeStmt(InvokeStmt stmt) {
InvokeExpr e = stmt.getInvokeExpr();
usedAsObject = examineInvokeExpr(e);
if (usedAsObject)
doBreak = true;
return;
}
@Override
public void caseAssignStmt(AssignStmt stmt) {
Value left = stmt.getLeftOp();
Value r = stmt.getRightOp();
if (left instanceof ArrayRef) {
if (((ArrayRef) left).getIndex() == l) {
// doBreak = true;
return;
}
}
// used to assign
if (stmt.getRightOp() == l) {
Value l = stmt.getLeftOp();
if (l instanceof StaticFieldRef && isObject(((StaticFieldRef) l).getFieldRef().type())) {
usedAsObject = true;
if (usedAsObject)
doBreak = true;
return;
} else if (l instanceof InstanceFieldRef && isObject(((InstanceFieldRef) l).getFieldRef().type())) {
usedAsObject = true;
if (usedAsObject)
doBreak = true;
return;
} else if (l instanceof ArrayRef) {
Type aType = ((ArrayRef) l).getType();
if (aType instanceof UnknownType) {
// isObject(
usedAsObject = stmt.hasTag("ObjectOpTag");
// findArrayType(g,
// localDefs,
// localUses,
// stmt));
} else {
usedAsObject = isObject(aType);
}
if (usedAsObject)
doBreak = true;
return;
}
}
// assignment)
if (r instanceof FieldRef) {
// isObject(((FieldRef)
usedAsObject = true;
// r).getFieldRef().type());
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) r;
if (ar.getBase() == l) {
usedAsObject = true;
} else {
// used as index
usedAsObject = false;
}
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof StringConstant || r instanceof NewExpr) {
throw new RuntimeException("NOT POSSIBLE StringConstant or NewExpr at " + stmt);
} else if (r instanceof NewArrayExpr) {
usedAsObject = false;
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof CastExpr) {
usedAsObject = isObject(((CastExpr) r).getCastType());
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof InvokeExpr) {
usedAsObject = examineInvokeExpr((InvokeExpr) stmt.getRightOp());
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof LengthExpr) {
usedAsObject = true;
if (usedAsObject)
doBreak = true;
return;
} else if (r instanceof BinopExpr) {
usedAsObject = false;
if (usedAsObject)
doBreak = true;
return;
}
}
@Override
public void caseIdentityStmt(IdentityStmt stmt) {
if (stmt.getLeftOp() == l)
throw new RuntimeException("IMPOSSIBLE 0");
}
@Override
public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
usedAsObject = stmt.getOp() == l;
if (usedAsObject)
doBreak = true;
return;
}
@Override
public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
usedAsObject = stmt.getOp() == l;
if (usedAsObject)
doBreak = true;
return;
}
@Override
public void caseReturnStmt(ReturnStmt stmt) {
usedAsObject = stmt.getOp() == l && isObject(body.getMethod().getReturnType());
if (usedAsObject)
doBreak = true;
return;
}
@Override
public void caseThrowStmt(ThrowStmt stmt) {
usedAsObject = stmt.getOp() == l;
if (usedAsObject)
doBreak = true;
return;
}
});
if (doBreak)
break;
}
// for uses
if (doBreak)
break;
}
if (// as soon as one def or use refers to an object
doBreak)
// be updated
break;
}
// change values
if (usedAsObject) {
Set<Unit> defsOp1 = localDefs.collectDefinitionsWithAliases(twoIfLocals[0]);
Set<Unit> defsOp2 = localDefs.collectDefinitionsWithAliases(twoIfLocals[1]);
defsOp1.addAll(defsOp2);
for (Unit u : defsOp1) {
Stmt s = (Stmt) u;
// If we have a[x] = 0 and a is an object, we may not conclude 0 -> null
if (!s.containsArrayRef() || (!defsOp1.contains(s.getArrayRef().getBase()) && !defsOp2.contains(s.getArrayRef().getBase())))
replaceWithNull(u);
Local l = (Local) ((DefinitionStmt) u).getLeftOp();
for (Unit uuse : localDefs.getUsesOf(l)) {
Stmt use = (Stmt) uuse;
// If we have a[x] = 0 and a is an object, we may not conclude 0 -> null
if (!use.containsArrayRef() || (twoIfLocals[0] != use.getArrayRef().getBase()) && twoIfLocals[1] != use.getArrayRef().getBase())
replaceWithNull(use);
}
}
}
// end if
}
// for if statements
}
use of soot.jimple.AssignStmt in project soot by Sable.
the class DexNullArrayRefTransformer method internalTransform.
protected void internalTransform(final Body body, String phaseName, Map<String, String> options) {
final ExceptionalUnitGraph g = new ExceptionalUnitGraph(body, DalvikThrowAnalysis.v());
final LocalDefs defs = LocalDefs.Factory.newLocalDefs(g);
final LocalCreation lc = new LocalCreation(body.getLocals(), "ex");
boolean changed = false;
for (Iterator<Unit> unitIt = body.getUnits().snapshotIterator(); unitIt.hasNext(); ) {
Stmt s = (Stmt) unitIt.next();
if (s.containsArrayRef()) {
// Check array reference
Value base = s.getArrayRef().getBase();
if (isAlwaysNullBefore(s, (Local) base, defs)) {
createThrowStmt(body, s, lc);
changed = true;
}
} else if (s instanceof AssignStmt) {
AssignStmt ass = (AssignStmt) s;
Value rightOp = ass.getRightOp();
if (rightOp instanceof LengthExpr) {
// Check lengthof expression
LengthExpr l = (LengthExpr) ass.getRightOp();
Value base = l.getOp();
if (base instanceof IntConstant) {
IntConstant ic = (IntConstant) base;
if (ic.value == 0) {
createThrowStmt(body, s, lc);
changed = true;
}
} else if (base == NullConstant.v() || isAlwaysNullBefore(s, (Local) base, defs)) {
createThrowStmt(body, s, lc);
changed = true;
}
}
}
}
if (changed)
UnreachableCodeEliminator.v().transform(body);
}
use of soot.jimple.AssignStmt in project soot by Sable.
the class DexNumTransformer method getNumCandidates.
/**
* Collect all the locals which are assigned a IntConstant(0) or are used
* within a zero comparison.
*
* @param body
* the body to analyze
*/
private Set<Local> getNumCandidates(Body body) {
Set<Local> candidates = new HashSet<Local>();
for (Unit u : body.getUnits()) {
if (u instanceof AssignStmt) {
AssignStmt a = (AssignStmt) u;
if (!(a.getLeftOp() instanceof Local))
continue;
Local l = (Local) a.getLeftOp();
Value r = a.getRightOp();
if ((r instanceof IntConstant || r instanceof LongConstant)) {
candidates.add(l);
}
}
}
return candidates;
}
use of soot.jimple.AssignStmt in project soot by Sable.
the class DexReturnValuePropagator method internalTransform.
@Override
protected void internalTransform(Body body, String phaseName, Map<String, String> options) {
ExceptionalUnitGraph graph = new ExceptionalUnitGraph(body, DalvikThrowAnalysis.v(), true);
LocalDefs localDefs = LocalDefs.Factory.newLocalDefs(graph);
LocalUses localUses = null;
LocalCreation localCreation = null;
// a copy statement, we take the original operand
for (Unit u : body.getUnits()) if (u instanceof ReturnStmt) {
ReturnStmt retStmt = (ReturnStmt) u;
if (retStmt.getOp() instanceof Local) {
List<Unit> defs = localDefs.getDefsOfAt((Local) retStmt.getOp(), retStmt);
if (defs.size() == 1 && defs.get(0) instanceof AssignStmt) {
AssignStmt assign = (AssignStmt) defs.get(0);
final Value rightOp = assign.getRightOp();
final Value leftOp = assign.getLeftOp();
// Copy over the left side if it is a local
if (rightOp instanceof Local) {
// to return a;
if (!isRedefined((Local) rightOp, u, assign, graph))
retStmt.setOp(rightOp);
} else if (rightOp instanceof Constant) {
retStmt.setOp(rightOp);
} else // we rename the local to help splitting
if (rightOp instanceof FieldRef) {
if (localUses == null)
localUses = LocalUses.Factory.newLocalUses(body, localDefs);
if (localUses.getUsesOf(assign).size() == 1) {
if (localCreation == null)
localCreation = new LocalCreation(body.getLocals(), "ret");
Local newLocal = localCreation.newLocal(leftOp.getType());
assign.setLeftOp(newLocal);
retStmt.setOp(newLocal);
}
}
}
}
}
}
Aggregations