/* 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:{
___________________ ____________________
| | | |
| no break label_1 | | no break label_1 |
|___________________| |____________________|
| | | |
|ASTLabeledNode | | label_1: |
|while(cond){ | ----> | while(cond){ |
| use of label_1 | | use of label_1 |
| | | } |
|} | |____________________|
|___________________|
| |
| Nothing here |
|___________________|
}//end of label_1
The important thing to note in this case is that the node which uses breaks
extends ASTLabeledNode so that we can move the label down. Obviously there shouldnt be
an already existing label on this node. Once the node containing the break is detected
there should be no node following this in the body of the labeled block. This is so because
if the break is moved down that code will get executed and thats a wrong transformation.
label_1:{
___________________ _____________________
| | | |
|label_2 | | label_2: |
|while(cond){ | ----> | while(cond){ |
| use of label_1 | | label_1 replaced|
| | | by label_2 |
|} | |___}_________________|
|___________________|
| |
| Nothing here |
|___________________|
}//end of label_1
If the previous pattern did not match because the node on which we wanted to push the label
inwards already had a label we can try to use the label on the inner node. This is only possible
if there is only a single node in the labeledBlocks subBody, to make sure that we break and jump
to exactly the same point as we were jumping before.
TO MAKE CODE EFFECIENT BLOCK THE ANALYSIS TO GOING INTO STATEMENTS
this is done by overriding the caseASTStatementSequenceNode
*/
public class PushLabeledBlockIn extends DepthFirstAdapter{
public PushLabeledBlockIn(){
}
public PushLabeledBlockIn(boolean verbose){
super(verbose);
}
public void caseASTStatementSequenceNode(ASTStatementSequenceNode node){
}
public void outASTLabeledBlockNode(ASTLabeledBlockNode node){
String label = node.get_Label().toString();
List<Object> subBodies = node.get_SubBodies();
if(subBodies.size()!=1){
return;
}
List subBody = (List)subBodies.get(0);
int nodeNumber=checkForBreak(subBody,label);
if(nodeNumber>-1){
//found some break for this label
//retrieve element at this nodeNumber
if(subBody.size()<nodeNumber){
//something is wrong
throw new RuntimeException("Please submit this benchmark as a bug");
}
//check that this is the last node in the list
//since otherwise we cant change anything
if(nodeNumber+1!=subBody.size()){
//it is not the last
return;
}
//safe to access the list
ASTNode temp = (ASTNode)subBody.get(nodeNumber);
if(!(temp instanceof ASTLabeledNode)){
//does not extend labeledNode hence cannot give it a label
return;
}
ASTLabeledNode tempNode = (ASTLabeledNode)temp;
//shouldnt already have a label
String innerLabel = tempNode.get_Label().toString();
if (innerLabel!=null){
//already has a label
//we could still do something if this is the ONLY node in the body
if(subBody.size()==1){
//there is only one node
/*
The situation is that there is a labeled block whic has only one
node that also has a label on it.
There is some statement deep down which breaks the outer label
No reason why it cant break the inner label since there is nothing after that!!!
label has the outer label whose break we found
innerLabel has the label of the inner node which contains the break
replace all occurances of break of outer label
with that of break of inner label
*/
//we know that the breaks occur within the subtree rooted at temp
boolean done=replaceBreakLabels(temp,label,innerLabel);
if(done){
//System.out.println("REMOVED LABELED BLOCK-replaced label names");
node.set_Label(new SETNodeLabel());
G.v().ASTTransformations_modified = true;
}
}
return;
}
else{
//doesnt have a label
//System.out.println("PUSHED LABEL DOWN");
SETNodeLabel newLabel = new SETNodeLabel();
newLabel.set_Name(label);
tempNode.set_Label(newLabel);
node.set_Label(new SETNodeLabel());
G.v().ASTTransformations_modified = true;
}
}
}
private boolean replaceBreakLabels(ASTNode node,String toReplace, String replaceWith){
boolean toReturn=false;
List<Object> subBodies=node.get_SubBodies();
Iterator<Object> subIt = subBodies.iterator();
while(subIt.hasNext()){
List subBody=null;
if(node instanceof ASTTryNode){
ASTTryNode.container subBodyContainer = (ASTTryNode.container) subIt.next();
subBody=(List)subBodyContainer.o;
}
else
subBody=(List)subIt.next();
Iterator it = subBody.iterator();
while(it.hasNext()){
ASTNode temp = (ASTNode)it.next();
//check if this is ASTStatementSequenceNode
if(temp instanceof ASTStatementSequenceNode){
ASTStatementSequenceNode stmtSeq = (ASTStatementSequenceNode)temp;
List<Object> statements = stmtSeq.getStatements();
Iterator<Object> stmtIt = statements.iterator();
while(stmtIt.hasNext()){
AugmentedStmt as = (AugmentedStmt)stmtIt.next();
Stmt s = as.get_Stmt();
String labelBroken = isAbrupt(s);
if(labelBroken != null){//stmt breaks some label
if(labelBroken.compareTo(toReplace)==0){
//we have found a break breaking this label
//replace the label with "replaceWith"
replaceLabel(s,replaceWith);
toReturn=true;
}
}
}
}//if it was a StmtSeq node
else{
//otherwise recursion
boolean returnVal=replaceBreakLabels(temp,toReplace,replaceWith);
if(returnVal)
toReturn=true;
}
}//end of while
}
return toReturn;
}
private int checkForBreak(List ASTNodeBody,String outerLabel){
Iterator it = ASTNodeBody.iterator();
int nodeNumber=0;
while(it.hasNext()){
ASTNode temp = (ASTNode)it.next();
//check if this is ASTStatementSequenceNode
if(temp instanceof ASTStatementSequenceNode){
ASTStatementSequenceNode stmtSeq = (ASTStatementSequenceNode)temp;
List<Object> statements = stmtSeq.getStatements();
Iterator<Object> stmtIt = statements.iterator();
while(stmtIt.hasNext()){
AugmentedStmt as = (AugmentedStmt)stmtIt.next();
Stmt s = as.get_Stmt();
String labelBroken = breaksLabel(s);
if(labelBroken != null && outerLabel!=null){//stmt breaks some label
if(labelBroken.compareTo(outerLabel)==0){
//we have found a break breaking this label
return nodeNumber;
}
}
}
}//if it was a StmtSeq node
else{
//otherwise recursion
//getSubBodies
List<Object> subBodies=temp.get_SubBodies();
Iterator<Object> subIt = subBodies.iterator();
while(subIt.hasNext()){
if(temp instanceof ASTTryNode){
ASTTryNode.container subBody = (ASTTryNode.container) subIt.next();
if(checkForBreak((List)subBody.o,outerLabel)> (-1) ){
//if this is true there was a break found
return nodeNumber;
}
}
else{
if(checkForBreak((List)subIt.next(),outerLabel)> (-1) ){
//if this is true there was a break found
return nodeNumber;
}
}
}
}
nodeNumber++;
}//end of while
return -1;
}
/*
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();
}
/*
If the stmt is a abruptstmt either break or continue
returns the labels name
else returns null
*/
private String isAbrupt(Stmt stmt){
if(!(stmt instanceof DAbruptStmt)){
//this is not a break stmt
return null;
}
DAbruptStmt abStmt = (DAbruptStmt)stmt;
if(abStmt.is_Break() || abStmt.is_Continue()){
SETNodeLabel label = abStmt.getLabel();
return label.toString();
}
else
return null;
}
private void replaceLabel(Stmt s, String replaceWith){
//we know its an AbruptStmt
DAbruptStmt abStmt = (DAbruptStmt)s;
SETNodeLabel label = abStmt.getLabel();
label.set_Name(replaceWith);
}
}