/* Soot - a J*va Optimization Framework * Copyright (C) 2005 Nomair A. Naeem * * 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. */ /* * Maintained by Nomair A. Naeem */ /* * Change log: * November 22nd 2005: Moved this class from structuredAnalysis * package to traversals package. Since this is a traversal not an analysis * * * November 23rd 2005. MASSIVE CHANGES * Created a Class LocalVariableCleaner which should * be run after running copy prop and moved some of the * functionality from this class to localVariableCleaner */ /* * TODO: November 23rd, 2005. What if removeStmt removes a copyStmt and that was the only * stmt in the stmtSequenceBlock. Shouldnt that block be removed?? */ package soot.dava.toolkits.base.AST.traversals; import soot.*; import java.util.*; import soot.jimple.*; import soot.dava.internal.AST.*; import soot.dava.internal.asg.*; import soot.dava.toolkits.base.AST.analysis.*; import soot.dava.toolkits.base.AST.structuredAnalysis.*; /* * TODO: shouldnt this be a transformation and hence under the transformation package??? This analysis uses the results from 1 ReachingCopies 2 uD and dU chains to eliminate extra copies ALGORITHM: When you encounter a copy stmt (a=b) find all uses of local a (using dU chain) if For ALL uses the ReachingCopies set contains copy stmt (a=b) Remove Copy Stmt Replace use of a with use of b Note: copy stmts can be encountered in: a, ASTStatementSequenceNode b, for loop init -------> dont want to remove this c, for loop update ---------> dont want to remove this */ public class CopyPropagation extends DepthFirstAdapter { public static boolean DEBUG = false; ASTNode AST; ASTUsesAndDefs useDefs; ReachingCopies reachingCopies; ASTParentNodeFinder parentOf; boolean someCopyStmtModified; //need to keep track of whenever we modify the AST //this flag is set to true whenever a stmt is removed or a local substituted for another boolean ASTMODIFIED; public CopyPropagation(ASTNode AST) { super(); someCopyStmtModified = false; this.AST = AST; ASTMODIFIED = false; setup(); } public CopyPropagation(boolean verbose, ASTNode AST) { super(verbose); someCopyStmtModified = false; this.AST = AST; ASTMODIFIED = false; setup(); } private void setup() { //create the uD and dU chains if (DEBUG) System.out.println("computing usesAnd Defs"); useDefs = new ASTUsesAndDefs(AST); AST.apply(useDefs); if (DEBUG) System.out.println("computing usesAnd Defs....done"); //apply the reaching copies Structural flow Analysis reachingCopies = new ReachingCopies(AST); parentOf = new ASTParentNodeFinder(); AST.apply(parentOf); } /* * If any copy stmt was removed or any substitution made * we might be able to get better results by redoing the analysis */ public void outASTMethodNode(ASTMethodNode node) { if (ASTMODIFIED) { //need to rerun copy prop //before running a structured flow analysis have to do this one AST.apply(ClosestAbruptTargetFinder.v()); //System.out.println("\n\n\nCOPY PROP\n\n\n\n"); CopyPropagation prop1 = new CopyPropagation(AST); AST.apply(prop1); } } public void inASTStatementSequenceNode(ASTStatementSequenceNode node) { List<Object> statements = node.getStatements(); Iterator<Object> it = statements.iterator(); while (it.hasNext()) { AugmentedStmt as = (AugmentedStmt) it.next(); Stmt s = as.get_Stmt(); if (isCopyStmt(s)) { handleCopyStmt((DefinitionStmt) s); } } } /* * Method returns true if s is a copy stmt i.e. a = b where a and b are both locals */ public boolean isCopyStmt(Stmt s) { if (!(s instanceof DefinitionStmt)) { //only definition stmts can be copy stmts return false; } // x = expr; //check if expr is a local in which case this is a copy Value leftOp = ((DefinitionStmt) s).getLeftOp(); Value rightOp = ((DefinitionStmt) s).getRightOp(); if (leftOp instanceof Local && rightOp instanceof Local) { //this is a copy statement return true; } return false; } /* * Given a copy stmt (a=b) find all uses of local a (using dU chain) * if For ALL uses the ReachingCopies set contains copy stmt (a=b) * Remove Copy Stmt * Replace use of a with use of b */ public void handleCopyStmt(DefinitionStmt copyStmt) { //System.out.println("COPY STMT FOUND-----------------------------------"+copyStmt); //get defined local...safe to cast since this is copyStmt Local definedLocal = (Local) copyStmt.getLeftOp(); //get all uses of this local from the dU chain Object temp = useDefs.getDUChain(copyStmt); ArrayList uses = new ArrayList(); if (temp != null) { uses = (ArrayList) temp; } //the uses list contains all stmts / nodes which use the definedLocal //check if uses is non-empty if (uses.size() != 0) { if (DEBUG) { System.out.println(">>>>The defined local:" + definedLocal + " is used in the following"); System.out.println("\n numof uses:" + uses.size() + uses + ">>>>>>>>>>>>>>>\n\n"); } //continuing with copy propagation algorithm //create localPair for copy stmt in question...same to cast as its a copyStmt Local leftLocal = (Local) copyStmt.getLeftOp(); Local rightLocal = (Local) copyStmt.getRightOp(); ReachingCopies.LocalPair localPair = reachingCopies.new LocalPair(leftLocal, rightLocal); //check for all the non zero uses Iterator useIt = uses.iterator(); while (useIt.hasNext()) { //check that the reaching copies of each use has the copy stmt //a use is either a statement or a node(condition, synch, switch , for etc) Object tempUse = useIt.next(); DavaFlowSet reaching = reachingCopies.getReachingCopies(tempUse); if (!reaching.contains(localPair)) { //this copy stmt does not reach this use //no copy elimination can be done return; } } //if we get here that means that the copy stmt reached each use //replace each use of a with b useIt = uses.iterator(); while (useIt.hasNext()) { Object tempUse = useIt.next(); if (DEBUG) { System.out.println("copy stmt reached this use" + tempUse); } replace(leftLocal, rightLocal, tempUse); } //remove copy stmt a=b removeStmt(copyStmt); if (someCopyStmtModified) { //get all the analyses re-set setup(); someCopyStmtModified = false; } } else { //the copy stmt is usesless since the definedLocal is not being used anywhere after definition //System.out.println("The defined local:"+definedLocal+" is not used anywhere"); removeStmt(copyStmt); } } public void removeStmt(Stmt stmt) { Object tempParent = parentOf.getParentOf(stmt); if (tempParent == null) { //System.out.println("NO PARENT FOUND CANT DO ANYTHING"); return; } //parents are always ASTNodes, hence safe to cast ASTNode parent = (ASTNode) tempParent; //REMOVING STMT if (!(parent instanceof ASTStatementSequenceNode)) { //parent of a statement should always be a ASTStatementSequenceNode throw new RuntimeException( "Found a stmt whose parent is not an ASTStatementSequenceNode"); } ASTStatementSequenceNode parentNode = (ASTStatementSequenceNode) parent; ArrayList<Object> newSequence = new ArrayList<Object>(); Iterator<Object> it = parentNode.getStatements().iterator(); while (it.hasNext()) { AugmentedStmt as = (AugmentedStmt) it.next(); Stmt s = as.get_Stmt(); if (s.toString().compareTo(stmt.toString()) != 0) { //this is not the stmt to be removed newSequence.add(as); } } //System.out.println("STMT REMOVED---------------->"+stmt); parentNode.setStatements(newSequence); ASTMODIFIED = true; return; } /* * Method goes depth first into the condition tree and finds any use of local "from" * If it finds the use it replaces it with the use of local "to" */ public void modifyUses(Local from, Local to, ASTCondition cond) { if (cond instanceof ASTAggregatedCondition) { //ArrayList useList = new ArrayList(); modifyUses(from, to, ((ASTAggregatedCondition) cond).getLeftOp()); modifyUses(from, to, ((ASTAggregatedCondition) cond).getRightOp()); } else if (cond instanceof ASTUnaryCondition) { //get uses from unary condition Value val = ((ASTUnaryCondition) cond).getValue(); if (val instanceof Local) { Local local = (Local) val; if (local.getName().compareTo(from.getName()) == 0) { //replace the name with the one in "to" ((ASTUnaryCondition) cond).setValue(to); ASTMODIFIED = true; } } else { Iterator it = val.getUseBoxes().iterator(); while (it.hasNext()) { ValueBox valBox = (ValueBox) it.next(); Value tempVal = valBox.getValue(); if (tempVal instanceof Local) { Local local = (Local) tempVal; if (local.getName().compareTo(from.getName()) == 0) { //replace the name with the one in "to" valBox.setValue(to); ASTMODIFIED = true; } } } } }//end unary condition else if (cond instanceof ASTBinaryCondition) { //get uses from binaryCondition Value val = ((ASTBinaryCondition) cond).getConditionExpr(); Iterator it = val.getUseBoxes().iterator(); while (it.hasNext()) { ValueBox valBox = (ValueBox) it.next(); Value tempVal = valBox.getValue(); if (tempVal instanceof Local) { Local local = (Local) tempVal; if (local.getName().compareTo(from.getName()) == 0) { //replace the name with the one in "to" valBox.setValue(to); ASTMODIFIED = true; } } } } else { throw new RuntimeException( "Method getUseList in CopyPropagation encountered unknown condition type"); } } public void modifyUseBoxes(Local from, Local to, List useBoxes){ Iterator it = useBoxes.iterator(); while (it.hasNext()) { ValueBox valBox = (ValueBox) it.next(); Value tempVal = valBox.getValue(); if (tempVal instanceof Local) { Local local = (Local) tempVal; if (local.getName().compareTo(from.getName()) == 0) { //replace the name with the one in "to" valBox.setValue(to); ASTMODIFIED = true; } } } } /* * Invoked by handleCopyStmt to replace the use of local <from> * to the use of local <to> in <use> * * Notice <use> can be a stmt or an ASTNode */ public void replace(Local from, Local to, Object use) { if (use instanceof Stmt) { Stmt s = (Stmt) use; if (isCopyStmt(s)) { someCopyStmtModified = true; } List useBoxes = s.getUseBoxes(); if(DEBUG) System.out.println("Printing uses for stmt"+useBoxes); //TODO modifyUseBoxes(from,to,useBoxes); } else if (use instanceof ASTNode) { if (use instanceof ASTSwitchNode) { ASTSwitchNode temp = (ASTSwitchNode) use; Value val = temp.get_Key(); if (val instanceof Local) { if (((Local) val).getName().compareTo(from.getName()) == 0) { //replace the name with the one in "to" ASTMODIFIED = true; temp.set_Key(to); } } else { List useBoxes = val.getUseBoxes(); //TODO modifyUseBoxes(from,to,useBoxes); } } else if (use instanceof ASTSynchronizedBlockNode) { ASTSynchronizedBlockNode temp = (ASTSynchronizedBlockNode) use; Local local = temp.getLocal(); if (local.getName().compareTo(from.getName()) == 0) { //replace the name with the one in "to" temp.setLocal(to); ASTMODIFIED = true; } } else if (use instanceof ASTIfNode) { if (DEBUG) System.out.println("Use is an instanceof if node"); ASTIfNode temp = (ASTIfNode) use; ASTCondition cond = temp.get_Condition(); modifyUses(from, to, cond); } else if (use instanceof ASTIfElseNode) { ASTIfElseNode temp = (ASTIfElseNode) use; ASTCondition cond = temp.get_Condition(); modifyUses(from, to, cond); } else if (use instanceof ASTWhileNode) { ASTWhileNode temp = (ASTWhileNode) use; ASTCondition cond = temp.get_Condition(); modifyUses(from, to, cond); } else if (use instanceof ASTDoWhileNode) { ASTDoWhileNode temp = (ASTDoWhileNode) use; ASTCondition cond = temp.get_Condition(); modifyUses(from, to, cond); } else if (use instanceof ASTForLoopNode) { ASTForLoopNode temp = (ASTForLoopNode) use; //init List<Object> init = temp.getInit(); Iterator<Object> it = init.iterator(); while (it.hasNext()) { AugmentedStmt as = (AugmentedStmt) it.next(); Stmt s = as.get_Stmt(); replace(from, to, s); } //update List<Object> update = temp.getUpdate(); it = update.iterator(); while (it.hasNext()) { AugmentedStmt as = (AugmentedStmt) it.next(); Stmt s = as.get_Stmt(); replace(from, to, s); } //condition ASTCondition cond = temp.get_Condition(); modifyUses(from, to, cond); } else throw new RuntimeException( "Encountered an unknown ASTNode in copyPropagation method replace"); } else throw new RuntimeException( "Encountered an unknown use in copyPropagation method replace"); } }