/** * Returns basic block that contains the statement, or null. If id stmt, it looks in tag of first * non-id stmt. */ public static Block getBB(Stmt s) { Block bb; // 2010-02-26: return null when s == null if (s != null) { // move to first non-id stmt Stmt sNonId = s; if (sNonId instanceof IdentityStmt) { PatchingChain pchain = ProgramFlowGraph.inst().getContainingMethod(sNonId).retrieveActiveBody().getUnits(); do { sNonId = (Stmt) pchain.getSuccOf(sNonId); } while (sNonId instanceof IdentityStmt); } // retrieve basic block for non-id stmt StmtTag sTag = (StmtTag) sNonId.getTag(StmtTag.TAG_NAME); bb = sTag.getBasicBlock(); } else { bb = null; } return bb; }
private DUAAnalysis() { // prepare required collection and map List<SootMethod> allReachableMethods = ProgramFlowGraph.inst().getReachableAppMethods(); Map<SootMethod, ReachableUsesDefs> methodsToReachUseDefs = dua.util.Util.convertToRUMap(ProgramFlowGraph.inst().getMethodToCFGMap()); if (!Options.localDUAsOnly()) computeFieldArrayObjDUAs(allReachableMethods, methodsToReachUseDefs); // goal: find inter-proc uses for each param of each method (reachable from entry) // ReachableUses already inited param to local real uses, and linked params to local call uses // iteratively: // for each method, add to each param all real uses of call uses for that param ArrayList<SootMethod> worklist = new ArrayList<SootMethod>(allReachableMethods); int propCount = 1; while (!worklist.isEmpty()) { System.out.println("Inter-procedural reachable uses to params iteration #" + propCount++); for (SootMethod m : (ArrayList<SootMethod>) worklist.clone()) { worklist.remove(m); ReachableUsesDefs ru = methodsToReachUseDefs.get(m); if (ru.propagateAllUsesDefsToParams(methodsToReachUseDefs)) { MethodTag mTag = (MethodTag) m.getTag(MethodTag.TAG_NAME); for (SootMethod mCaller : mTag.getCallerMethods()) { MethodTag mCallerTag = (MethodTag) mCaller.getTag(MethodTag.TAG_NAME); if (mCallerTag.isReachableFromEntry()) worklist.add(mCaller); } } } } for (SootMethod m : allReachableMethods) { ReachableUsesDefs ru = methodsToReachUseDefs.get(m); // DEBUG ru.dumpReachUsesDefs(); ru.findLocalUsesDefsForDefs(methodsToReachUseDefs); } // for each def, create duas for local real uses and real uses of params in call uses // also, collect statistics // first, determine # interproc defs per use HashMap<Use, Integer> interProcDefsPerUse = new HashMap<Use, Integer>(); // maps use -> # interproc defs for (SootMethod m : allReachableMethods) { ReachableUsesDefs ru = methodsToReachUseDefs.get(m); HashMap<Def, HashMap<Use, ArrayList<Use>>> dus = ru.getDUs(); for (Def def : dus.keySet()) { Map<Use, ArrayList<Use>> usesMap = dus.get(def); for (Use use : usesMap.keySet()) { // determine and update # of interproc defs for use Integer numInterDefs = interProcDefsPerUse.get(use); if (numInterDefs == null) { numInterDefs = 0; interProcDefsPerUse.put(use, numInterDefs); // just init entry in map } } } } // create local var DUAs int cDuas = 0, pDuas = 0, cIntraOnly = 0, cInterOnly = 0, pIntraOnly = 0, pInterOnly = 0; int numKills = 0, minKills = Integer.MAX_VALUE, maxKills = 0; int possibleKills = 0, subsDuasWithPossKill = 0; ArrayList<Integer> useCallDepthsCount = new ArrayList<Integer>(); for (SootMethod m : allReachableMethods) { // methods are sorted if (verbose) System.out.print("Local-var duas for " + m + ": "); // build map stmt->idx ReachableUsesDefs ru = methodsToReachUseDefs.get(m); HashMap<Def, HashMap<Use, ArrayList<Use>>> dus = ru.getDUs(); HashMap<Def, HashSet<Def>> dds = ru.getDDs(); // determine subsumability and update stats for these DUAs / DDAs List<Def> sortedDefs = new ArrayList<Def>(dus.keySet()); Collections.sort(sortedDefs, new DefComparator()); for (Def def : sortedDefs) { HashSet<Def> defKills = dds.get(def); if (verbose) System.out.print(def + "={"); Map<Use, ArrayList<Use>> realToLocalUsesMap = dus.get(def); List<Use> sortedUses = new ArrayList<Use>(realToLocalUsesMap.keySet()); Collections.sort(sortedUses, new UseComparator()); for (Use use : sortedUses) { // determine type of use (c or p; intra or inter) PUse pUse = (use instanceof PUse) ? (PUse) use : null; // determine D-U node order, taking use's src statement first, and tgt if puse CFGNode nDef = def.getN(); CFGNode nUseSrc = use.getSrcNode(); CFGNode nUseTgt = (pUse == null) ? null : use.getBranch().getTgt(); Branch brUse = use.getBranch(); final boolean useReachesDef = Options.reachability() ? ((pUse == null) ? ReachabilityAnalysis.reachesFromTop(nUseSrc, nDef, true) : ReachabilityAnalysis.reachesFromTop(nUseTgt, nDef, true)) : true; // assume use reaches def, if no reachability analysis available final boolean duInNodeOrder = (pUse == null) ? orderGuaranteed(useReachesDef, nDef, nUseSrc) : orderGuaranteed(useReachesDef, nDef, brUse); // get # interproc defs for use final int numInterProcDefs = interProcDefsPerUse.get(use); // create and store DUA(s) // d-u event order is guaranteed if d-u node order is guaranteed, // and if use doesn't have multiple inter-proc defs // (p-uses with > 1 defs will be considered later) final boolean duEventOrderGuaranteed = duInNodeOrder && numInterProcDefs <= 1; ArrayList<Use> localUses = realToLocalUsesMap.get(use); Use[] localUsesArr = new Use[localUses.size()]; int uId = 0; for (Use u : localUses) localUsesArr[uId++] = u; DUA dua = new DUA(def, use, localUsesArr, duEventOrderGuaranteed); duaSet.addDUA(dua); // DEBUG if (verbose) System.out.print((duEventOrderGuaranteed ? "" : "(P)") + use + "["); // increment c-use/p-use counter if (pUse == null) ++cDuas; else ++pDuas; // determine kills for this DUA, and update kill stats int killsForThisDua = 0; int possKillsForThisDua = 0; if (defKills != null) { for (Def kill : defKills) { if (kill != def) { // get dus for kill's method SootMethod mKill = ProgramFlowGraph.inst().getContainingMethod(kill.getN().getStmt()); HashMap<Def, HashMap<Use, ArrayList<Use>>> killDUs = methodsToReachUseDefs.get(mKill).getDUs(); Set<Use> usesForKill = null; if (killDUs.get(kill) != null) usesForKill = killDUs.get(kill).keySet(); if (usesForKill != null && usesForKill.contains(use)) { // kills this DUA CFGNode nKill = kill.getN(); final boolean killAligned = orderGuaranteed(nDef, nKill, true) && ((pUse == null) ? orderGuaranteed(nKill, nUseSrc, true) : orderGuaranteed(nKill, brUse, true)); if (verbose) System.out.print((killAligned ? "" : "(P)") + kill + ","); ++killsForThisDua; // not only kill must be aligned, but use must not reach def if (!useReachesDef && killAligned) dua.addKillInOrder(kill); else { dua.addKillNotInOrder(kill); ++possKillsForThisDua; } } } } } numKills += killsForThisDua; if (killsForThisDua < minKills) minKills = killsForThisDua; if (killsForThisDua > maxKills) maxKills = killsForThisDua; possibleKills += possKillsForThisDua; if (duEventOrderGuaranteed) subsDuasWithPossKill += possKillsForThisDua; if (verbose) System.out.print("],"); } if (verbose) System.out.print("}, "); } // after regular DUAs, store same-BB dus duaSet.addSameBBDUs(ru.getSameBBDUs()); if (verbose) System.out.println(); } duaSet.updateInferrability(); // inferrability stats final int numAllDuas = duaSet.getAllDUAs().size(); int inferrDuas = 0, condInfDuas = 0, nonInfDuas = 0; int inferrDuasIntra = 0, condInfDuasIntra = 0, nonInfDuasIntra = 0; for (DUA dua : duaSet.getAllDUAs()) { SootMethod m = ProgramFlowGraph.inst().getContainingMethod(dua.getDef().getN().getStmt()); ReachableUsesDefs ru = methodsToReachUseDefs.get(m); if (dua.isInferrableOrCondInf()) { if (dua.isDefinitelyInferrable()) { ++inferrDuas; } else { ++condInfDuas; } } else { ++nonInfDuas; } } final int totalDuas = cDuas + pDuas; final int totalIntra = cIntraOnly + pIntraOnly; final int totalInter = cInterOnly + pInterOnly; System.out.println( "INFERRABILITY: inf " + inferrDuas + ", cond " + condInfDuas + ", non-inf " + (numAllDuas - inferrDuas - condInfDuas)); System.out.println( "INF: intra " + inferrDuasIntra + ", inter " + (inferrDuas - inferrDuasIntra)); System.out.println( "COND-INF: intra " + condInfDuasIntra + ", inter " + (condInfDuas - condInfDuasIntra)); assert nonInfDuasIntra == (totalIntra - inferrDuasIntra - condInfDuasIntra); System.out.println( "NON-INF: intra " + nonInfDuasIntra + ", inter " + (nonInfDuas - nonInfDuasIntra)); for (int i = 1; i < useCallDepthsCount.size(); ++i) System.out.print(i + ":" + useCallDepthsCount.get(i) + " "); System.out.println(); if (!useCallDepthsCount.isEmpty() && useCallDepthsCount.get(0) != totalDuas - totalInter) System.out.println( "NOTE -- DUAs at depth 0 are " + useCallDepthsCount.get(0) + ", but intra duas are " + (totalDuas - totalInter)); // // TEST // reportPaths(methodsToReachUseDefs); System.out.println( "DUA totals: " + totalDuas + "; c-duas " + cDuas + ", p-duas " + pDuas + "; intra " + totalIntra + ", inter " + totalInter + ", both " + (totalDuas - totalIntra - totalInter)); System.out.println( "c-DUAs intra " + cIntraOnly + ", inter " + cInterOnly + ", both " + (cDuas - cIntraOnly - cInterOnly) + "; p-DUAs intra " + pIntraOnly + ", inter " + pInterOnly + ", both " + (pDuas - pIntraOnly - pInterOnly)); }