import soot.*; import soot.jimple.*; import soot.toolkits.scalar.*; import soot.toolkits.graph.*; import soot.util.*; import java.util.*; /** Tracks which locals are definitely non-null. * Author: Patrick Lam (plam@sable.mcgill.ca) * Based on BranchedRefVarsAnalysis by Janus Godard (janus@place.org). */ class NullnessAnalysis extends ForwardBranchedFlowAnalysis { protected void copy(Object src, Object dest) { FlowSet sourceSet = (FlowSet)src, destSet = (FlowSet) dest; sourceSet.copy(destSet); } protected void merge(Object src1, Object src2, Object dest) { FlowSet srcSet1 = (FlowSet) src1; FlowSet srcSet2 = (FlowSet) src2; FlowSet destSet = (FlowSet) dest; srcSet1.intersection(srcSet2, destSet); } FlowSet fullSet, emptySet; FlowUniverse allRefLocals; Map unitToGenerateSet; protected void flowThrough(Object srcValue, Unit unit, List fallOut, List branchOuts) { FlowSet dest; FlowSet src = (FlowSet) srcValue; Unit s = (Unit) unit; // Create working set. dest = (FlowSet)src.clone(); // Take out kill set. Iterator boxIt = s.getDefBoxes().iterator(); while (boxIt.hasNext()) { ValueBox box = (ValueBox) boxIt.next(); Value value = box.getValue(); if (value instanceof Local && value.getType() instanceof RefLikeType) dest.remove(value); } // Perform gen. dest.union((FlowSet)unitToGenerateSet.get(unit), dest); // Handle copy statements: // x = y && 'y' in src => add 'x' to dest if (s instanceof DefinitionStmt) { DefinitionStmt as = (DefinitionStmt) s; Value ro = as.getRightOp(); // extract cast argument if (ro instanceof CastExpr) ro = ((CastExpr) ro).getOp(); if (src.contains(ro) && as.getLeftOp() instanceof Local) dest.add(as.getLeftOp()); } // Copy the out value to the fallthrough box (don't need iterator) { Iterator it = fallOut.iterator(); while (it.hasNext()) { FlowSet fs = (FlowSet) (it.next()); copy(dest, fs); } } // Copy the out value to all branch boxes. { Iterator it = branchOuts.iterator(); while (it.hasNext()) { FlowSet fs = (FlowSet) (it.next()); copy(dest, fs); } } // Handle if statements by patching dest sets. if (unit instanceof IfStmt) { Value cond = ((IfStmt)unit).getCondition(); Value op1 = ((BinopExpr) cond).getOp1(); Value op2 = ((BinopExpr) cond).getOp2(); boolean isNeg = cond instanceof NeExpr; Value toGen = null; // case 1: opN is a local and opM is NullConstant // => opN nonnull on ne branch. if (op1 instanceof Local && op2 instanceof NullConstant) toGen = op1; if (op2 instanceof Local && op1 instanceof NullConstant) toGen = op2; if (toGen != null) { Iterator it = null; // if (toGen != null) goto l1: on branch, toGen nonnull. if (isNeg) it = branchOuts.iterator(); else it = fallOut.iterator(); while(it.hasNext()) { FlowSet fs = (FlowSet) (it.next()); fs.add(toGen); } } // case 2: both ops are local and one op is non-null and testing equality if (op1 instanceof Local && op2 instanceof Local && cond instanceof EqExpr) { toGen = null; if (src.contains(op1)) toGen = op2; if (src.contains(op2)) toGen = op1; if (toGen != null) { Iterator branchIt = branchOuts.iterator(); while (branchIt.hasNext()) { FlowSet fs = (FlowSet) (branchIt.next()); fs.add(toGen); } } } } } protected Object newInitialFlow() { return fullSet.clone(); } protected Object entryInitialFlow() { // everything could be null return emptySet.clone(); } private void addGen(Unit u, Value v) { ArraySparseSet l = (ArraySparseSet)unitToGenerateSet.get(u); l.add(v); } private void addGensFor(DefinitionStmt u) { Value lo = u.getLeftOp(); Value ro = u.getRightOp(); if (ro instanceof NewExpr || ro instanceof NewArrayExpr || ro instanceof NewMultiArrayExpr || ro instanceof ThisRef || ro instanceof CaughtExceptionRef) addGen(u, lo); } public NullnessAnalysis(UnitGraph g) { super(g); unitToGenerateSet = new HashMap(); Body b = g.getBody(); List refLocals = new LinkedList(); // set up universe, empty, full sets. emptySet = new ArraySparseSet(); fullSet = new ArraySparseSet(); // Find all locals in body. Iterator localIt = b.getLocals().iterator(); while (localIt.hasNext()) { Local l = (Local)localIt.next(); if (l.getType() instanceof RefLikeType) fullSet.add(l); } // Create gen sets. Iterator unitIt = b.getUnits().iterator(); while (unitIt.hasNext()) { Unit u = (Unit)unitIt.next(); unitToGenerateSet.put(u, new ArraySparseSet()); if (u instanceof DefinitionStmt) { Value lo = ((DefinitionStmt)u).getLeftOp(); if (lo instanceof Local && lo.getType() instanceof RefLikeType) addGensFor((DefinitionStmt)u); } Iterator boxIt = u.getUseAndDefBoxes().iterator(); while (boxIt.hasNext()) { Value boxValue = ((ValueBox) boxIt.next()).getValue(); Value base = null; if(boxValue instanceof InstanceFieldRef) { base = ((InstanceFieldRef) (boxValue)).getBase(); } else if (boxValue instanceof ArrayRef) { base = ((ArrayRef) (boxValue)).getBase(); } else if (boxValue instanceof InstanceInvokeExpr) { base = ((InstanceInvokeExpr) boxValue).getBase(); } else if (boxValue instanceof LengthExpr) { base = ((LengthExpr) boxValue).getOp(); } else if (u instanceof ThrowStmt) { base = ((ThrowStmt)u).getOp(); } else if (u instanceof MonitorStmt) { base = ((MonitorStmt)u).getOp(); } if (base != null && base instanceof Local && base.getType() instanceof RefLikeType) addGen(u, base); } } // Call superclass method to do work. doAnalysis(); } }