package jqian.sootex.sideeffect; import java.util.*; import jqian.Global; import jqian.sootex.location.AccessPath; import jqian.sootex.location.HeapLocation; import jqian.sootex.location.InstanceObject; import jqian.sootex.location.Location; import jqian.sootex.location.HeapAbstraction; import jqian.sootex.ptsto.IPtsToQuery; import jqian.sootex.ptsto.PtsToHelper; import jqian.sootex.util.SootUtils; import jqian.util.Utils; import soot.*; import soot.jimple.toolkits.callgraph.*; import soot.toolkits.graph.DirectedGraph; import soot.toolkits.graph.PseudoTopologicalOrderer; /** * Context-insensitive side effect information collector. * When using context-insensitive pointer analysis, the side-effect sets of a method can be huge. * * TODO: Use some kinds of escape analysis to improve the analysis precision. * Filter the locations that have no chance to escape or are never used outside the method */ @SuppressWarnings({"rawtypes","unchecked"}) public class SideEffectAnalysis implements ISideEffectAnalysis{ private Collection _entries; private IPtsToQuery _ptsto; HeapAbstraction _heapAbstraction; private Set<Location>[] _method2ModHeaps; private Set<Location>[] _method2UseHeaps; private Set<Location>[] _method2ModGb; private Set<Location>[] _method2UseGb; public SideEffectAnalysis(IPtsToQuery ptsto,Collection entries, HeapAbstraction heapMemAbstraction){ this._entries = entries; this._ptsto = ptsto; this._heapAbstraction = heapMemAbstraction; } /**Get outer abstract locations that can be modified by a method.*/ public Collection<Location> getModGlobals(SootMethod m){ return _method2ModGb[m.getNumber()]; } public Collection<Location> getUseGlobals(SootMethod m){ return _method2UseGb[m.getNumber()]; } public Collection<Location> getModHeapLocs(SootMethod m){ return _method2ModHeaps[m.getNumber()]; } public Collection<Location> getUseHeapLocs(SootMethod m){ return _method2UseHeaps[m.getNumber()]; } void clearMethod(int id){ _method2ModHeaps[id] = null; _method2UseHeaps[id] = null; _method2ModGb[id] = null; _method2UseGb[id] = null; } private Set<InstanceObject> collectObjects(Collection<Location> locations){ Set<InstanceObject> objects = new HashSet<InstanceObject>(); for(Location loc: locations){ if(loc instanceof HeapLocation){ HeapLocation hLoc = (HeapLocation)loc; objects.add(hLoc.getWrapperObject()); } } return objects; } public Collection<InstanceObject> getModObjects(SootMethod m){ Collection<Location> locations = getModHeapLocs(m); return collectObjects(locations); } public Collection<InstanceObject> getUseObjects(SootMethod m){ Collection<Location> locations = getUseHeapLocs(m); return collectObjects(locations); } public void build(){ Date startBuild = new Date(); int methodNum = SootUtils.getMethodCount(); _method2ModHeaps = new Set[methodNum]; _method2UseHeaps = new Set[methodNum]; _method2ModGb = new Set[methodNum]; _method2UseGb = new Set[methodNum]; CallGraph cg = Scene.v().getCallGraph(); FastEscapeAnalysis escape = new FastEscapeAnalysis(cg); escape.build(); //1. get the collapse call graph, each strong connected component into a single graph node DirectedGraph graph = SootUtils.getSCCGraph(cg,_entries); //2. topological sort PseudoTopologicalOrderer pto = new PseudoTopologicalOrderer(); List order = pto.newList(graph,true); //3. bottom-up phase to find read/write on globals methodNum = 0; for(Iterator it=order.iterator();it.hasNext();){ Collection node = (Collection) it.next(); methodNum += node.size(); findRWGlobalsForComponent(node, cg); } //3. bottom-up phase to find read/write on instance fields for(Iterator it=order.iterator();it.hasNext();){ Collection node = (Collection) it.next(); findRWInstFieldsForComponent(node, cg, escape); } //free memories _entries = null; _ptsto = null; Date endBuild = new Date(); Global.v().out.println("[SideEffect]"+methodNum+" methods complete in "+ Utils.getTimeConsumed(startBuild,endBuild)+"."); } //return the number of all side effects for statistics private void findRWGlobalsForComponent(Collection methods, CallGraph cg){ Set mod = new HashSet(); Set use = new HashSet(); //intra-procedural analysis for(Iterator it = methods.iterator();it.hasNext();){ SootMethod m = (SootMethod)it.next(); SideEffectHelper.collectRWStaticFields(m,mod,use); } // collect from callees Set<SootMethod> callees = new HashSet(); SideEffectHelper.collectComponentCallees(methods,cg,callees); for(SootMethod tgt: callees){ int tgtId = tgt.getNumber(); mod.addAll(_method2ModGb[tgtId]); use.addAll(_method2UseGb[tgtId]); } mod = SideEffectHelper.compact(mod); use = SideEffectHelper.compact(use); for(Iterator it = methods.iterator();it.hasNext();){ SootMethod m=(SootMethod)it.next(); int id = m.getNumber(); _method2ModGb[id] = mod; _method2UseGb[id] = use; } } private void findRWInstFieldsForComponent(Collection methods, CallGraph cg, ILocalityQuery locality){ Set mod = new HashSet(); Set use = new HashSet(); //intra-procedural analysis for(Iterator it = methods.iterator();it.hasNext();){ SootMethod m = (SootMethod)it.next(); collectRWInstanceFields(m, _ptsto, locality, mod, use); } // collect from callees Set<SootMethod> callees = new HashSet(); SideEffectHelper.collectComponentCallees(methods,cg,callees); for(SootMethod tgt: callees){ int tgtId = tgt.getNumber(); mod.addAll(_method2ModHeaps[tgtId]); use.addAll(_method2UseHeaps[tgtId]); } mod = SideEffectHelper.compact(mod); use = SideEffectHelper.compact(use); for(Iterator it = methods.iterator();it.hasNext();){ SootMethod m=(SootMethod)it.next(); int id = m.getNumber(); _method2ModHeaps[id] = mod; _method2UseHeaps[id] = use; } } private void addSideEffect(IPtsToQuery ptrQuery, AccessPath ap, Set<Location> out) { Set<Location> locs = PtsToHelper.getAccessedLocations(ptrQuery, _heapAbstraction, null, ap); out.addAll(locs); } void collectRWInstanceFields(SootMethod m, IPtsToQuery ptsto, ILocalityQuery locality, Set<Location> mod, Set<Location> use) { Set<AccessPath> modAps = new HashSet<AccessPath>(); Set<AccessPath> useAps = new HashSet<AccessPath>(); SideEffectHelper.collectRWAccessPaths(m, locality, modAps, useAps); for(AccessPath ap: modAps){ addSideEffect(ptsto, ap, mod); } for(AccessPath ap: useAps){ addSideEffect(ptsto, ap, use); } } }