/* Soot - a J*va Optimization Framework * Copyright (C) 2006 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. */ package soot.dava.toolkits.base.AST.transformations; import java.util.Iterator; import java.util.List; import java.util.Map; import soot.BooleanType; import soot.Value; import soot.dava.internal.AST.ASTCondition; import soot.dava.internal.AST.ASTControlFlowNode; import soot.dava.internal.AST.ASTDoWhileNode; import soot.dava.internal.AST.ASTForLoopNode; import soot.dava.internal.AST.ASTIfElseNode; import soot.dava.internal.AST.ASTIfNode; import soot.dava.internal.AST.ASTLabeledBlockNode; import soot.dava.internal.AST.ASTLabeledNode; import soot.dava.internal.AST.ASTMethodNode; import soot.dava.internal.AST.ASTNode; import soot.dava.internal.AST.ASTStatementSequenceNode; import soot.dava.internal.AST.ASTSwitchNode; import soot.dava.internal.AST.ASTTryNode; import soot.dava.internal.AST.ASTUnaryCondition; import soot.dava.internal.AST.ASTWhileNode; import soot.dava.internal.javaRep.DIntConstant; import soot.dava.internal.javaRep.DNotExpr; import soot.dava.toolkits.base.AST.analysis.DepthFirstAdapter; import soot.dava.toolkits.base.AST.traversals.ASTParentNodeFinder; /* * if (true) ---> remove conditional copy ifbody to parent * * if(false) eliminate in all entirety * * if(true) * bla1 * else * bla2 remove conditional copy bla1 to parent * * if(false) * bla1 * else * bla2 remoce conditional copy bla2 to parent * * * while(false) eliminate in entirety... notice this is not an Uncondition loop but a ASTWhileNode * * do{ .... } while(false) eliminate loop copy body to parent * * for(int i =0;false;i++) remove for . copy init stmts to parent */ public class EliminateConditions extends DepthFirstAdapter { public static boolean DEBUG=false; public boolean modified=false; ASTParentNodeFinder finder; ASTMethodNode AST; List<Object> bodyContainingNode=null; public EliminateConditions(ASTMethodNode AST) { super(); finder = new ASTParentNodeFinder(); this.AST=AST; } public EliminateConditions(boolean verbose,ASTMethodNode AST) { super(verbose); finder = new ASTParentNodeFinder(); this.AST=AST; } public void normalRetrieving(ASTNode node){ modified=false; if(node instanceof ASTSwitchNode){ do{ modified=false; dealWithSwitchNode((ASTSwitchNode)node); }while(modified); return; } //from the Node get the subBodes Iterator<Object> sbit = node.get_SubBodies().iterator(); while (sbit.hasNext()) { List subBody = (List)sbit.next(); Iterator it = subBody.iterator(); ASTNode temp=null; Boolean returned=null; while (it.hasNext()){ temp = (ASTNode) it.next(); //only check condition if this is a control flow node if(temp instanceof ASTControlFlowNode){ bodyContainingNode=null; returned = eliminate(temp); if(returned!=null && canChange(returned,temp)){ break; } else{ if(DEBUG) System.out.println("returned is null"+temp.getClass()); bodyContainingNode=null; } } temp.apply(this); }//end while going through nodes in subBody boolean changed = change(returned,temp); if(changed) modified=true; }//end of going over subBodies if(modified){ //repeat the whole thing normalRetrieving(node); } } public Boolean eliminate(ASTNode node){ ASTCondition cond=null; if(node instanceof ASTControlFlowNode) cond = ((ASTControlFlowNode)node).get_Condition(); else return null; if( cond == null || !(cond instanceof ASTUnaryCondition)) return null; ASTUnaryCondition unary = (ASTUnaryCondition)cond; Value unaryValue = unary.getValue(); boolean notted=false; if(unaryValue instanceof DNotExpr){ notted=true; unaryValue= ((DNotExpr)unaryValue).getOp(); } Boolean isBoolean = isBooleanConstant(unaryValue); if(isBoolean == null){ //not a constant return null; } boolean trueOrFalse = isBoolean.booleanValue(); if(notted){ //since it is notted we reverse the booleans trueOrFalse= !trueOrFalse; } AST.apply(finder); Object temp = finder.getParentOf(node); if(temp == null) return null; ASTNode parent = (ASTNode)temp; List<Object> subBodies = parent.get_SubBodies(); Iterator<Object> it = subBodies.iterator(); int index=-1; while(it.hasNext()){ bodyContainingNode = (List<Object>)it.next(); index = bodyContainingNode.indexOf(node); if(index<0){ bodyContainingNode=null; } else{ //bound the body containing Node return new Boolean(trueOrFalse); } } return null; } /* * Method returns null if the Value is not a constant or not a boolean constant * return true if the constant is true * return false if the constant is false */ public Boolean isBooleanConstant(Value internal){ if(! (internal instanceof DIntConstant)) return null; if(DEBUG) System.out.println("Found Constant"); DIntConstant intConst = (DIntConstant)internal; if(! (intConst.type instanceof BooleanType) ) return null; //either true or false if(DEBUG) System.out.println("Found Boolean Constant"); if(intConst.value == 1){ return new Boolean(true); } else if(intConst.value == 0){ return new Boolean(false); } else throw new RuntimeException("BooleanType found with value different than 0 or 1"); } public Boolean eliminateForTry(ASTNode node){ ASTCondition cond=null; if(node instanceof ASTControlFlowNode) cond = ((ASTControlFlowNode)node).get_Condition(); else return null; if( cond == null || !(cond instanceof ASTUnaryCondition)) return null; ASTUnaryCondition unary = (ASTUnaryCondition)cond; Value unaryValue = unary.getValue(); boolean notted=false; if(unaryValue instanceof DNotExpr){ notted=true; unaryValue= ((DNotExpr)unaryValue).getOp(); } Boolean isBoolean = isBooleanConstant(unaryValue); if(isBoolean == null){ //not a constant return null; } boolean trueOrFalse = isBoolean.booleanValue(); if(notted){ //since it is notted we reverse the booleans trueOrFalse= !trueOrFalse; } AST.apply(finder); Object temp = finder.getParentOf(node); if(temp == null) return null; if(!(temp instanceof ASTTryNode )) throw new RuntimeException("eliminateTry called when parent was not a try node"); ASTTryNode parent = (ASTTryNode)temp; List<Object> tryBody = parent.get_TryBody(); int index = tryBody.indexOf(node); if(index>=0){ //bound the body containing Node bodyContainingNode=tryBody; return new Boolean(trueOrFalse); } List<Object> catchList = parent.get_CatchList(); Iterator<Object> it = catchList.iterator(); while (it.hasNext()) { ASTTryNode.container catchBody = (ASTTryNode.container)it.next(); List<Object> body = (List<Object>)catchBody.o; index = body.indexOf(node); if(index>=0){ //bound the body containing Node bodyContainingNode=body; return new Boolean(trueOrFalse); } } return null; } public void caseASTTryNode(ASTTryNode node){ modified=false; inASTTryNode(node); //get try body iterator Iterator<Object> it = node.get_TryBody().iterator(); Boolean returned=null; ASTNode temp=null; while (it.hasNext()){ temp = (ASTNode) it.next(); //only check condition if this is a control flow node if(temp instanceof ASTControlFlowNode){ bodyContainingNode=null; returned = eliminateForTry(temp); if(returned!=null && canChange(returned,temp)) break; else bodyContainingNode=null; } temp.apply(this); }//end while boolean changed = change(returned, temp); if(changed) modified=true; //get catch list and apply on the following // a, type of exception caught ......... NO NEED // b, local of exception ............... NO NEED // c, catchBody List<Object> catchList = node.get_CatchList(); Iterator itBody=null; it = catchList.iterator(); while (it.hasNext()) { ASTTryNode.container catchBody = (ASTTryNode.container)it.next(); List body = (List)catchBody.o; itBody = body.iterator(); returned=null; temp=null; //go over the ASTNodes and apply while (itBody.hasNext()){ temp = (ASTNode) itBody.next(); //System.out.println("Next node is "+temp); //only check condition if this is a control flow node if(temp instanceof ASTControlFlowNode){ bodyContainingNode=null; returned = eliminateForTry(temp); if(returned!=null && canChange(returned,temp)) break; else bodyContainingNode=null; } temp.apply(this); } changed = change(returned, temp); if(changed) modified=true; } outASTTryNode(node); if(modified){ //repeat the whole thing caseASTTryNode(node); } } public boolean canChange(Boolean returned, ASTNode temp){ return true; } public boolean change(Boolean returned, ASTNode temp){ if(bodyContainingNode!=null && returned!=null && temp!=null){ int index = bodyContainingNode.indexOf(temp); if(DEBUG) System.out.println("in change"); if(temp instanceof ASTIfNode ){ bodyContainingNode.remove(temp); if (returned.booleanValue()){ //if statement and value was true put the body of if into the code //if its a labeled stmt we need a labeled block instead //notice that its okkay to put a labeled block since other transformations might remove it String label = ((ASTLabeledNode)temp).get_Label().toString(); if(label != null){ ASTLabeledBlockNode labeledNode = new ASTLabeledBlockNode( ((ASTLabeledNode)temp).get_Label(), (List<Object>)temp.get_SubBodies().get(0) ); bodyContainingNode.add(index,labeledNode); } else{ bodyContainingNode.addAll(index,(List)temp.get_SubBodies().get(0)); } } if(DEBUG) System.out.println("Removed if"+temp); return true; } else if(temp instanceof ASTIfElseNode){ bodyContainingNode.remove(temp); if(returned.booleanValue()){ //true so the if branch's body has to be added //if its a labeled stmt we need a labeled block instead //notice that its okkay to put a labeled block since other transformations might remove it String label = ((ASTLabeledNode)temp).get_Label().toString(); if(label != null){ ASTLabeledBlockNode labeledNode = new ASTLabeledBlockNode( ((ASTLabeledNode)temp).get_Label(), (List<Object>)temp.get_SubBodies().get(0) ); bodyContainingNode.add(index,labeledNode); } else{ bodyContainingNode.addAll(index,(List)temp.get_SubBodies().get(0)); } } else{ //if its a labeled stmt we need a labeled block instead //notice that its okkay to put a labeled block since other transformations might remove it String label = ((ASTLabeledNode)temp).get_Label().toString(); if(label != null){ ASTLabeledBlockNode labeledNode = new ASTLabeledBlockNode( ((ASTLabeledNode)temp).get_Label(), (List<Object>)temp.get_SubBodies().get(1) ); bodyContainingNode.add(index,labeledNode); } else{ bodyContainingNode.addAll(index,(List)temp.get_SubBodies().get(1)); } } return true; } else if(temp instanceof ASTWhileNode && returned.booleanValue()==false){ //notice we only remove if ASTWhileNode has false condition bodyContainingNode.remove(temp); return true; } else if(temp instanceof ASTDoWhileNode && returned.booleanValue()==false){ //System.out.println("in try dowhile false"); //remove the loop copy the body out since it gets executed once bodyContainingNode.remove(temp); bodyContainingNode.addAll(index,(List)temp.get_SubBodies().get(0)); return true; } else if(temp instanceof ASTForLoopNode && returned.booleanValue()==false){ bodyContainingNode.remove(temp); ASTStatementSequenceNode newNode = new ASTStatementSequenceNode(((ASTForLoopNode)temp).getInit()); bodyContainingNode.add(index,newNode); return true; } } return false; } public void dealWithSwitchNode(ASTSwitchNode node){ List<Object> indexList = node.getIndexList(); Map<Object, List<Object>> index2BodyList = node.getIndex2BodyList(); Iterator<Object> it = indexList.iterator(); while (it.hasNext()) { // going through all the cases of the switch statement Object currentIndex = it.next(); List body = index2BodyList.get( currentIndex); if (body != null){ // this body is a list of ASTNodes Iterator itBody = body.iterator(); Boolean returned=null; ASTNode temp = null; while (itBody.hasNext()){ temp = (ASTNode) itBody.next(); if(temp instanceof ASTControlFlowNode){ bodyContainingNode=null; returned = eliminate(temp); if(returned!=null && canChange(returned,temp)) break; else bodyContainingNode=null; } temp.apply(this); } boolean changed=change(returned,temp); if(changed) modified=true; }//end while changed } } }