private void searchRef(StringArrayRef ref, Loop loop) { String temp_name = ref.getArrayName(); Iterator<Unit> iter = loop.getBodyBlocks().get(0).getBody().getUnits().iterator(); while (iter.hasNext()) { Unit curr = iter.next(); if (defines(curr, temp_name) && curr instanceof AssignStmt) { AssignStmt assign = (AssignStmt) curr; Value right = assign.getRightOp(); if (right instanceof FieldRef) { FieldRef field_ref = (FieldRef) right; ref.setFieldSignature(field_ref.getField().getSignature()); ref.setField(field_ref.getField().getName()); } } } }
private static boolean internalAggregate( StmtBody body, Map<ValueBox, Zone> boxToZone, boolean onlyStackVars) { LocalUses localUses; LocalDefs localDefs; ExceptionalUnitGraph graph; boolean hadAggregation = false; Chain<Unit> units = body.getUnits(); graph = new ExceptionalUnitGraph(body); localDefs = new SmartLocalDefs(graph, new SimpleLiveLocals(graph)); localUses = new SimpleLocalUses(graph, localDefs); List<Unit> unitList = new PseudoTopologicalOrderer<Unit>().newList(graph, false); for (Unit u : unitList) { if (!(u instanceof AssignStmt)) continue; AssignStmt s = (AssignStmt) u; Value lhs = s.getLeftOp(); if (!(lhs instanceof Local)) continue; Local lhsLocal = (Local) lhs; if (onlyStackVars && !lhsLocal.getName().startsWith("$")) continue; List<UnitValueBoxPair> lu = localUses.getUsesOf(s); if (lu.size() != 1) continue; UnitValueBoxPair usepair = lu.get(0); Unit use = usepair.unit; ValueBox useBox = usepair.valueBox; List<Unit> ld = localDefs.getDefsOfAt(lhsLocal, use); if (ld.size() != 1) continue; // Check to make sure aggregation pair in the same zone if (boxToZone.get(s.getRightOpBox()) != boxToZone.get(usepair.valueBox)) { continue; } /* we need to check the path between def and use */ /* to see if there are any intervening re-defs of RHS */ /* in fact, we should check that this path is unique. */ /* if the RHS uses only locals, then we know what to do; if RHS has a method invocation f(a, b, c) or field access, we must ban field writes, other method calls and (as usual) writes to a, b, c. */ boolean cantAggr = false; boolean propagatingInvokeExpr = false; boolean propagatingFieldRef = false; boolean propagatingArrayRef = false; ArrayList<FieldRef> fieldRefList = new ArrayList<FieldRef>(); LinkedList<Value> localsUsed = new LinkedList<Value>(); for (ValueBox vb : s.getUseBoxes()) { Value v = vb.getValue(); if (v instanceof Local) localsUsed.add(v); else if (v instanceof InvokeExpr) propagatingInvokeExpr = true; else if (v instanceof ArrayRef) propagatingArrayRef = true; else if (v instanceof FieldRef) { propagatingFieldRef = true; fieldRefList.add((FieldRef) v); } } // look for a path from s to use in graph. // only look in an extended basic block, though. List<Unit> path = graph.getExtendedBasicBlockPathBetween(s, use); if (path == null) continue; Iterator<Unit> pathIt = path.iterator(); // skip s. if (pathIt.hasNext()) pathIt.next(); while (pathIt.hasNext() && !cantAggr) { Stmt between = (Stmt) (pathIt.next()); if (between != use) { // Check for killing definitions for (ValueBox vb : between.getDefBoxes()) { Value v = vb.getValue(); if (localsUsed.contains(v)) { cantAggr = true; break; } if (propagatingInvokeExpr || propagatingFieldRef || propagatingArrayRef) { if (v instanceof FieldRef) { if (propagatingInvokeExpr) { cantAggr = true; break; } else if (propagatingFieldRef) { // Can't aggregate a field access if passing a definition of a field // with the same name, because they might be aliased for (FieldRef fieldRef : fieldRefList) { if (((FieldRef) v).getField() == fieldRef.getField()) { cantAggr = true; break; } } } } else if (v instanceof ArrayRef) { if (propagatingInvokeExpr) { // Cannot aggregate an invoke expr past an array write cantAggr = true; break; } else if (propagatingArrayRef) { // cannot aggregate an array read past a write // this is somewhat conservative // (if types differ they may not be aliased) cantAggr = true; break; } } } } // Make sure not propagating past a {enter,exit}Monitor if (propagatingInvokeExpr && between instanceof MonitorStmt) cantAggr = true; } // Check for intervening side effects due to method calls if (propagatingInvokeExpr || propagatingFieldRef || propagatingArrayRef) { for (final ValueBox box : between.getUseBoxes()) { if (between == use && box == useBox) { // Reached use point, stop looking for // side effects break; } Value v = box.getValue(); if (v instanceof InvokeExpr || (propagatingInvokeExpr && (v instanceof FieldRef || v instanceof ArrayRef))) { cantAggr = true; break; } } } } // we give up: can't aggregate. if (cantAggr) { continue; } /* assuming that the d-u chains are correct, */ /* we need not check the actual contents of ld */ Value aggregatee = s.getRightOp(); if (usepair.valueBox.canContainValue(aggregatee)) { boolean wasSimpleCopy = isSimpleCopy(usepair.unit); usepair.valueBox.setValue(aggregatee); units.remove(s); hadAggregation = true; // clean up the tags. If s was not a simple copy, the new statement should get // the tags of s. // OK, this fix was wrong. The condition should not be // "If s was not a simple copy", but rather "If usepair.unit // was a simple copy". This way, when there's a load of a constant // followed by an invoke, the invoke gets the tags. if (wasSimpleCopy) { // usepair.unit.removeAllTags(); usepair.unit.addAllTagsOf(s); } } else { /* if(Options.v().verbose()) { G.v().out.println("[debug] failed aggregation"); G.v().out.println("[debug] tried to put "+aggregatee+ " into "+usepair.stmt + ": in particular, "+usepair.valueBox); G.v().out.println("[debug] aggregatee instanceof Expr: " +(aggregatee instanceof Expr)); }*/ } } return hadAggregation; }
@Override public Type appliesInternal(AndroidMethod method) { SootMethod sm = getSootMethod(method); // We are only interested in getters and setters if (!sm.getName().startsWith("get") && !sm.getName().startsWith("set")) return Type.NOT_SUPPORTED; String baseName = sm.getName().substring(3); String getterName = "get" + baseName; String setterName = "set" + baseName; try { // Find the getter and the setter SootMethod getter = getSootMethod(new AndroidMethod(getterName, "", sm.getDeclaringClass().getName())); SootMethod setter = getSootMethod(new AndroidMethod(setterName, "", sm.getDeclaringClass().getName())); if (getter == null || setter == null) return Type.FALSE; if (!setter.isConcrete() || !getter.isConcrete()) return Type.NOT_SUPPORTED; Body bodyGetter = null; try { bodyGetter = getter.retrieveActiveBody(); } catch (Exception ex) { return Type.NOT_SUPPORTED; } // Find the local that gets returned Local returnLocal = null; for (Unit u : bodyGetter.getUnits()) if (u instanceof ReturnStmt) { ReturnStmt ret = (ReturnStmt) u; if (ret.getOp() instanceof Local) { returnLocal = (Local) ret.getOp(); break; } } if (returnLocal == null) return Type.FALSE; // Find where the local is assigned a value in the code List<FieldRef> accessPath = new ArrayList<FieldRef>(); Local returnBase = returnLocal; while (returnBase != null) for (Unit u : bodyGetter.getUnits()) { if (u instanceof AssignStmt) { AssignStmt assign = (AssignStmt) u; if (assign.getLeftOp().equals(returnBase)) if (assign.getRightOp() instanceof InstanceFieldRef) { InstanceFieldRef ref = (InstanceFieldRef) assign.getRightOp(); accessPath.add(0, ref); returnBase = (Local) ref.getBase(); break; } else returnBase = null; } else if (u instanceof IdentityStmt) { IdentityStmt id = (IdentityStmt) u; if (id.getLeftOp().equals(returnBase)) returnBase = null; } } if (accessPath.isEmpty()) return Type.FALSE; /* // Find the corresponding access path in the setter for (Unit u : bodySetter.getUnits()) if (u instanceof AssignStmt) { AssignStmt assign = (AssignStmt) u; if (assign.getLeftOp() instanceof InstanceFieldRef && assign.getRightOp() instanceof Local) { InstanceFieldRef iref = (InstanceFieldRef) assign.getLeftOp(); if (iref.getFieldRef().toString().equals(accessPath.get(accessPath.size() - 1).getFieldRef().toString())) { // This is a starting point boolean pathFound = false; Local startLocal = (Local) iref.getBase(); int accessPathPos = accessPath.size() - 2; while (startLocal != null) { for (Unit u2 : bodySetter.getUnits()) { if (u2 instanceof AssignStmt) { AssignStmt assign2 = (AssignStmt) u2; if (assign2.getLeftOp().equals(startLocal)) if (assign2.getRightOp() instanceof InstanceFieldRef) { InstanceFieldRef ref = (InstanceFieldRef) assign2.getRightOp(); if (accessPath.get(accessPathPos--).getFieldRef().toString().equals(ref.getFieldRef().toString())) { startLocal = (Local) ref.getBase(); break; } else startLocal = null; } else startLocal = null; } else if (u2 instanceof IdentityStmt) { IdentityStmt id = (IdentityStmt) u2; if (id.getLeftOp().equals(startLocal)) { startLocal = null; pathFound = true; break; } } } } if (pathFound) { if (assign.getRightOp() instanceof Local) { // Find the parameter being set for (Unit u2 : bodySetter.getUnits()) if (u2 instanceof IdentityStmt) { IdentityStmt id = (IdentityStmt) u2; if (id.getLeftOp().equals(assign.getRightOp())) return Type.TRUE; } } break; } } } } return Type.FALSE; */ return Type.TRUE; } catch (Exception ex) { System.err.println("Something went wrong:"); ex.printStackTrace(); return Type.NOT_SUPPORTED; } }