/* Soot - a J*va Optimization Framework * Copyright (C) 2000 Feng Qian * * 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. */ /* * Modified by the Sable Research Group and others 1997-1999. * See the 'credits' file distributed with Soot for the complete list of * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot) */ package soot.jimple.toolkits.annotation.arraycheck; import soot.options.*; import soot.*; import soot.jimple.*; import soot.jimple.internal.*; import soot.util.*; import soot.toolkits.graph.*; import soot.toolkits.scalar.*; import java.util.*; class ArrayIndexLivenessAnalysis extends BackwardFlowAnalysis { HashSet<Local> fullSet = new HashSet<Local>(); ExceptionalUnitGraph eug; /* for each unit, kill set has variables to be killed. * gen set was considered with conditionOfGenSet, * for example, gen set of unit s are valid only when the condition object. * was in the living input set. */ HashMap<Stmt, HashSet<Object>> genOfUnit; HashMap<Stmt, HashSet<Value>> absGenOfUnit; HashMap<Stmt, HashSet<Value>> killOfUnit; HashMap<Stmt, HashSet<Value>> conditionOfGen; // s --> a kill all a[?]. HashMap<DefinitionStmt, Value> killArrayRelated; // s --> true HashMap<DefinitionStmt, Boolean> killAllArrayRef; IntContainer zero = new IntContainer(0); private final boolean fieldin; HashMap<Object, HashSet<Value>> localToFieldRef, fieldToFieldRef; HashSet<Value> allFieldRefs; private final boolean arrayin; HashMap localToArrayRef; HashSet allArrayRefs; private final boolean csin; HashMap<Value, HashSet<Value>> localToExpr; private final boolean rectarray; HashSet<Local> multiarraylocals; public ArrayIndexLivenessAnalysis(DirectedGraph dg, boolean takeFieldRef, boolean takeArrayRef, boolean takeCSE, boolean takeRectArray) { super(dg); fieldin = takeFieldRef; arrayin = takeArrayRef; csin = takeCSE; rectarray = takeRectArray; if (Options.v().debug()) G.v().out.println("Enter ArrayIndexLivenessAnalysis"); eug = (ExceptionalUnitGraph)dg; retrieveAllArrayLocals(eug.getBody(), fullSet); /* compute gen set, kill set, and condition set */ genOfUnit = new HashMap<Stmt, HashSet<Object>>(eug.size()*2+1); absGenOfUnit = new HashMap<Stmt, HashSet<Value>>(eug.size()*2+1); killOfUnit = new HashMap<Stmt, HashSet<Value>>(eug.size()*2+1); conditionOfGen = new HashMap<Stmt, HashSet<Value>>(eug.size()*2+1); if (fieldin) { localToFieldRef = new HashMap<Object, HashSet<Value>>(); fieldToFieldRef = new HashMap<Object, HashSet<Value>>(); allFieldRefs = new HashSet<Value>(); } if (arrayin) { localToArrayRef = new HashMap(); allArrayRefs = new HashSet(); killArrayRelated = new HashMap<DefinitionStmt, Value>(); killAllArrayRef = new HashMap<DefinitionStmt, Boolean>(); if (rectarray) { multiarraylocals = new HashSet<Local>(); retrieveMultiArrayLocals(eug.getBody(), multiarraylocals); } } if (csin) { localToExpr = new HashMap<Value, HashSet<Value>>(); } getAllRelatedMaps(eug.getBody()); getGenAndKillSet(eug.getBody(), absGenOfUnit, genOfUnit, killOfUnit, conditionOfGen); doAnalysis(); if (Options.v().debug()) G.v().out.println("Leave ArrayIndexLivenessAnalysis"); } public HashMap<Object, HashSet<Value>> getLocalToFieldRef() { return localToFieldRef; } public HashMap<Object, HashSet<Value>> getFieldToFieldRef() { return fieldToFieldRef; } public HashSet<Value> getAllFieldRefs() { return this.allFieldRefs; } public HashMap getLocalToArrayRef() { return localToArrayRef; } public HashSet getAllArrayRefs() { return allArrayRefs; } public HashMap<Value, HashSet<Value>> getLocalToExpr() { return localToExpr; } public HashSet<Local> getMultiArrayLocals() { return multiarraylocals; } private void getAllRelatedMaps(Body body) { Iterator unitIt = body.getUnits().iterator(); while (unitIt.hasNext()) { Stmt stmt = (Stmt)unitIt.next(); if (csin) { if (stmt instanceof DefinitionStmt) { Value rhs = ((DefinitionStmt)stmt).getRightOp(); if (rhs instanceof BinopExpr) { Value op1 = ((BinopExpr)rhs).getOp1(); Value op2 = ((BinopExpr)rhs).getOp2(); if (rhs instanceof AddExpr) { // op1 + op2 --> a + b if ((op1 instanceof Local) && (op2 instanceof Local)) { HashSet<Value> refs = localToExpr.get(op1); if (refs == null) { refs = new HashSet<Value>(); localToExpr.put(op1, refs); } refs.add(rhs); refs = localToExpr.get(op2); if (refs == null) { refs = new HashSet<Value>(); localToExpr.put(op2, refs); } refs.add(rhs); } } // a * b, a * c, c * a else if (rhs instanceof MulExpr) { HashSet<Value> refs = localToExpr.get(op1); if (refs == null) { refs = new HashSet<Value>(); localToExpr.put(op1, refs); } refs.add(rhs); refs = localToExpr.get(op2); if (refs == null) { refs = new HashSet<Value>(); localToExpr.put(op2, refs); } refs.add(rhs); } else if (rhs instanceof SubExpr) { if (op2 instanceof Local) { HashSet<Value> refs = localToExpr.get(op2); if (refs == null) { refs = new HashSet<Value>(); localToExpr.put(op2, refs); } refs.add(rhs); if (op1 instanceof Local) { refs = localToExpr.get(op1); if (refs == null) { refs = new HashSet<Value>(); localToExpr.put(op1, refs); } refs.add(rhs); } } } } } } List vboxes = stmt.getUseAndDefBoxes(); Iterator vboxIt = vboxes.iterator(); while (vboxIt.hasNext()) { Value v = ((ValueBox)vboxIt.next()).getValue(); if (fieldin) { if (v instanceof InstanceFieldRef) { Value base = ((InstanceFieldRef)v).getBase(); SootField field = ((InstanceFieldRef)v).getField(); HashSet<Value> baseset = localToFieldRef.get(base); if (baseset == null) { baseset = new HashSet<Value>(); localToFieldRef.put(base, baseset); } baseset.add(v); HashSet<Value> fieldset = fieldToFieldRef.get(field); if (fieldset == null) { fieldset = new HashSet<Value>(); fieldToFieldRef.put(field, fieldset); } fieldset.add(v); } if (v instanceof FieldRef) allFieldRefs.add(v); } if (arrayin) { // a = ... --> kill all a[x] nodes. // a[i] = .. --> kill all array references. // m(a) --> kill all array references // i = ... --> kill all array reference with index as i /* if (v instanceof ArrayRef) { Value base = ((ArrayRef)v).getBase(); Value index = ((ArrayRef)v).getIndex(); HashSet refset = (HashSet)localToArrayRef.get(base); if (refset == null) { refset = new HashSet(); localToArrayRef.put(base, refset); } refset.add(v); if (index instanceof Local) { refset = (HashSet)localToArrayRef.get(index); if (refset == null) { refset = new HashSet(); localToArrayRef.put(index, refset); } refset.add(v); } allArrayRefs.add(v); } */ } } } } private void retrieveAllArrayLocals(Body body, Set<Local> container) { Chain locals = body.getLocals(); Iterator localIt = locals.iterator(); while (localIt.hasNext()) { Local local = (Local)localIt.next(); Type type = local.getType(); if (type instanceof IntType || type instanceof ArrayType) container.add(local); } } private void retrieveMultiArrayLocals(Body body, Set<Local> container) { Chain locals = body.getLocals(); Iterator localIt = locals.iterator(); while (localIt.hasNext()) { Local local = (Local)localIt.next(); Type type = local.getType(); if (type instanceof ArrayType) { if (((ArrayType)type).numDimensions > 1) this.multiarraylocals.add(local); } } } private void getGenAndKillSetForDefnStmt(DefinitionStmt asstmt, HashMap<Stmt, HashSet<Value>> absgen, HashSet<Object> genset, HashSet<Value> absgenset, HashSet<Value> killset, HashSet<Value> condset) { /* kill left hand side */ Value lhs = asstmt.getLeftOp(); Value rhs = asstmt.getRightOp(); boolean killarrayrelated = false; boolean killallarrayref = false; if (fieldin) { if (lhs instanceof Local) { HashSet related = localToFieldRef.get(lhs); if (related != null) killset.addAll(related); } else if (lhs instanceof StaticFieldRef) { killset.add(lhs); condset.add(lhs); } else if (lhs instanceof InstanceFieldRef) { SootField field = ((InstanceFieldRef)lhs).getField(); HashSet related = fieldToFieldRef.get(field); if (related != null) killset.addAll(related); condset.add(lhs); } if (asstmt.containsInvokeExpr()) { /* Value expr = asstmt.getInvokeExpr(); List parameters = ((InvokeExpr)expr).getArgs(); // add the method invocation boolean killall = false; if (expr instanceof InstanceInvokeExpr) killall = true; else { for (int i=0; i<parameters.size(); i++) { Value para = (Value)parameters.get(i); if (para.getType() instanceof RefType) { killall = true; break; } } } if (killall) { killset.addAll(allInstFieldRefs); } */ killset.addAll(allFieldRefs); } } if (arrayin) { // a = ... or i = ... if (lhs instanceof Local) { killarrayrelated = true; } else // a[i] = ... if (lhs instanceof ArrayRef) { killallarrayref = true; condset.add(lhs); } // invokeexpr kills all array references. if (asstmt.containsInvokeExpr()) { killallarrayref = true; } } if (csin) { HashSet exprs = localToExpr.get(lhs); if (exprs != null) killset.addAll(exprs); if (rhs instanceof BinopExpr) { Value op1 = ((BinopExpr)rhs).getOp1(); Value op2 = ((BinopExpr)rhs).getOp2(); if (rhs instanceof AddExpr) { if ((op1 instanceof Local) && (op2 instanceof Local)) genset.add(rhs); } else if (rhs instanceof MulExpr) { if ((op1 instanceof Local) || (op2 instanceof Local)) genset.add(rhs); } else if (rhs instanceof SubExpr) { if (op2 instanceof Local) genset.add(rhs); } } } if ((lhs instanceof Local)&&(fullSet.contains(lhs))) { killset.add(lhs); /* speculatively add lhs as live condition. */ condset.add(lhs); } else if (lhs instanceof ArrayRef) { /* a[i] generate a and i. */ Value base = ((ArrayRef)lhs).getBase(); Value index = ((ArrayRef)lhs).getIndex(); ArrayList genList = new ArrayList(); absgenset.add(base); if (index instanceof Local) { absgenset.add(index); } } if (rhs instanceof Local) { /* only lhs=rhs is valid. */ /* if (lhs instanceof Local && fullSet.contains(rhs)) genset.add(rhs); */ if (fullSet.contains(rhs)) genset.add(rhs); /* if (fieldin && (lhs instanceof FieldRef)) genset.add(rhs); */ } else if (rhs instanceof FieldRef) { if (fieldin) genset.add(rhs); } else if (rhs instanceof ArrayRef) { /* lhs=a[i]. */ Value base = ((ArrayRef)rhs).getBase(); Value index = ((ArrayRef)rhs).getIndex(); absgenset.add(base); if (index instanceof Local) { absgenset.add(index); } if (arrayin) { genset.add(rhs); if (rectarray) genset.add(Array2ndDimensionSymbol.v(base)); } } else if (rhs instanceof NewArrayExpr) { /* a = new A[i]; */ Value size = ((NewArrayExpr)rhs).getSize(); if (size instanceof Local) genset.add(size); } else if (rhs instanceof NewMultiArrayExpr) { /* a = new A[i][]...;*/ /* More precisely, we should track other dimensions. */ List sizes = ((NewMultiArrayExpr)rhs).getSizes(); Iterator sizeIt = sizes.iterator(); while (sizeIt.hasNext()) { Value size = (Value)sizeIt.next(); if (size instanceof Local) genset.add(size); } } else if (rhs instanceof LengthExpr) { /* lhs = lengthof rhs */ Value op = ((LengthExpr)rhs).getOp(); genset.add(op); } else if (rhs instanceof JAddExpr) { /* lhs = rhs+c, lhs=c+rhs */ Value op1 = ((JAddExpr)rhs).getOp1(); Value op2 = ((JAddExpr)rhs).getOp2(); if ((op1 instanceof IntConstant) && (op2 instanceof Local)) { genset.add(op2); } else if ((op2 instanceof IntConstant) && (op1 instanceof Local)) { genset.add(op1); } } else if (rhs instanceof JSubExpr) { Value op1 = ((JSubExpr)rhs).getOp1(); Value op2 = ((JSubExpr)rhs).getOp2(); if ((op1 instanceof Local) && (op2 instanceof IntConstant)) { genset.add(op1); } } if (arrayin) { if (killarrayrelated) killArrayRelated.put(asstmt, lhs); if (killallarrayref) killAllArrayRef.put(asstmt, new Boolean(true)); } } private void getGenAndKillSet(Body body, HashMap<Stmt, HashSet<Value>> absgen, HashMap<Stmt, HashSet<Object>> gen, HashMap<Stmt, HashSet<Value>> kill, HashMap<Stmt, HashSet<Value>> condition) { Iterator unitIt = body.getUnits().iterator(); while (unitIt.hasNext()) { Stmt stmt = (Stmt)unitIt.next(); HashSet<Object> genset = new HashSet<Object>(); HashSet<Value> absgenset = new HashSet<Value>(); HashSet<Value> killset = new HashSet<Value>(); HashSet<Value> condset = new HashSet<Value>(); if (stmt instanceof DefinitionStmt) { getGenAndKillSetForDefnStmt((DefinitionStmt)stmt, absgen, genset, absgenset, killset, condset); } else if (stmt instanceof IfStmt) { /* if one of condition is living, than other one is live. */ Value cmpcond = ((IfStmt)stmt).getCondition(); if (cmpcond instanceof ConditionExpr) { Value op1 = ((ConditionExpr)cmpcond).getOp1(); Value op2 = ((ConditionExpr)cmpcond).getOp2(); if (fullSet.contains(op1) && fullSet.contains(op2)) { condset.add(op1); condset.add(op2); genset.add(op1); genset.add(op2); } } } if (genset.size() != 0) gen.put(stmt, genset); if (absgenset.size() != 0) absgen.put(stmt, absgenset); if (killset.size() != 0) kill.put(stmt, killset); if (condset.size() != 0) condition.put(stmt, condset); } } /* It is unsafe for normal units. */ /* Since the initial value is safe, empty set. we do not need to do it again. */ protected Object newInitialFlow() { return new HashSet(); } /* It is safe for end units. */ protected Object entryInitialFlow() { return new HashSet(); } protected void flowThrough(Object inValue, Object unit, Object outValue) { HashSet inset = (HashSet)inValue; HashSet outset = (HashSet)outValue; Stmt stmt = (Stmt)unit; /* copy in set to out set. */ outset.clear(); outset.addAll(inset); HashSet genset = genOfUnit.get(unit); HashSet absgenset = absGenOfUnit.get(unit); HashSet killset = killOfUnit.get(unit); HashSet condset = conditionOfGen.get(unit); if (killset != null) outset.removeAll(killset); if (arrayin) { Boolean killall = killAllArrayRef.get(stmt); if ((killall != null) && killall.booleanValue()) { List keylist = new ArrayList(outset); Iterator keyIt = keylist.iterator(); while (keyIt.hasNext()) { Object key = keyIt.next(); if (key instanceof ArrayRef) outset.remove(key); } } else { Object local = killArrayRelated.get(stmt); if (local != null) { List keylist = new ArrayList(outset); Iterator keyIt = keylist.iterator(); while (keyIt.hasNext()) { Object key = keyIt.next(); if (key instanceof ArrayRef) { Value base = ((ArrayRef)key).getBase(); Value index = ((ArrayRef)key).getIndex(); if (base.equals(local) || index.equals(local)) outset.remove(key); } if (rectarray) { if (key instanceof Array2ndDimensionSymbol) { Object base = ((Array2ndDimensionSymbol)key).getVar(); if (base.equals(local)) outset.remove(key); } } } } } } if (genset != null) { if (condset == null || (condset.size()==0)) outset.addAll(genset); else { Iterator condIt = condset.iterator(); while (condIt.hasNext()) { if (inset.contains(condIt.next())) { outset.addAll(genset); break; } } } } if (absgenset != null) outset.addAll(absgenset); } protected void merge(Object in1, Object in2, Object out) { HashSet inset1 = (HashSet)in1; HashSet inset2 = (HashSet)in2; HashSet outset = (HashSet)out; HashSet src = inset1; if (outset == inset1) src = inset2; else if (outset == inset2) src = inset1; else { outset.clear(); outset.addAll(inset2); } outset.addAll(src); } protected void copy(Object source, Object dest) { if (source == dest) return; HashSet sourceSet = (HashSet)source; HashSet destSet = (HashSet)dest; destSet.clear(); destSet.addAll(sourceSet); } }