/* 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.
*/
package soot.dava.toolkits.base.AST.transformations;
import soot.*;
import java.util.*;
import soot.jimple.*;
import soot.dava.internal.SET.*;
import soot.dava.internal.AST.*;
import soot.dava.internal.asg.*;
import soot.dava.internal.javaRep.*;
import soot.dava.toolkits.base.AST.analysis.*;
/*
Nomair A. Naeem 18-FEB-2005
The class is responsible to do the following transformation on the AST
label_1:
while(cond){ label_1:
BodyA; while(cond){
label_2:{ BodyA;
if(cond1){ if(cond1 || ..... || !cond2){
break label_2; BodyB
} }
//same as above }//end of while
.
. remove label_1 if BodyA and BodyB
if(cond2){ dont have any reference to label_1 (highly likely)
continue label_1; ------> should be done as a separate analysis
}
}//end of label_2
BodyB
}//end while
This pattern is applicable to the four cycle nodes representing
while(true), while(cond) and dowhile(cond) for loops
TO MAKE CODE EFFECIENT BLOCK THE ANALYSIS TO GOING INTO STATEMENTS
this is done by overriding the caseASTStatementSequenceNode
*/
public class OrAggregatorFour extends DepthFirstAdapter{
public OrAggregatorFour(){
}
public OrAggregatorFour(boolean verbose){
super(verbose);
}
public void caseASTStatementSequenceNode(ASTStatementSequenceNode node){
}
public void outASTForLoopNode(ASTForLoopNode node){
String label = node.get_Label().toString();
if(label==null)
return;
List<Object> subBodies=node.get_SubBodies();
List<Object> newBody=matchPattern(label,subBodies);
if(newBody!=null){
node.replaceBody(newBody);
//System.out.println("OR AGGREGATOR FOUR");
G.v().ASTTransformations_modified = true;
}
/*
see if we can remove the label from this construct
*/
UselessLabelFinder.v().findAndKill(node);
}
public void outASTWhileNode(ASTWhileNode node){
String label = node.get_Label().toString();
if(label==null)
return;
List<Object> subBodies=node.get_SubBodies();
List<Object> newBody=matchPattern(label,subBodies);
if(newBody!=null){
node.replaceBody(newBody);
//System.out.println("OR AGGREGATOR FOUR");
G.v().ASTTransformations_modified = true;
}
/*
see if we can remove the label from this construct
*/
UselessLabelFinder.v().findAndKill(node);
}
public void outASTDoWhileNode(ASTDoWhileNode node){
String label = node.get_Label().toString();
if(label==null)
return;
List<Object> subBodies=node.get_SubBodies();
List<Object> newBody=matchPattern(label,subBodies);
if(newBody!=null){
node.replaceBody(newBody);
//System.out.println("OR AGGREGATOR FOUR");
G.v().ASTTransformations_modified = true;
}
/*
see if we can remove the label from this construct
*/
UselessLabelFinder.v().findAndKill(node);
}
public void outASTUnconditionalLoopNode(ASTUnconditionalLoopNode node){
String label = node.get_Label().toString();
if(label==null)
return;
List<Object> subBodies=node.get_SubBodies();
List<Object> newBody=matchPattern(label,subBodies);
if(newBody!=null){
node.replaceBody(newBody);
//System.out.println("OR AGGREGATOR FOUR");
G.v().ASTTransformations_modified = true;
}
/*
see if we can remove the label from this construct
*/
UselessLabelFinder.v().findAndKill(node);
}
public List<Object> matchPattern(String whileLabel,List<Object> subBodies){
//since the subBodies are coming from a cycle node we know
//there is only one subBody
if(subBodies.size()!=1){
//size should be one
return null;
}
List subBody = (List)subBodies.get(0);
Iterator it = subBody.iterator();
int nodeNumber=0;
while(it.hasNext()){//going through the ASTNodes
//look for a labeledBlock
ASTNode temp = (ASTNode)it.next();
if(temp instanceof ASTLabeledBlockNode){
//see if the inner pattern matches
ASTLabeledBlockNode labeledNode = (ASTLabeledBlockNode)temp;
String innerLabel=labeledNode.get_Label().toString();
if(innerLabel==null){//label better not be null
nodeNumber++;
continue;
}
//get labeledBlocksBodies
List<Object> labeledBlocksSubBodies = labeledNode.get_SubBodies();
if(labeledBlocksSubBodies.size()!=1){
//should always be one
nodeNumber++;
continue;
}
//get the subBody
List labeledBlocksSubBody = (List)labeledBlocksSubBodies.get(0);
boolean allIfs = checkAllAreIfsWithProperBreaks(labeledBlocksSubBody.iterator(),whileLabel,innerLabel);
if(!allIfs){
//pattern doesnt match
nodeNumber++;
continue;
}
//the pattern has been matched do the transformation
//nodeNumber is the location of the ASTLabeledBlockNode
List<Object> whileBody = createWhileBody(subBody,labeledBlocksSubBody,nodeNumber);
if(whileBody!=null){
return whileBody;
}
}//if its an ASTLabeledBlockNode
nodeNumber++;
}//end of going through ASTNodes
return null;
}
private List<Object> createWhileBody(List subBody,List labeledBlocksSubBody,int nodeNumber){
//create BodyA, Nodes from 0 to nodeNumber
List<Object> bodyA = new ArrayList<Object>();
//this is an iterator of ASTNodes
Iterator it = subBody.iterator();
//copy to bodyA all nodes until you get to nodeNumber
int index=0;
while(index!=nodeNumber ){
if(!it.hasNext()){
return null;
}
bodyA.add(it.next());
index++;
}
//create ASTIfNode
// Create a list of conditions to be Ored together
// remembering that the last ones condition is to be flipped
List<ASTCondition> conditions = getConditions(labeledBlocksSubBody.iterator());
//create an aggregated condition
Iterator<ASTCondition> condIt = conditions.iterator();
ASTCondition newCond=null;;
while(condIt.hasNext()){
ASTCondition next = condIt.next();
if(newCond==null)
newCond=next;
else
newCond=new ASTOrCondition(newCond,next);
}
//create BodyB
it.next();//this skips the LabeledBlockNode
List<Object> bodyB = new ArrayList<Object>();
while(it.hasNext()){
bodyB.add(it.next());
}
ASTIfNode newNode = new ASTIfNode(new SETNodeLabel(),newCond,bodyB);
//add this node to the bodyA
bodyA.add(newNode);
return bodyA;
}
/*
The method will go through the iterator because of the sequence
of methods called before in the outASTLabeledBlockNode
it knows the following:
All nodes are ASTIFNodes
*/
private List<ASTCondition> getConditions(Iterator it){
List<ASTCondition> toReturn = new ArrayList<ASTCondition>();
while(it.hasNext()){
//safe cast since we know these are all ASTIfNodes
ASTIfNode node = (ASTIfNode)it.next();
ASTCondition cond = node.get_Condition();
//check if this is the last in which case we need to flip
if(it.hasNext()){
//no need to flip
toReturn.add(cond);
}
else{
//need to flip condition
//System.out.println("old:"+cond);
cond.flip();
//System.out.println("new"+cond);
toReturn.add(cond);
}
}//end of while
return toReturn;
}
private boolean checkAllAreIfsWithProperBreaks(Iterator it,String outerLabel, String innerLabel){
//the pattern says that ALL bodies in this list should be IF statements
while(it.hasNext()){
ASTNode secondLabelsBody = (ASTNode)it.next();
//check that this is a ifNode with a single statement
Stmt stmt = isIfNodeWithOneStatement(secondLabelsBody);
if(stmt == null){
//pattern is broken
return false;
}
//check if the single stmt follows the pattern
boolean abrupt = abruptLabel(stmt,outerLabel,innerLabel,it.hasNext());
if(!abrupt){
//stmt does not follow the pattern
return false;
}
}//end of while going through all the bodies of the secondlabel
//if we get here that means everything was according to the pattern
return true;
}
/*
If the stmt is a break stmt then see it breaks the inner label and thee boolean is true return true
If the stmt is a continue then see it continues the outer label and the boolean is false return true
else return false
*/
private boolean abruptLabel(Stmt stmt, String outerLabel, String innerLabel, boolean hasNext){
if(!(stmt instanceof DAbruptStmt)){
//this is not a break/continue stmt
return false;
}
DAbruptStmt abStmt = (DAbruptStmt)stmt;
SETNodeLabel label = abStmt.getLabel();
String abruptLabel=label.toString();
if(abruptLabel==null)
return false;
if(abStmt.is_Break() && abruptLabel.compareTo(innerLabel)==0 && hasNext){
return true;
}
else if (abStmt.is_Continue() && abruptLabel.compareTo(outerLabel)==0 && !hasNext){
return true;
}
else
return false;
}
private Stmt isIfNodeWithOneStatement(ASTNode secondLabelsBody){
if(!(secondLabelsBody instanceof ASTIfNode)){
//pattern broken as this should be a IfNode
return null;
}
//check that the body of ASTIfNode has a single ASTStatementSequence
ASTIfNode ifNode =(ASTIfNode)secondLabelsBody;
List<Object> ifSubBodies =ifNode.get_SubBodies();
if(ifSubBodies.size()!=1){
//if body should always have oneSubBody
return null;
}
//if has one SubBody
List ifBody = (List)ifSubBodies.get(0);
//Looking for a statement sequence node with a single stmt
if(ifBody.size()!=1){
//there should only be one body
return null;
}
//The only subBody has one ASTNode
ASTNode ifBodysBody = (ASTNode)ifBody.get(0);
if(!(ifBodysBody instanceof ASTStatementSequenceNode)){
//had to be a STMTSEQ node
return null;
}
//the only ASTnode is a ASTStatementSequence
List<Object> statements = ((ASTStatementSequenceNode)ifBodysBody).getStatements();
if(statements.size()!=1){
//there is more than one statement
return null;
}
//there is only one statement return the statement
AugmentedStmt as = (AugmentedStmt)statements.get(0);
Stmt s = as.get_Stmt();
return s;
}
}