/* 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:{ label_1:{
label_0:{ if(cond1 || cond2){
if(cond1){ Body1
break label_0; }
} }
if(!cond2){ Body2
break label_1; ------>
} Cant remove label_1 as Body 1
}//end of label_0 might have reference to it
Body1 can however set some flag if we are
}//end of label_1 sure that label_1 is not broken
Body2 and later removed
TO MAKE CODE EFFECIENT BLOCK THE ANALYSIS TO GOING INTO STATEMENTS
this is done by overriding the caseASTStatementSequenceNode
*/
public class OrAggregatorOne extends DepthFirstAdapter{
public OrAggregatorOne(){
}
public OrAggregatorOne(boolean verbose){
super(verbose);
}
public void caseASTStatementSequenceNode(ASTStatementSequenceNode node){
}
public void outASTLabeledBlockNode(ASTLabeledBlockNode node){
String outerLabel = node.get_Label().toString();
if(outerLabel==null)
return;
String innerLabel=null;
ASTLabeledBlockNode secondLabeledBlockNode = isLabelWithinLabel(node);
if(secondLabeledBlockNode == null){
//node doesnt have an immediate label following it
return;
}
//store the labelname
innerLabel=secondLabeledBlockNode.get_Label().toString();
if(innerLabel==null){
//empty or marked for deletion
return;
}
List secondLabelsBodies= getSecondLabeledBlockBodies(secondLabeledBlockNode);
boolean allIfs = checkAllAreIfsWithProperBreaks(secondLabelsBodies.iterator(),outerLabel,innerLabel);
if(!allIfs){
//pattern doesnt match
return;
}
//the pattern has been matched do the transformation
// Create a list of conditions to be Ored together
// remembering that the last ones condition is to be flipped
List<ASTCondition> conditions = getConditions(secondLabelsBodies.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);
}
//will contain the Body of the ASTIfNode
List<Object> newIfBody = new ArrayList<Object>();
//get_SubBodies of upper labeled block
List<Object> subBodies = node.get_SubBodies();
//we know that there is only one SubBody for this node retrieve that
List labeledBlockBody = (List)subBodies.get(0);
//from the isLabelWithinLabel method we know that the first is the labeled block
//discard that keep the rest
Iterator subBodiesIt = labeledBlockBody.iterator();
subBodiesIt.next();//discarding first
while(subBodiesIt.hasNext()){
ASTNode temp = (ASTNode)subBodiesIt.next();
newIfBody.add(temp);
}
ASTIfNode newNode = new ASTIfNode(new SETNodeLabel(),newCond,newIfBody);
List<Object> newLabeledBlockBody = new ArrayList<Object>();
newLabeledBlockBody.add(newNode);
G.v().ASTTransformations_modified = true;
//System.out.println("OR AGGREGATING ONE!!!");
node.replaceBody(newLabeledBlockBody);
/*
See if the outer label can be marked as useless
*/
UselessLabelFinder.v().findAndKill(node);
}
private ASTLabeledBlockNode isLabelWithinLabel(ASTLabeledBlockNode node){
List<Object> subBodies = node.get_SubBodies();
if(subBodies.size()==0){ //shouldnt happen
//labeledBlockNodes size is zero this is a useless label
//marked for removal by setting an empty SETNodeLabel
node.set_Label(new SETNodeLabel());
return null;
}
//LabeledBlockNode had SubBody we know there is always only one
List bodies = (List)subBodies.get(0);
//these bodies should be a labelled block followed by something
if(bodies.size()==0){
//there is nothing inside this labeledBlock
//an empty Body is useless
node.set_Label(new SETNodeLabel());
return null;
}
//there is some ASTNode there
ASTNode firstBody = (ASTNode)bodies.get(0);
if(!(firstBody instanceof ASTLabeledBlockNode)){
//first body is not a labeledBlock node thus the pattern
//does not have the shape
// label_1:
// label_0
return null;
}
//Pattern is fine return the ASTLabeledBlockNode found
return (ASTLabeledBlockNode)firstBody;
}
private List getSecondLabeledBlockBodies(ASTLabeledBlockNode secondLabeledBlockNode){
//retrieve the SubBodies of this second labeledblock
List<Object> secondLabelsSubBodies = secondLabeledBlockNode.get_SubBodies();
if(secondLabelsSubBodies.size()==0){
//there is nothing in the labeledblock
//highlly unlikely but if yes then set labeledBlockNode for not printing/deletion
secondLabeledBlockNode.set_Label(new SETNodeLabel());
return null;
}
/*
there is atleast one body in there and infact it should be only one
since this is a labeledBlockNode
*/
List secondLabelsBodies = (List)secondLabelsSubBodies.get(0);
//return the list
return secondLabelsBodies;
}
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 is a break stmt
String labelBroken = breaksLabel(stmt);
if(labelBroken == null){
//stmt does not break a label
return false;
}
//check if this is the inner label broken and is not the last in the iterator
if(labelBroken.compareTo(innerLabel)==0 && it.hasNext())
continue;
//check if this is the outer label broken and is the last in the iterator
if(labelBroken.compareTo(outerLabel)==0 && !it.hasNext())
continue;
//if we get here that means this is not a break breaking the label we want
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 this method
returns the labels name
else returns null
*/
private String breaksLabel(Stmt stmt){
if(!(stmt instanceof DAbruptStmt)){
//this is not a break stmt
return null;
}
DAbruptStmt abStmt = (DAbruptStmt)stmt;
if(!abStmt.is_Break()){
//not a break stmt
return null;
}
SETNodeLabel label = abStmt.getLabel();
return label.toString();
}
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;
}
/*
The method will go through the iterator because of the sequence
of methods called before in the outASTLabeledBlockNode
it knows the following:
1, 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
cond.flip();
toReturn.add(cond);
}
}//end of while
return toReturn;
}
}