/* Soot - a J*va Optimization Framework * Copyright (C) 2005 Antoine Mine * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * Implementation of the paper "A Combined Pointer and Purity Analysis for * Java Programs" by Alexandru Salcianu and Martin Rinard, within the * Soot Optimization Framework. * * by Antoine Mine, 2005/01/24 */ package soot.jimple.toolkits.annotation.purity; import java.util.*; import soot.*; import soot.util.*; import soot.jimple.toolkits.callgraph.*; import soot.toolkits.graph.*; /** * Builds a DirectedGraph from a CallGraph and SootMethodFilter. * * This is used in AbstractInterproceduralAnalysis to construct a reverse * pseudo topological order on which to iterate. * You can specify a SootMethodFilter to trim the graph by cutting * call edges strarting * * Methods filtered-out by the SootMethodFilter will not appear in the * DirectedGraph! */ public class DirectedCallGraph implements DirectedGraph { protected Set nodes; protected Map<Object,List> succ; protected Map<Object,List> pred; protected List heads; protected List tails; protected int size; /** * The constructor does all the work here. * After constructed, you can safely use all interface methods. * Moreover, these methods should perform very fastly... * * The DirectedGraph will only contain methods in call paths from a method * in head and comprising only methods wanted by filter. * Moreover, only concrete methods are put in the graph... * * @param heads is a List of SootMethod */ public DirectedCallGraph(CallGraph cg, SootMethodFilter filter, Iterator heads, boolean verbose) { // filter heads by filter List filteredHeads = new LinkedList(); while (heads.hasNext()) { SootMethod m = (SootMethod) heads.next(); if (m.isConcrete() && filter.want(m)) filteredHeads.add(m); } this.nodes = new HashSet(filteredHeads); MultiMap s = new HashMultiMap(); MultiMap p = new HashMultiMap(); // simple breadth-first visit Set remain = new HashSet(filteredHeads); int nb = 0; if (verbose) G.v().out.println("[AM] dumping method dependencies"); while (!remain.isEmpty()) { Set newRemain = new HashSet(); Iterator it = remain.iterator(); while (it.hasNext()) { SootMethod m = (SootMethod)it.next(); Iterator itt = cg.edgesOutOf(m); if (verbose) G.v().out.println(" |- "+m.toString()+" calls"); while (itt.hasNext()) { Edge edge = (Edge)itt.next(); SootMethod mm = edge.tgt(); boolean keep = mm.isConcrete() && filter.want(mm); if (verbose) G.v().out.println(" | |- "+mm.toString()+ (keep?"":" (filtered out)")); if (keep) { if (this.nodes.add(mm)) newRemain.add(mm); s.put(m,mm); p.put(mm,m); } } nb++; } remain = newRemain; } G.v().out.println("[AM] number of methods to be analysed: "+nb); // MultiMap -> Map of List this.succ = new HashMap(); this.pred = new HashMap(); this.tails = new LinkedList(); this.heads = new LinkedList(); Iterator it = this.nodes.iterator(); while (it.hasNext()) { Object x = it.next(); Set ss = s.get(x); Set pp = p.get(x); this.succ.put(x, new LinkedList(ss)); this.pred.put(x, new LinkedList(pp)); if (ss.isEmpty()) this.tails.add(x); if (pp.isEmpty()) this.heads.add(x); } this.size = this.nodes.size(); } /** You get a List of SootMethod. */ public List getHeads() { return heads; } /** You get a List of SootMethod. */ public List getTails() { return tails; } /** You get an Iterator on SootMethod. */ public Iterator iterator() { return nodes.iterator(); } public int size() { return size; } /** You get a List of SootMethod. */ public List getSuccsOf(Object s) { return succ.get(s); } /** You get a List of SootMethod. */ public List getPredsOf(Object s) { return pred.get(s); } }