use of soot.UnknownType in project soot by Sable.
the class LocalNameStandardizer method internalTransform.
@Override
protected void internalTransform(Body body, String phaseName, Map<String, String> options) {
boolean onlyStackName = PhaseOptions.getBoolean(options, "only-stack-locals");
boolean sortLocals = PhaseOptions.getBoolean(options, "sort-locals");
final BooleanType booleanType = BooleanType.v();
final ByteType byteType = ByteType.v();
final ShortType shortType = ShortType.v();
final CharType charType = CharType.v();
final IntType intType = IntType.v();
final LongType longType = LongType.v();
final DoubleType doubleType = DoubleType.v();
final FloatType floatType = FloatType.v();
final ErroneousType erroneousType = ErroneousType.v();
final UnknownType unknownType = UnknownType.v();
final StmtAddressType stmtAddressType = StmtAddressType.v();
final NullType nullType = NullType.v();
// Change the names to the standard forms now.
{
int objectCount = 0;
int intCount = 0;
int longCount = 0;
int floatCount = 0;
int doubleCount = 0;
int addressCount = 0;
int errorCount = 0;
int nullCount = 0;
/* The goal of this option is to ensure that local ordering remains
* consistent between different iterations of soot. This helps to ensure
* things like stable string representations of instructions and stable
* jimple representations of a methods body when soot is used to load
* the same code in different iterations.
*
* First sorts the locals alphabetically by the string representation of
* their type. Then if there are two locals with the same type, it uses
* the only other source of structurally stable information (i.e. the
* instructions themselves) to produce an ordering for the locals
* that remains consistent between different soot instances. It achieves
* this by determining the position of a local's first occurrence in the
* instruction's list of definition statements. This position is then used
* to sort the locals with the same type in an ascending order.
*
* The only times that this may not produce a consistent ordering for the
* locals between different soot instances is if a local is never defined in
* the instructions or if the instructions themselves are changed in some way
* that effects the ordering of the locals. In the first case, if a local is
* never defined, the other jimple body phases will remove this local as it is
* unused. As such, all we have to do is rerun this LocalNameStandardizer after
* all other jimple body phases to eliminate any ambiguity introduced by these
* phases and by the removed unused locals. In the second case, if the instructions
* themselves changed then the user would have had to intentionally told soot to
* modify the instructions of the code. Otherwise, the instructions would not have
* changed because we assume the instructions to always be structurally stable
* between different instances of soot. As such, in this instance, the user should
* not be expecting soot to produce the same output as the input and thus the
* ordering of the locals does not matter.
*/
if (sortLocals) {
Chain<Local> locals = body.getLocals();
final List<ValueBox> defs = body.getDefBoxes();
ArrayList<Local> sortedLocals = new ArrayList<Local>(locals);
Collections.sort(sortedLocals, new Comparator<Local>() {
private Map<Local, Integer> firstOccuranceCache = new HashMap<Local, Integer>();
@Override
public int compare(Local arg0, Local arg1) {
int ret = arg0.getType().toString().compareTo(arg1.getType().toString());
if (ret == 0) {
ret = Integer.compare(getFirstOccurance(arg0), getFirstOccurance(arg1));
}
return ret;
}
private int getFirstOccurance(Local l) {
Integer cur = firstOccuranceCache.get(l);
if (cur != null) {
return cur;
} else {
int count = 0;
int first = -1;
for (ValueBox vb : defs) {
Value v = vb.getValue();
if (v instanceof Local && v.equals(l)) {
first = count;
break;
}
count++;
}
firstOccuranceCache.put(l, first);
return first;
}
}
});
locals.clear();
locals.addAll(sortedLocals);
}
for (Local l : body.getLocals()) {
String prefix = "";
if (l.getName().startsWith("$"))
prefix = "$";
else {
if (onlyStackName)
continue;
}
final Type type = l.getType();
if (type.equals(booleanType))
l.setName(prefix + "z" + intCount++);
else if (type.equals(byteType))
l.setName(prefix + "b" + longCount++);
else if (type.equals(shortType))
l.setName(prefix + "s" + longCount++);
else if (type.equals(charType))
l.setName(prefix + "c" + longCount++);
else if (type.equals(intType))
l.setName(prefix + "i" + longCount++);
else if (type.equals(longType))
l.setName(prefix + "l" + longCount++);
else if (type.equals(doubleType))
l.setName(prefix + "d" + doubleCount++);
else if (type.equals(floatType))
l.setName(prefix + "f" + floatCount++);
else if (type.equals(stmtAddressType))
l.setName(prefix + "a" + addressCount++);
else if (type.equals(erroneousType) || type.equals(unknownType)) {
l.setName(prefix + "e" + errorCount++);
} else if (type.equals(nullType))
l.setName(prefix + "n" + nullCount++);
else
l.setName(prefix + "r" + objectCount++);
}
}
}
use of soot.UnknownType in project soot by Sable.
the class AbstractThrowAnalysis method mightThrowExplicitly.
public ThrowableSet mightThrowExplicitly(ThrowStmt t) {
Value thrownExpression = t.getOp();
Type thrownType = thrownExpression.getType();
if (thrownType == null || thrownType instanceof UnknownType) {
// We can't identify the type of thrownExpression, so...
return ThrowableSet.Manager.v().ALL_THROWABLES;
} else if (thrownType instanceof NullType) {
ThrowableSet result = ThrowableSet.Manager.v().EMPTY;
result = result.add(ThrowableSet.Manager.v().NULL_POINTER_EXCEPTION);
return result;
} else if (!(thrownType instanceof RefType)) {
throw new IllegalStateException("UnitThrowAnalysis StmtSwitch: type of throw argument is not a RefType!");
} else {
ThrowableSet result = ThrowableSet.Manager.v().EMPTY;
if (thrownExpression instanceof NewInvokeExpr) {
// In this case, we know the exact type of the
// argument exception.
result = result.add((RefType) thrownType);
} else {
result = result.add(AnySubType.v((RefType) thrownType));
}
return result;
}
}
use of soot.UnknownType in project soot by Sable.
the class SootASMClassWriterTest method setUp.
@Before
public void setUp() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
mockStatic(Scene.class);
mockStatic(RefType.class);
mockStatic(UnknownType.class);
scene = mock(Scene.class);
when(Scene.v()).thenReturn(scene);
UnknownType unknown = mock(UnknownType.class);
when(UnknownType.v()).thenReturn(unknown);
sc1 = mockClass("A");
sc2 = mockClass("B");
type1 = RefType.v("A");
type2 = RefType.v("B");
object = mockClass("java.lang.Object");
objectType = mock(RefType.class);
when(object.getType()).thenReturn(objectType);
when(Scene.v().getObjectType()).thenReturn(objectType);
when(objectType.getSootClass()).thenReturn(object);
when(objectType.getClassName()).thenReturn("java.lang.Object");
when(type1.merge(type2, scene)).thenCallRealMethod();
commonSuperClass = mockClass("C");
commonSuperClass.setResolvingLevel(SootClass.HIERARCHY);
when(commonSuperClass.getSuperclass()).thenReturn(object);
when(commonSuperClass.getSuperclassUnsafe()).thenReturn(object);
cw = mock(SootASMClassWriter.class);
when(cw.getCommonSuperClass("A", "B")).thenCallRealMethod();
}
use of soot.UnknownType 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.UnknownType 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
}
Aggregations