/* Soot - a J*va Optimization Framework * Copyright (C) 2004 Ondrej Lhotak * * 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. */ package soot.toolkits.scalar; import soot.options.*; import soot.toolkits.graph.*; import soot.*; import soot.util.*; import java.util.*; /** * Analysis that computes live locals, local defs, and local uses all at once. */ public class CombinedDUAnalysis extends BackwardFlowAnalysis implements CombinedAnalysis, LocalDefs, LocalUses, LiveLocals { // Implementations of our interfaces... private final Map<Cons, List> defsOfAt = new HashMap<Cons, List>(); public List<Unit> getDefsOfAt(Local l, Unit s) { Cons cons = new Cons(l, s); List<Unit> ret = defsOfAt.get(cons); if(ret == null) { defsOfAt.put(cons, ret = new ArrayList<Unit>()); } return ret; } private final Map<Unit, List> usesOf = new HashMap<Unit, List>(); public List getUsesOf(Unit u) { List ret = usesOf.get(u); if( ret == null ) { Local def = localDefed(u); if( def == null ) { usesOf.put(u, ret = Collections.EMPTY_LIST); } else { usesOf.put(u, ret = new ArrayList()); for( Iterator vbIt = ((FlowSet)getFlowAfter(u)).iterator(); vbIt.hasNext(); ) { final ValueBox vb = (ValueBox) vbIt.next(); if( vb.getValue() != def ) continue; ret.add(new UnitValueBoxPair(useBoxToUnit.get(vb), vb)); } } } return ret; } private final Map<Unit, List> liveLocalsBefore = new HashMap<Unit, List>(); public List getLiveLocalsBefore(Unit u) { List ret = liveLocalsBefore.get(u); if( ret == null ) { HashSet hs = new HashSet(); for( Iterator vbIt = ((FlowSet)getFlowBefore(u)).iterator(); vbIt.hasNext(); ) { final ValueBox vb = (ValueBox) vbIt.next(); hs.add(vb.getValue()); } liveLocalsBefore.put(u, ret = new ArrayList(hs)); } return ret; } private final Map<Unit, List> liveLocalsAfter = new HashMap<Unit, List>(); public List getLiveLocalsAfter(Unit u) { List ret = liveLocalsAfter.get(u); if( ret == null ) { HashSet hs = new HashSet(); for( Iterator vbIt = ((FlowSet)getFlowAfter(u)).iterator(); vbIt.hasNext(); ) { final ValueBox vb = (ValueBox) vbIt.next(); hs.add(vb.getValue()); } liveLocalsAfter.put(u, ret = new ArrayList(hs)); } return ret; } // The actual analysis is below. private final Map<ValueBox, Unit> useBoxToUnit = new HashMap<ValueBox, Unit>(); private final Map<Unit, Value> unitToLocalDefed = new HashMap<Unit, Value>(); private Local localDefed(Unit u) { return (Local) unitToLocalDefed.get(u); } private final Map<Unit, ArraySparseSet> unitToLocalUseBoxes = new HashMap<Unit, ArraySparseSet>(); private final MultiMap localToUseBoxes = new HashMultiMap(); public static CombinedAnalysis v(final UnitGraph graph) { if(true) { return new CombinedDUAnalysis(graph); } return new CombinedAnalysis() { CombinedDUAnalysis combined = new CombinedDUAnalysis(graph); SimpleLocalDefs defs = new SimpleLocalDefs(graph); SimpleLocalUses uses = new SimpleLocalUses(graph, defs); SimpleLiveLocals live = new SimpleLiveLocals(graph); public List<Unit> getDefsOfAt(Local l, Unit s) { HashSet<Unit> hs1 = new HashSet<Unit>(combined.getDefsOfAt(l, s)); HashSet<Unit> hs2 = new HashSet<Unit>(defs.getDefsOfAt(l, s)); if( !hs1.equals(hs2) ) throw new RuntimeException( "Defs of "+l+" in "+s+"\ncombined: "+hs1+"\nsimple: "+hs2); return combined.getDefsOfAt(l, s); } public List getUsesOf(Unit u) { HashSet hs1 = new HashSet(combined.getUsesOf(u)); HashSet hs2 = new HashSet(uses.getUsesOf(u)); if( !hs1.equals(hs2) ) throw new RuntimeException( "Uses of "+u+"\ncombined: "+hs1+"\nsimple: "+hs2); return combined.getUsesOf(u); } public List getLiveLocalsBefore(Unit u) { HashSet hs1 = new HashSet(combined.getLiveLocalsBefore(u)); HashSet hs2 = new HashSet(live.getLiveLocalsBefore(u)); if( !hs1.equals(hs2) ) throw new RuntimeException( "llb of "+u+"\ncombined: "+hs1+"\nsimple: "+hs2); return combined.getLiveLocalsBefore(u); } public List getLiveLocalsAfter(Unit u) { HashSet hs1 = new HashSet(combined.getLiveLocalsAfter(u)); HashSet hs2 = new HashSet(live.getLiveLocalsAfter(u)); if( !hs1.equals(hs2) ) throw new RuntimeException( "lla of "+u+"\ncombined: "+hs1+"\nsimple: "+hs2); return combined.getLiveLocalsAfter(u); } } ; } private CombinedDUAnalysis(UnitGraph graph) { super(graph); if(Options.v().verbose()) G.v().out.println("[" + graph.getBody().getMethod().getName() + "] Constructing CombinedDUAnalysis..."); for( Iterator uIt = graph.iterator(); uIt.hasNext(); ) { final Unit u = (Unit) uIt.next(); List<Value> defs = localsInBoxes(u.getDefBoxes()); if( defs.size() == 1 ) unitToLocalDefed.put(u, defs.get(0)); else if(defs.size() != 0) throw new RuntimeException("Locals defed in "+u+": "+defs.size()); ArraySparseSet localUseBoxes = new ArraySparseSet(); for( Iterator vbIt = u.getUseBoxes().iterator(); vbIt.hasNext(); ) { final ValueBox vb = (ValueBox) vbIt.next(); Value v = vb.getValue(); if(!(v instanceof Local)) continue; localUseBoxes.add(vb); if( useBoxToUnit.containsKey(vb) ) throw new RuntimeException("Aliased ValueBox "+vb+" in Unit "+u); useBoxToUnit.put(vb, u); localToUseBoxes.put(v, vb); } unitToLocalUseBoxes.put(u, localUseBoxes); } doAnalysis(); for( Iterator defUnitIt = graph.iterator(); defUnitIt.hasNext(); ) { final Unit defUnit = (Unit) defUnitIt.next(); /* getLiveLocalsAfter(defUnit); getLiveLocalsBefore(defUnit); getUsesOf(defUnit); */ Local localDefed = localDefed(defUnit); if( localDefed == null ) continue; for( Iterator vbIt = ((FlowSet)getFlowAfter(defUnit)).iterator(); vbIt.hasNext(); ) { final ValueBox vb = (ValueBox) vbIt.next(); if( vb.getValue() != localDefed ) continue; Unit useUnit = useBoxToUnit.get(vb); getDefsOfAt(localDefed, useUnit).add(defUnit); } } if(Options.v().verbose()) G.v().out.println("[" + graph.getBody().getMethod().getName() + "] Finished CombinedDUAnalysis..."); } private List<Value> localsInBoxes(List/*ValueBox*/ boxes) { List<Value> ret = new ArrayList<Value>(); for( Iterator vbIt = boxes.iterator(); vbIt.hasNext(); ) { final ValueBox vb = (ValueBox) vbIt.next(); Value v = vb.getValue(); if( !(v instanceof Local) ) continue; ret.add(v); } return ret; } // STEP 1: What are we computing? // SETS OF USE BOXES CONTAINING LOCALS => Use HashSet. // // STEP 2: Precisely define what we are computing. // A use box B is live at program point P if there exists a path from P to the // unit using B on which the local in B is not defined. // // STEP 3: Decide whether it is a backwards or forwards analysis. // BACKWARDS // // STEP 4: Is the merge operator union or intersection? // UNION protected void merge(Object inoutO, Object inO) { FlowSet inout = (FlowSet) inoutO; FlowSet in = (FlowSet) inO; inout.union(in); } protected void merge(Object in1O, Object in2O, Object outO) { FlowSet in1 = (FlowSet) in1O; FlowSet in2 = (FlowSet) in2O; FlowSet out = (FlowSet) outO; in1.union(in2, out); } // STEP 5: Define flow equations. // in(s) = ( out(s) minus boxes(def(s)) ) union useboxes(s) protected void flowThrough(Object outValue, Object unit, Object inValue) { Unit u = (Unit) unit; FlowSet in = (FlowSet) inValue; FlowSet out = (FlowSet) outValue; Local def = localDefed(u); out.copy(in); if(def != null) { Collection boxesDefed = localToUseBoxes.get(def); for( Iterator vbIt = in.toList().iterator(); vbIt.hasNext(); ) { final ValueBox vb = (ValueBox) vbIt.next(); if(boxesDefed.contains(vb)) in.remove(vb); } } in.union(unitToLocalUseBoxes.get(u)); } // STEP 6: Determine value for start/end node, and // initial approximation. // // end node: empty set // initial approximation: empty set protected Object entryInitialFlow() { return new ArraySparseSet(); } protected Object newInitialFlow() { return new ArraySparseSet(); } protected void copy(Object source, Object dest) { FlowSet sourceSet = (FlowSet) source; FlowSet destSet = (FlowSet) dest; sourceSet.copy(destSet); } }