use of soot.UnknownType in project soot by Sable.
the class DeadAssignmentEliminator method internalTransform.
/**
* Eliminates dead code in a linear fashion. Complexity is linear
* with respect to the statements.
*
* Does not work on grimp code because of the check on the right hand
* side for side effects.
*/
@Override
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
boolean eliminateOnlyStackLocals = PhaseOptions.getBoolean(options, "only-stack-locals");
final Options soptions = Options.v();
if (soptions.verbose()) {
logger.debug("[" + b.getMethod().getName() + "] Eliminating dead code...");
}
if (soptions.time()) {
Timers.v().deadCodeTimer.start();
}
Chain<Unit> units = b.getUnits();
Deque<Unit> q = new ArrayDeque<Unit>(units.size());
// Make a first pass through the statements, noting
// the statements we must absolutely keep.
boolean isStatic = b.getMethod().isStatic();
boolean allEssential = true;
boolean checkInvoke = false;
Local thisLocal = null;
for (Iterator<Unit> it = units.iterator(); it.hasNext(); ) {
Unit s = it.next();
boolean isEssential = true;
if (s instanceof NopStmt) {
// Hack: do not remove nop if is is used for a Trap
// which is at the very end of the code.
boolean removeNop = it.hasNext();
if (!removeNop) {
removeNop = true;
for (Trap t : b.getTraps()) {
if (t.getEndUnit() == s) {
removeNop = false;
break;
}
}
}
if (removeNop) {
it.remove();
continue;
}
} else if (s instanceof AssignStmt) {
AssignStmt as = (AssignStmt) s;
Value lhs = as.getLeftOp();
Value rhs = as.getRightOp();
// Stmt is of the form a = a which is useless
if (lhs == rhs && lhs instanceof Local) {
it.remove();
continue;
}
if (lhs instanceof Local && (!eliminateOnlyStackLocals || ((Local) lhs).getName().startsWith("$") || lhs.getType() instanceof NullType)) {
isEssential = false;
if (!checkInvoke) {
checkInvoke = as.containsInvokeExpr();
}
if (rhs instanceof CastExpr) {
// CastExpr : can trigger ClassCastException, but null-casts never fail
CastExpr ce = (CastExpr) rhs;
Type t = ce.getCastType();
Value v = ce.getOp();
isEssential = !(v instanceof NullConstant && t instanceof RefType);
} else if (rhs instanceof InvokeExpr || rhs instanceof ArrayRef || rhs instanceof NewExpr || rhs instanceof NewArrayExpr || rhs instanceof NewMultiArrayExpr) {
// ArrayRef : can have side effects (like throwing a null pointer exception)
// InvokeExpr : can have side effects (like throwing a null pointer exception)
// NewArrayExpr : can throw exception
// NewMultiArrayExpr : can throw exception
// NewExpr : can trigger class initialization
isEssential = true;
} else if (rhs instanceof FieldRef) {
// Can trigger class initialization
isEssential = true;
if (rhs instanceof InstanceFieldRef) {
InstanceFieldRef ifr = (InstanceFieldRef) rhs;
if (!isStatic && thisLocal == null) {
thisLocal = b.getThisLocal();
}
// Any InstanceFieldRef may have side effects,
// unless the base is reading from 'this'
// in a non-static method
isEssential = (isStatic || thisLocal != ifr.getBase());
}
} else if (rhs instanceof DivExpr || rhs instanceof RemExpr) {
BinopExpr expr = (BinopExpr) rhs;
Type t1 = expr.getOp1().getType();
Type t2 = expr.getOp2().getType();
// Can trigger a division by zero
boolean t2Int = t2 instanceof IntType;
isEssential = t2Int || t1 instanceof IntType || t1 instanceof LongType || t2 instanceof LongType || t1 instanceof UnknownType || t2 instanceof UnknownType;
if (isEssential && t2Int) {
Value v = expr.getOp2();
if (v instanceof IntConstant) {
IntConstant i = (IntConstant) v;
isEssential = (i.value == 0);
} else
// could be 0, we don't know
isEssential = true;
}
if (isEssential && t2 instanceof LongType) {
Value v = expr.getOp2();
if (v instanceof LongConstant) {
LongConstant l = (LongConstant) v;
isEssential = (l.value == 0);
} else
// could be 0, we don't know
isEssential = true;
}
}
}
}
if (isEssential) {
q.addFirst(s);
}
allEssential &= isEssential;
}
if (checkInvoke || !allEssential) {
// Add all the statements which are used to compute values
// for the essential statements, recursively
final LocalDefs localDefs = LocalDefs.Factory.newLocalDefs(b);
if (!allEssential) {
Set<Unit> essential = new HashSet<Unit>(b.getUnits().size());
while (!q.isEmpty()) {
Unit s = q.removeFirst();
if (essential.add(s)) {
for (ValueBox box : s.getUseBoxes()) {
Value v = box.getValue();
if (v instanceof Local) {
Local l = (Local) v;
List<Unit> defs = localDefs.getDefsOfAt(l, s);
if (defs != null)
q.addAll(defs);
}
}
}
}
// Remove the dead statements
units.retainAll(essential);
}
if (checkInvoke) {
final LocalUses localUses = LocalUses.Factory.newLocalUses(b, localDefs);
// Eliminate dead assignments from invokes such as x = f(), where
// x is no longer used
List<AssignStmt> postProcess = new ArrayList<AssignStmt>();
for (Unit u : units) {
if (u instanceof AssignStmt) {
AssignStmt s = (AssignStmt) u;
if (s.containsInvokeExpr()) {
// Just find one use of l which is essential
boolean deadAssignment = true;
for (UnitValueBoxPair pair : localUses.getUsesOf(s)) {
if (units.contains(pair.unit)) {
deadAssignment = false;
break;
}
}
if (deadAssignment) {
postProcess.add(s);
}
}
}
}
final Jimple jimple = Jimple.v();
for (AssignStmt s : postProcess) {
// Transform it into a simple invoke.
Stmt newInvoke = jimple.newInvokeStmt(s.getInvokeExpr());
newInvoke.addAllTagsOf(s);
units.swapWith(s, newInvoke);
// If we have a callgraph, we need to fix it
if (Scene.v().hasCallGraph())
Scene.v().getCallGraph().swapEdgesOutOf(s, newInvoke);
}
}
}
if (soptions.time()) {
Timers.v().deadCodeTimer.end();
}
}
use of soot.UnknownType in project soot by Sable.
the class DalvikTyper method assignType.
@Override
public void assignType(final Body b) {
// Debug.printDbg("assignTypes: before: \n", b);
constraints.clear();
localObjList.clear();
final Set<Unit> todoUnits = new HashSet<Unit>();
// put constraints:
for (Unit u : b.getUnits()) {
StmtSwitch ss = new StmtSwitch() {
@Override
public void caseBreakpointStmt(BreakpointStmt stmt) {
// nothing
}
@Override
public void caseInvokeStmt(InvokeStmt stmt) {
// add constraint
DalvikTyper.v().setInvokeType(stmt.getInvokeExpr());
}
@Override
public void caseAssignStmt(AssignStmt stmt) {
// add constraint
Value l = stmt.getLeftOp();
Value r = stmt.getRightOp();
// size in new array expression is of tye integer
if (r instanceof NewArrayExpr) {
NewArrayExpr nae = (NewArrayExpr) r;
ValueBox sb = nae.getSizeBox();
if (sb.getValue() instanceof Local) {
DalvikTyper.v().setType(sb, IntType.v(), true);
}
}
// array index is of type integer
if (stmt.containsArrayRef()) {
ArrayRef ar = stmt.getArrayRef();
ValueBox sb = ar.getIndexBox();
if (sb.getValue() instanceof Local) {
DalvikTyper.v().setType(sb, IntType.v(), true);
}
}
if (l instanceof Local && r instanceof Local) {
DalvikTyper.v().addConstraint(stmt.getLeftOpBox(), stmt.getRightOpBox());
return;
}
if (stmt.containsInvokeExpr()) {
DalvikTyper.v().setInvokeType(stmt.getInvokeExpr());
}
if (r instanceof Local) {
// l NOT local
Type leftType = stmt.getLeftOp().getType();
if (l instanceof ArrayRef && leftType instanceof UnknownType) {
// find type later
todoUnits.add(stmt);
return;
}
DalvikTyper.v().setType(stmt.getRightOpBox(), leftType, true);
return;
}
if (l instanceof Local) {
if (r instanceof UntypedConstant)
return;
for (Tag t : stmt.getTags()) {
if (r instanceof CastExpr) {
// do not check tag, since the tag is for the operand of the cast
break;
}
// Debug.printDbg("assign stmt tag: ", stmt, t);
if (t instanceof IntOpTag) {
checkExpr(r, IntType.v());
DalvikTyper.v().setType(stmt.getLeftOpBox(), IntType.v(), false);
return;
} else if (t instanceof FloatOpTag) {
checkExpr(r, FloatType.v());
DalvikTyper.v().setType(stmt.getLeftOpBox(), FloatType.v(), false);
return;
} else if (t instanceof DoubleOpTag) {
checkExpr(r, DoubleType.v());
DalvikTyper.v().setType(stmt.getLeftOpBox(), DoubleType.v(), false);
return;
} else if (t instanceof LongOpTag) {
checkExpr(r, LongType.v());
DalvikTyper.v().setType(stmt.getLeftOpBox(), LongType.v(), false);
return;
}
}
Type rightType = stmt.getRightOp().getType();
if (r instanceof ArrayRef && rightType instanceof UnknownType) {
// find type later
todoUnits.add(stmt);
return;
} else if (r instanceof CastExpr) {
CastExpr ce = (CastExpr) r;
Type castType = ce.getCastType();
if (castType instanceof PrimType) {
// check incoming primitive type
for (Tag t : stmt.getTags()) {
// Debug.printDbg("assign primitive type from stmt tag: ", stmt, t);
if (t instanceof IntOpTag) {
DalvikTyper.v().setType(ce.getOpBox(), IntType.v(), false);
return;
} else if (t instanceof FloatOpTag) {
DalvikTyper.v().setType(ce.getOpBox(), FloatType.v(), false);
return;
} else if (t instanceof DoubleOpTag) {
DalvikTyper.v().setType(ce.getOpBox(), DoubleType.v(), false);
return;
} else if (t instanceof LongOpTag) {
DalvikTyper.v().setType(ce.getOpBox(), LongType.v(), false);
return;
}
}
} else {
// incoming type is object
DalvikTyper.v().setType(ce.getOpBox(), RefType.v("java.lang.Object"), false);
}
}
DalvikTyper.v().setType(stmt.getLeftOpBox(), rightType, false);
return;
}
}
@Override
public void caseIdentityStmt(IdentityStmt stmt) {
DalvikTyper.v().setType(stmt.getLeftOpBox(), stmt.getRightOp().getType(), false);
}
@Override
public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
// add constraint
DalvikTyper.v().setType(stmt.getOpBox(), RefType.v("java.lang.Object"), true);
}
@Override
public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
// add constraint
DalvikTyper.v().setType(stmt.getOpBox(), RefType.v("java.lang.Object"), true);
}
@Override
public void caseGotoStmt(GotoStmt stmt) {
// nothing
}
@Override
public void caseIfStmt(IfStmt stmt) {
// add constraint
Value c = stmt.getCondition();
if (c instanceof BinopExpr) {
BinopExpr bo = (BinopExpr) c;
Value op1 = bo.getOp1();
Value op2 = bo.getOp2();
if (op1 instanceof Local && op2 instanceof Local) {
DalvikTyper.v().addConstraint(bo.getOp1Box(), bo.getOp2Box());
}
}
}
@Override
public void caseLookupSwitchStmt(LookupSwitchStmt stmt) {
// add constraint
DalvikTyper.v().setType(stmt.getKeyBox(), IntType.v(), true);
}
@Override
public void caseNopStmt(NopStmt stmt) {
// nothing
}
@Override
public void caseRetStmt(RetStmt stmt) {
// nothing
}
@Override
public void caseReturnStmt(ReturnStmt stmt) {
// add constraint
DalvikTyper.v().setType(stmt.getOpBox(), b.getMethod().getReturnType(), true);
}
@Override
public void caseReturnVoidStmt(ReturnVoidStmt stmt) {
// nothing
}
@Override
public void caseTableSwitchStmt(TableSwitchStmt stmt) {
// add constraint
DalvikTyper.v().setType(stmt.getKeyBox(), IntType.v(), true);
}
@Override
public void caseThrowStmt(ThrowStmt stmt) {
// add constraint
DalvikTyper.v().setType(stmt.getOpBox(), RefType.v("java.lang.Object"), true);
}
@Override
public void defaultCase(Object obj) {
throw new RuntimeException("error: unknown statement: " + obj);
}
};
u.apply(ss);
}
// <com.admob.android.ads.q: void a(android.os.Bundle,java.lang.String,java.lang.Object)>
if (!todoUnits.isEmpty()) {
// propagate array types
UnitGraph ug = new ExceptionalUnitGraph(b);
SimpleLocalDefs sld = new SimpleLocalDefs(ug);
SimpleLocalUses slu = new SimpleLocalUses(b, sld);
for (Unit u : b.getUnits()) {
if (u instanceof DefinitionStmt) {
// Debug.printDbg("U: ", u);
DefinitionStmt ass = (DefinitionStmt) u;
Value r = ass.getRightOp();
if (r instanceof UntypedConstant)
continue;
Type rType = r.getType();
if (rType instanceof ArrayType && ass.getLeftOp() instanceof Local) {
// Debug.printDbg("propagate-array: checking ", u);
// propagate array type through aliases
Set<Unit> done = new HashSet<Unit>();
Set<DefinitionStmt> toDo = new HashSet<DefinitionStmt>();
toDo.add(ass);
while (!toDo.isEmpty()) {
DefinitionStmt currentUnit = toDo.iterator().next();
if (done.contains(currentUnit)) {
toDo.remove(currentUnit);
continue;
}
done.add(currentUnit);
for (UnitValueBoxPair uvbp : slu.getUsesOf(currentUnit)) {
Unit use = uvbp.unit;
Value l2 = null;
Value r2 = null;
if (use instanceof AssignStmt) {
AssignStmt ass2 = (AssignStmt) use;
l2 = ass2.getLeftOp();
r2 = ass2.getRightOp();
if (!(l2 instanceof Local) || !(r2 instanceof Local || r2 instanceof ArrayRef)) {
// Debug.printDbg("propagate-array: skipping ", use);
continue;
}
Type newType = null;
if (r2 instanceof Local) {
List<LocalObj> lobjs = local2Obj.get(r2);
newType = lobjs.get(0).t;
} else if (r2 instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) r2;
// skip if use is in index
if (ar.getIndex() == currentUnit.getLeftOp()) {
// Debug.printDbg("skipping since local is used as index...");
continue;
}
Local arBase = (Local) ar.getBase();
List<LocalObj> lobjs = local2Obj.get(arBase);
Type baseT = lobjs.get(0).t;
if (baseT.toString().equals(("java.lang.Object"))) {
// look for an array type, because an TTT[] is also an Object...
ArrayType aTypeOtherThanObject = null;
for (LocalObj lo : local2Obj.get(arBase)) {
if (lo.t instanceof ArrayType) {
aTypeOtherThanObject = (ArrayType) lo.t;
}
}
if (aTypeOtherThanObject == null) {
throw new RuntimeException("error: did not found array type for base " + arBase + " " + local2Obj.get(arBase) + " \n " + b);
}
baseT = aTypeOtherThanObject;
}
ArrayType at = (ArrayType) baseT;
newType = at.getElementType();
} else {
throw new RuntimeException("error: expected Local or ArrayRef. Got " + r2);
}
toDo.add((DefinitionStmt) use);
DalvikTyper.v().setType(ass2.getLeftOpBox(), newType, true);
}
}
}
}
}
}
for (Unit u : todoUnits) {
// Debug.printDbg("todo unit: ", u);
}
while (!todoUnits.isEmpty()) {
Unit u = todoUnits.iterator().next();
if (!(u instanceof AssignStmt)) {
throw new RuntimeException("error: expecting assign stmt. Got " + u);
}
AssignStmt ass = (AssignStmt) u;
Value l = ass.getLeftOp();
Value r = ass.getRightOp();
ArrayRef ar = null;
Local loc = null;
if (l instanceof ArrayRef) {
ar = (ArrayRef) l;
loc = (Local) r;
} else if (r instanceof ArrayRef) {
ar = (ArrayRef) r;
loc = (Local) l;
} else {
throw new RuntimeException("error: expecting an array ref. Got " + u);
}
Local baselocal = (Local) ar.getBase();
if (!local2Obj.containsKey(baselocal)) {
// Debug.printDbg("b: ", b.getMethod(), " \n", b);
throw new RuntimeException("oups");
}
Type baseT = local2Obj.get(baselocal).get(0).t;
if (baseT.toString().equals(("java.lang.Object"))) {
// look for an array type, because an TTT[] is also an Object...
ArrayType aTypeOtherThanObject = null;
for (LocalObj lo : local2Obj.get(baselocal)) {
if (lo.t instanceof ArrayType) {
aTypeOtherThanObject = (ArrayType) lo.t;
}
}
if (aTypeOtherThanObject == null) {
throw new RuntimeException("did not found array type for base " + baselocal + " " + local2Obj.get(baselocal) + " \n " + b);
}
baseT = aTypeOtherThanObject;
}
ArrayType basetype = (ArrayType) baseT;
// Debug.printDbg("v: ", ar, " base:", ar.getBase(), " base type: ", basetype, " type: ", ar.getType());
Type t = basetype.getElementType();
if (t instanceof UnknownType) {
todoUnits.add(u);
continue;
} else {
DalvikTyper.v().setType(ar == l ? ass.getRightOpBox() : ass.getLeftOpBox(), t, true);
todoUnits.remove(u);
}
}
// throw new RuntimeException("ouppppp");
}
// Debug.printDbg(IDalvikTyper.DEBUG, "list of constraints:");
List<ValueBox> vbList = b.getUseAndDefBoxes();
// clear constraints after local splitting and dead code eliminator
List<Constraint> toRemove = new ArrayList<Constraint>();
for (Constraint c : constraints) {
if (!vbList.contains(c.l)) {
// Debug.printDbg(IDalvikTyper.DEBUG, "warning: ", c.l, " not in locals! removing...");
toRemove.add(c);
continue;
}
if (!vbList.contains(c.r)) {
// Debug.printDbg(IDalvikTyper.DEBUG, "warning: ", c.r, " not in locals! removing...");
toRemove.add(c);
continue;
}
}
for (Constraint c : toRemove) constraints.remove(c);
// keep only valid locals
for (LocalObj lo : localObjList) {
if (!vbList.contains(lo.vb)) {
// Debug.printDbg(IDalvikTyper.DEBUG, " -- removing vb: ", lo.vb, " with type ", lo.t);
continue;
}
Local l = lo.getLocal();
Type t = lo.t;
if (localTemp.contains(l) && lo.isUse) {
// Debug.printDbg(IDalvikTyper.DEBUG, " /!\\ def already added for local ", l, "! for vb: ", lo.vb);
} else {
// Debug.printDbg(IDalvikTyper.DEBUG, " * add type ", t, " to local ", l, " for vb: ", lo.vb);
localTemp.add(l);
typed.put(lo.vb, t);
}
}
for (ValueBox vb : typed.keySet()) {
if (vb.getValue() instanceof Local) {
Local l = (Local) vb.getValue();
localTyped.put(l, typed.get(vb));
}
}
for (Constraint c : constraints) // Debug.printDbg(IDalvikTyper.DEBUG, " -> constraint: ", c);
for (ValueBox vb : typed.keySet()) {
// Debug.printDbg(IDalvikTyper.DEBUG, " typed: ", vb, " -> ", typed.get(vb));
}
for (Local l : localTyped.keySet()) {
// Debug.printDbg(IDalvikTyper.DEBUG, " localTyped: ", l, " -> ", localTyped.get(l));
}
while (!constraints.isEmpty()) {
boolean update = false;
for (Constraint c : constraints) {
// Debug.printDbg(IDalvikTyper.DEBUG, "current constraint: ", c);
Value l = c.l.getValue();
Value r = c.r.getValue();
if (l instanceof Local && r instanceof Constant) {
Constant cst = (Constant) r;
if (!localTyped.containsKey(l))
continue;
Type lt = localTyped.get(l);
// Debug.printDbg(IDalvikTyper.DEBUG, "would like to set type ", lt, " to constant: ", c);
Value newValue = null;
if (lt instanceof IntType || lt instanceof BooleanType || lt instanceof ShortType || lt instanceof CharType || lt instanceof ByteType) {
UntypedIntOrFloatConstant uf = (UntypedIntOrFloatConstant) cst;
newValue = uf.toIntConstant();
} else if (lt instanceof FloatType) {
UntypedIntOrFloatConstant uf = (UntypedIntOrFloatConstant) cst;
newValue = uf.toFloatConstant();
} else if (lt instanceof DoubleType) {
UntypedLongOrDoubleConstant ud = (UntypedLongOrDoubleConstant) cst;
newValue = ud.toDoubleConstant();
} else if (lt instanceof LongType) {
UntypedLongOrDoubleConstant ud = (UntypedLongOrDoubleConstant) cst;
newValue = ud.toLongConstant();
} else {
if (cst instanceof UntypedIntOrFloatConstant && ((UntypedIntOrFloatConstant) cst).value == 0) {
newValue = NullConstant.v();
// Debug.printDbg("new null constant for constraint ", c, " with l type: ", localTyped.get(l));
} else {
throw new RuntimeException("unknow type for constance: " + lt);
}
}
c.r.setValue(newValue);
// Debug.printDbg(IDalvikTyper.DEBUG, "remove constraint: ", c);
constraints.remove(c);
update = true;
break;
} else if (l instanceof Local && r instanceof Local) {
Local leftLocal = (Local) l;
Local rightLocal = (Local) r;
if (localTyped.containsKey(leftLocal)) {
Type leftLocalType = localTyped.get(leftLocal);
if (!localTyped.containsKey(rightLocal)) {
// Debug.printDbg(IDalvikTyper.DEBUG, "set type ", leftLocalType, " to local ", rightLocal);
rightLocal.setType(leftLocalType);
setLocalTyped(rightLocal, leftLocalType);
}
// Debug.printDbg(IDalvikTyper.DEBUG, "remove constraint: ", c);
constraints.remove(c);
update = true;
break;
} else if (localTyped.containsKey(rightLocal)) {
Type rightLocalType = localTyped.get(rightLocal);
if (!localTyped.containsKey(leftLocal)) {
// Debug.printDbg(IDalvikTyper.DEBUG, "set type ", rightLocalType, " to local ", leftLocal);
leftLocal.setType(rightLocalType);
setLocalTyped(leftLocal, rightLocalType);
}
// Debug.printDbg(IDalvikTyper.DEBUG, "remove constraint: ", c);
constraints.remove(c);
update = true;
break;
}
} else if (l instanceof ArrayRef && r instanceof Local) {
Local rightLocal = (Local) r;
ArrayRef ar = (ArrayRef) l;
Local base = (Local) ar.getBase();
// Debug.printDbg(IDalvikTyper.DEBUG, "index: ", ar.getIndex());
if (localTyped.containsKey(base)) {
Type t = localTyped.get(base);
// Debug.printDbg(IDalvikTyper.DEBUG, "type of local1: ", t, " ", t.getClass());
Type elementType = null;
if (t instanceof ArrayType) {
ArrayType at = (ArrayType) t;
elementType = at.getArrayElementType();
} else {
continue;
}
if (!localTyped.containsKey(rightLocal)) {
// Debug.printDbg(IDalvikTyper.DEBUG, "set type ", elementType, " to local ", r);
rightLocal.setType(elementType);
setLocalTyped(rightLocal, elementType);
}
// Debug.printDbg(IDalvikTyper.DEBUG, "remove constraint: ", c);
constraints.remove(c);
update = true;
break;
}
} else if (l instanceof Local && r instanceof ArrayRef) {
Local leftLocal = (Local) l;
ArrayRef ar = (ArrayRef) r;
Local base = (Local) ar.getBase();
if (localTyped.containsKey(base)) {
Type t = localTyped.get(base);
// Debug.printDbg(IDalvikTyper.DEBUG, "type of local2: ", t, " ", t.getClass());
Type elementType = null;
if (t instanceof ArrayType) {
ArrayType at = (ArrayType) t;
elementType = at.getArrayElementType();
} else {
continue;
}
if (!localTyped.containsKey(leftLocal)) {
// Debug.printDbg(IDalvikTyper.DEBUG, "set type ", elementType, " to local ", l);
leftLocal.setType(elementType);
setLocalTyped(leftLocal, elementType);
}
// Debug.printDbg(IDalvikTyper.DEBUG, "remove constraint: ", c);
constraints.remove(c);
update = true;
break;
}
} else {
throw new RuntimeException("error: do not handling this kind of constraint: " + c);
}
}
if (!update)
break;
}
for (Unit u : b.getUnits()) {
if (!(u instanceof AssignStmt))
continue;
AssignStmt ass = (AssignStmt) u;
if (!(ass.getLeftOp() instanceof Local))
continue;
if (!(ass.getRightOp() instanceof UntypedConstant))
continue;
UntypedConstant uc = (UntypedConstant) ass.getRightOp();
ass.setRightOp(uc.defineType(localTyped.get(ass.getLeftOp())));
}
//
for (Constraint c : constraints) {
// Debug.printDbg(IDalvikTyper.DEBUG, "current constraint: ", c);
Value l = c.l.getValue();
Value r = c.r.getValue();
if (l instanceof Local && r instanceof Constant) {
if (r instanceof UntypedIntOrFloatConstant) {
UntypedIntOrFloatConstant cst = (UntypedIntOrFloatConstant) r;
Value newValue = null;
if (cst.value != 0) {
// Debug.printDbg(IDalvikTyper.DEBUG, "[untyped constaints] set type int to non zero constant: ", c, " = ", cst.value);
newValue = cst.toIntConstant();
} else {
// check if used in cast, just in case...
for (Unit u : b.getUnits()) {
for (ValueBox vb1 : u.getUseBoxes()) {
Value v1 = vb1.getValue();
if (v1 == l) {
// Debug.printDbg("local used in ", u);
if (u instanceof AssignStmt) {
AssignStmt a = (AssignStmt) u;
Value right = a.getRightOp();
if (right instanceof CastExpr) {
newValue = NullConstant.v();
} else {
newValue = cst.toIntConstant();
}
} else if (u instanceof IfStmt) {
// TODO check this better
newValue = cst.toIntConstant();
}
}
}
}
}
if (newValue == null) {
throw new RuntimeException("error: no type found for local: " + l);
}
c.r.setValue(newValue);
} else if (r instanceof UntypedLongOrDoubleConstant) {
// Debug.printDbg(IDalvikTyper.DEBUG, "[untyped constaints] set type long to constant: ", c);
Value newValue = ((UntypedLongOrDoubleConstant) r).toLongConstant();
c.r.setValue(newValue);
}
}
}
// fix untypedconstants which have flown to an array index
for (Unit u : b.getUnits()) {
StmtSwitch sw = new StmtSwitch() {
@Override
public void caseBreakpointStmt(BreakpointStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseInvokeStmt(InvokeStmt stmt) {
changeUntypedConstantsInInvoke(stmt.getInvokeExpr());
}
@Override
public void caseAssignStmt(AssignStmt stmt) {
if (stmt.getRightOp() instanceof NewArrayExpr) {
NewArrayExpr nae = (NewArrayExpr) stmt.getRightOp();
if (nae.getSize() instanceof UntypedConstant) {
UntypedIntOrFloatConstant uc = (UntypedIntOrFloatConstant) nae.getSize();
nae.setSize(uc.defineType(IntType.v()));
}
} else if (stmt.getRightOp() instanceof UntypedConstant) {
UntypedConstant uc = (UntypedConstant) stmt.getRightOp();
Value l = stmt.getLeftOp();
Type lType = null;
if (l instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) l;
Local baseLocal = (Local) ar.getBase();
ArrayType arrayType = (ArrayType) localTyped.get(baseLocal);
lType = arrayType.getElementType();
} else {
lType = l.getType();
}
stmt.setRightOp(uc.defineType(lType));
} else if (stmt.getRightOp() instanceof InvokeExpr) {
changeUntypedConstantsInInvoke((InvokeExpr) stmt.getRightOp());
}
if (!stmt.containsArrayRef()) {
return;
}
ArrayRef ar = stmt.getArrayRef();
if ((ar.getIndex() instanceof UntypedConstant)) {
UntypedIntOrFloatConstant uc = (UntypedIntOrFloatConstant) ar.getIndex();
ar.setIndex(uc.toIntConstant());
}
if (stmt.getLeftOp() instanceof ArrayRef && stmt.getRightOp() instanceof UntypedConstant) {
UntypedConstant uc = (UntypedConstant) stmt.getRightOp();
Local baseLocal = (Local) stmt.getArrayRef().getBase();
ArrayType lType = (ArrayType) localTyped.get(baseLocal);
Type elemType = lType.getElementType();
stmt.setRightOp(uc.defineType(elemType));
}
}
@Override
public void caseIdentityStmt(IdentityStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseGotoStmt(GotoStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseIfStmt(IfStmt stmt) {
Value c = stmt.getCondition();
if (c instanceof BinopExpr) {
BinopExpr be = (BinopExpr) c;
Value op1 = be.getOp1();
Value op2 = be.getOp2();
if (op1 instanceof UntypedConstant || op2 instanceof UntypedConstant) {
if (op1 instanceof Local) {
Type t = localTyped.get(op1);
// Debug.printDbg("if op1 type: ", t);
UntypedConstant uc = (UntypedConstant) op2;
be.setOp2(uc.defineType(t));
} else if (op2 instanceof Local) {
Type t = localTyped.get(op2);
// Debug.printDbg("if op2 type: ", t);
UntypedConstant uc = (UntypedConstant) op1;
be.setOp1(uc.defineType(t));
} else if (op1 instanceof UntypedConstant && op2 instanceof UntypedConstant) {
if (op1 instanceof UntypedIntOrFloatConstant && op2 instanceof UntypedIntOrFloatConstant) {
UntypedIntOrFloatConstant uc1 = (UntypedIntOrFloatConstant) op1;
UntypedIntOrFloatConstant uc2 = (UntypedIntOrFloatConstant) op2;
// to int or float, it does not matter
be.setOp1(uc1.toIntConstant());
be.setOp2(uc2.toIntConstant());
} else if (op1 instanceof UntypedLongOrDoubleConstant && op2 instanceof UntypedLongOrDoubleConstant) {
UntypedLongOrDoubleConstant uc1 = (UntypedLongOrDoubleConstant) op1;
UntypedLongOrDoubleConstant uc2 = (UntypedLongOrDoubleConstant) op2;
// to long or double, it does not matter
be.setOp1(uc1.toLongConstant());
be.setOp2(uc2.toLongConstant());
} else {
throw new RuntimeException("error: expected same type of untyped constants. Got " + stmt);
}
} else if (op1 instanceof UntypedConstant || op2 instanceof UntypedConstant) {
if (op1 instanceof UntypedConstant) {
UntypedConstant uc = (UntypedConstant) op1;
be.setOp1(uc.defineType(op2.getType()));
} else if (op2 instanceof UntypedConstant) {
UntypedConstant uc = (UntypedConstant) op2;
be.setOp2(uc.defineType(op1.getType()));
}
} else {
throw new RuntimeException("error: expected local/untyped untyped/local or untyped/untyped. Got " + stmt);
}
}
} else if (c instanceof UnopExpr) {
} else {
throw new RuntimeException("error: expected binop or unop. Got " + stmt);
}
}
@Override
public void caseLookupSwitchStmt(LookupSwitchStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseNopStmt(NopStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseRetStmt(RetStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseReturnStmt(ReturnStmt stmt) {
if (stmt.getOp() instanceof UntypedConstant) {
UntypedConstant uc = (UntypedConstant) stmt.getOp();
Type type = b.getMethod().getReturnType();
stmt.setOp(uc.defineType(type));
}
}
@Override
public void caseReturnVoidStmt(ReturnVoidStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseTableSwitchStmt(TableSwitchStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void caseThrowStmt(ThrowStmt stmt) {
// TODO Auto-generated method stub
}
@Override
public void defaultCase(Object obj) {
// TODO Auto-generated method stub
}
};
u.apply(sw);
}
// fix untyped constants remaining
// Debug.printDbg("assignTypes: after: \n", b);
}
use of soot.UnknownType in project soot by Sable.
the class DalvikTyper method setType.
@Override
public void setType(ValueBox vb, Type t, boolean isUse) {
if (IDalvikTyper.DEBUG)
if (t instanceof UnknownType) {
throw new RuntimeException("error: expected concreted type. Got " + t);
}
if (vb.getValue() instanceof Local) {
LocalObj lb = new LocalObj(vb, t, isUse);
localObjList.add(lb);
Local k = (Local) vb.getValue();
if (!local2Obj.containsKey(k)) {
local2Obj.put(k, new ArrayList<LocalObj>());
}
local2Obj.get(k).add(lb);
} else {
// Debug.printDbg(IDalvikTyper.DEBUG, "not instance of local: vb: ", vb, " value: ", vb.getValue(), " class: ", vb.getValue().getClass());
}
}
use of soot.UnknownType in project soot by Sable.
the class DexNumTransformer method internalTransform.
@Override
protected void internalTransform(final Body body, String phaseName, Map<String, String> options) {
final DexDefUseAnalysis localDefs = new DexDefUseAnalysis(body);
for (Local loc : getNumCandidates(body)) {
usedAsFloatingPoint = false;
Set<Unit> defs = localDefs.collectDefinitionsWithAliases(loc);
// process normally
doBreak = false;
for (Unit u : defs) {
// put correct local in l
final Local l = u instanceof DefinitionStmt ? (Local) ((DefinitionStmt) u).getLeftOp() : null;
// check defs
u.apply(new AbstractStmtSwitch() {
@Override
public void caseAssignStmt(AssignStmt stmt) {
Value r = stmt.getRightOp();
if (r instanceof BinopExpr && !(r instanceof CmpExpr)) {
usedAsFloatingPoint = examineBinopExpr(stmt);
doBreak = true;
} else if (r instanceof FieldRef) {
usedAsFloatingPoint = isFloatingPointLike(((FieldRef) r).getFieldRef().type());
doBreak = true;
} else if (r instanceof NewArrayExpr) {
NewArrayExpr nae = (NewArrayExpr) r;
Type t = nae.getType();
usedAsFloatingPoint = isFloatingPointLike(t);
doBreak = true;
} else if (r instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) r;
Type arType = ar.getType();
if (arType instanceof UnknownType) {
Type t = findArrayType(localDefs, stmt, 0, // TODO:
Collections.<Unit>emptySet());
// check
// where
// else
// to
// update
// if(ArrayRef...
usedAsFloatingPoint = isFloatingPointLike(t);
} else {
usedAsFloatingPoint = isFloatingPointLike(ar.getType());
}
doBreak = true;
} else if (r instanceof CastExpr) {
usedAsFloatingPoint = isFloatingPointLike(((CastExpr) r).getCastType());
doBreak = true;
} else if (r instanceof InvokeExpr) {
usedAsFloatingPoint = isFloatingPointLike(((InvokeExpr) r).getType());
doBreak = true;
} else if (r instanceof LengthExpr) {
usedAsFloatingPoint = false;
doBreak = true;
}
}
@Override
public void caseIdentityStmt(IdentityStmt stmt) {
if (stmt.getLeftOp() == l) {
usedAsFloatingPoint = isFloatingPointLike(stmt.getRightOp().getType());
doBreak = true;
}
}
});
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 && isFloatingPointLike(argTypes.get(i))) {
return true;
}
}
return false;
}
@Override
public void caseInvokeStmt(InvokeStmt stmt) {
InvokeExpr e = stmt.getInvokeExpr();
usedAsFloatingPoint = examineInvokeExpr(e);
}
@Override
public void caseAssignStmt(AssignStmt stmt) {
// only case where 'l' could be on the left side is
// arrayRef with 'l' as the index
Value left = stmt.getLeftOp();
if (left instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) left;
if (ar.getIndex() == l) {
doBreak = true;
return;
}
}
// from this point, we only check the right hand
// side of the assignment
Value r = stmt.getRightOp();
if (r instanceof ArrayRef) {
if (((ArrayRef) r).getIndex() == l) {
doBreak = true;
return;
}
} else if (r instanceof InvokeExpr) {
usedAsFloatingPoint = examineInvokeExpr((InvokeExpr) r);
doBreak = true;
return;
} else if (r instanceof BinopExpr) {
usedAsFloatingPoint = examineBinopExpr(stmt);
doBreak = true;
return;
} else if (r instanceof CastExpr) {
usedAsFloatingPoint = stmt.hasTag("FloatOpTag") || stmt.hasTag("DoubleOpTag");
doBreak = true;
return;
} else if (r instanceof Local && r == l) {
if (left instanceof FieldRef) {
FieldRef fr = (FieldRef) left;
if (isFloatingPointLike(fr.getType())) {
usedAsFloatingPoint = true;
}
doBreak = true;
return;
} else if (left instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) left;
Type arType = ar.getType();
if (arType instanceof UnknownType) {
arType = findArrayType(localDefs, stmt, 0, Collections.<Unit>emptySet());
}
usedAsFloatingPoint = isFloatingPointLike(arType);
doBreak = true;
return;
}
}
}
@Override
public void caseReturnStmt(ReturnStmt stmt) {
usedAsFloatingPoint = stmt.getOp() == l && isFloatingPointLike(body.getMethod().getReturnType());
doBreak = true;
return;
}
});
if (doBreak)
break;
}
// for uses
if (doBreak)
break;
}
// change values
if (usedAsFloatingPoint) {
for (Unit u : defs) {
replaceWithFloatingPoint(u);
}
}
// end if
}
}
use of soot.UnknownType in project soot by Sable.
the class DexNullTransformer method internalTransform.
@Override
protected void internalTransform(final Body body, String phaseName, Map<String, String> options) {
final DexDefUseAnalysis localDefs = new DexDefUseAnalysis(body);
AbstractStmtSwitch checkDef = new // Alex: should also end as
AbstractStmtSwitch() {
// 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());
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());
}
doBreak = true;
return;
} else if (r instanceof StringConstant || r instanceof NewExpr || r instanceof NewArrayExpr) {
usedAsObject = true;
doBreak = true;
return;
} else if (r instanceof CastExpr) {
usedAsObject = isObject(((CastExpr) r).getCastType());
doBreak = true;
return;
} else if (r instanceof InvokeExpr) {
usedAsObject = isObject(((InvokeExpr) r).getType());
doBreak = true;
return;
} else if (r instanceof LengthExpr) {
usedAsObject = false;
doBreak = true;
return;
// introduces alias
}
}
@Override
public void caseIdentityStmt(IdentityStmt stmt) {
if (stmt.getLeftOp() == l) {
usedAsObject = isObject(stmt.getRightOp().getType());
doBreak = true;
return;
}
}
};
AbstractStmtSwitch checkUse = 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);
doBreak = true;
return;
}
@Override
public void caseAssignStmt(AssignStmt stmt) {
Value left = stmt.getLeftOp();
Value r = stmt.getRightOp();
if (left instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) left;
if (ar.getIndex() == l) {
doBreak = true;
return;
} else if (ar.getBase() == l) {
usedAsObject = true;
doBreak = true;
return;
}
}
if (left instanceof InstanceFieldRef) {
InstanceFieldRef ifr = (InstanceFieldRef) left;
if (ifr.getBase() == l) {
usedAsObject = true;
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;
doBreak = true;
return;
} else if (l instanceof InstanceFieldRef && isObject(((InstanceFieldRef) l).getFieldRef().type())) {
usedAsObject = true;
doBreak = true;
return;
} else if (l instanceof ArrayRef) {
Type aType = ((ArrayRef) l).getType();
if (aType instanceof UnknownType) {
usedAsObject = stmt.hasTag(// isObject(
"ObjectOpTag");
// findArrayType(g,
// localDefs,
// localUses,
// stmt));
} else {
usedAsObject = isObject(aType);
}
doBreak = true;
return;
}
}
// is used as value (does not exclude assignment)
if (r instanceof FieldRef) {
// isObject(((FieldRef)
usedAsObject = true;
// r).getFieldRef().type());
doBreak = true;
return;
} else if (r instanceof ArrayRef) {
ArrayRef ar = (ArrayRef) r;
if (ar.getBase() == l) {
usedAsObject = true;
} else {
// used as index
usedAsObject = false;
}
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;
doBreak = true;
return;
} else if (r instanceof CastExpr) {
usedAsObject = isObject(((CastExpr) r).getCastType());
doBreak = true;
return;
} else if (r instanceof InvokeExpr) {
usedAsObject = examineInvokeExpr((InvokeExpr) stmt.getRightOp());
doBreak = true;
return;
} else if (r instanceof LengthExpr) {
usedAsObject = true;
doBreak = true;
return;
} else if (r instanceof BinopExpr) {
usedAsObject = false;
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;
doBreak = true;
return;
}
@Override
public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
usedAsObject = stmt.getOp() == l;
doBreak = true;
return;
}
@Override
public void caseReturnStmt(ReturnStmt stmt) {
usedAsObject = stmt.getOp() == l && isObject(body.getMethod().getReturnType());
doBreak = true;
return;
}
@Override
public void caseThrowStmt(ThrowStmt stmt) {
usedAsObject = stmt.getOp() == l;
doBreak = true;
return;
}
};
for (Local loc : getNullCandidates(body)) {
usedAsObject = false;
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 if (u instanceof IfStmt) {
throw new RuntimeException("ERROR: def can not be something else than Assign or Identity statement! (def: " + u + " class: " + u.getClass() + "");
}
// check defs
u.apply(checkDef);
if (doBreak)
break;
// check uses
for (Unit use : localDefs.getUsesOf(l)) {
use.apply(checkUse);
if (doBreak)
break;
}
// for uses
if (doBreak)
break;
}
// change values
if (usedAsObject) {
for (Unit u : defs) {
replaceWithNull(u);
Set<Value> defLocals = new HashSet<Value>();
for (ValueBox vb : u.getDefBoxes()) defLocals.add(vb.getValue());
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() || !defLocals.contains(use.getArrayRef().getBase()))
replaceWithNull(use);
}
}
}
// end if
}
// Check for inlined zero values
AbstractStmtSwitch inlinedZeroValues = new AbstractStmtSwitch() {
final NullConstant nullConstant = NullConstant.v();
@Override
public void caseAssignStmt(AssignStmt stmt) {
// Case a = 0 with a being an object
if (isObject(stmt.getLeftOp().getType()) && isConstZero(stmt.getRightOp())) {
stmt.setRightOp(nullConstant);
return;
}
// Case a = (Object) 0
if (stmt.getRightOp() instanceof CastExpr) {
CastExpr ce = (CastExpr) stmt.getRightOp();
if (isObject(ce.getCastType()) && isConstZero(ce.getOp())) {
stmt.setRightOp(nullConstant);
}
}
// Case a[0] = 0
if (stmt.getLeftOp() instanceof ArrayRef && isConstZero(stmt.getRightOp())) {
ArrayRef ar = (ArrayRef) stmt.getLeftOp();
if (isObjectArray(ar.getBase(), body) || stmt.hasTag("ObjectOpTag")) {
stmt.setRightOp(nullConstant);
}
}
}
private boolean isConstZero(Value rightOp) {
if (rightOp instanceof IntConstant && ((IntConstant) rightOp).value == 0)
return true;
if (rightOp instanceof LongConstant && ((LongConstant) rightOp).value == 0)
return true;
return false;
}
@Override
public void caseReturnStmt(ReturnStmt stmt) {
if (stmt.getOp() instanceof IntConstant && isObject(body.getMethod().getReturnType())) {
IntConstant iconst = (IntConstant) stmt.getOp();
assert iconst.value == 0;
stmt.setOp(nullConstant);
}
}
@Override
public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
if (stmt.getOp() instanceof IntConstant && ((IntConstant) stmt.getOp()).value == 0)
stmt.setOp(nullConstant);
}
@Override
public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
if (stmt.getOp() instanceof IntConstant && ((IntConstant) stmt.getOp()).value == 0)
stmt.setOp(nullConstant);
}
};
final NullConstant nullConstant = NullConstant.v();
for (Unit u : body.getUnits()) {
u.apply(inlinedZeroValues);
if (u instanceof Stmt) {
Stmt stmt = (Stmt) u;
if (stmt.containsInvokeExpr()) {
InvokeExpr invExpr = stmt.getInvokeExpr();
for (int i = 0; i < invExpr.getArgCount(); i++) if (isObject(invExpr.getMethodRef().parameterType(i)))
if (invExpr.getArg(i) instanceof IntConstant) {
IntConstant iconst = (IntConstant) invExpr.getArg(i);
assert iconst.value == 0;
invExpr.setArg(i, nullConstant);
}
}
}
}
}
Aggregations