/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-1999 Raja Vallee-Rai
*
* 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.jbco.bafTransformations;
import java.util.*;
import soot.*;
import soot.jbco.IJbcoTransform;
import soot.jbco.util.Rand;
import soot.toolkits.graph.BriefUnitGraph;
import soot.baf.internal.*;
import soot.baf.*;
/**
* @author Michael Batchelder
*
* Created on 31-Mar-2006
*/
public class MoveLoadsAboveIfs extends BodyTransformer implements IJbcoTransform {
int movedloads = 0;
public static String dependancies[] = new String[] {"bb.jbco_rlaii", "bb.jbco_ful", "bb.lp"};
public String[] getDependancies() {
return dependancies;
}
public static String name = "bb.jbco_rlaii";
public String getName() {
return name;
}
public void outputSummary() {
out.println("Moved Loads Above Ifs: "+movedloads);
}
protected void internalTransform(Body b, String phaseName, Map options) {
int weight = soot.jbco.Main.getWeight(phaseName, b.getMethod().getSignature());
if (weight == 0) return;
BriefUnitGraph bug = new BriefUnitGraph(b);
ArrayList<Unit> candidates = new ArrayList<Unit>();
ArrayList<Unit> visited = new ArrayList<Unit>();
ArrayList worklist = new ArrayList();
worklist.addAll(bug.getHeads());
while(worklist.size()>0) {
Unit u = (Unit)worklist.remove(0);
if (visited.contains(u))
continue;
visited.add(u);
List succs = bug.getSuccsOf(u);
if (u instanceof TargetArgInst) {
if (checkCandidate(succs,bug))
candidates.add(u);
}
for (int i = 0; i < succs.size(); i++) {
Object o = succs.get(i);
if (!visited.contains(o))
worklist.add(o);
}
}
int orig = movedloads;
boolean changed = false;
PatchingChain units = b.getUnits();
for (int i = 0; i < candidates.size(); i++) {
Unit u = candidates.get(i);
List succs = bug.getSuccsOf(u);
BLoadInst clone = (BLoadInst)((BLoadInst)succs.get(0)).clone();
if (u instanceof IfNonNullInst || u instanceof IfNullInst) {
if (category(clone.getOpType())==2 || Rand.getInt(10) > weight)
continue;
units.insertBefore(clone,u);
units.insertBefore(Baf.v().newSwapInst(RefType.v(),clone.getOpType()),u);
//units.insertAfter(clone,p);
//units.insertAfter(Baf.v().newSwapInst(RefType.v(),clone.getOpType()),clone);
} else if (u instanceof OpTypeArgInst) {
Type t = ((OpTypeArgInst)u).getOpType();
if (category(t)==2 || Rand.getInt(10) > weight)
continue;
units.insertBefore(clone,u);
Type t2 = clone.getOpType();
Unit dup;
if (category(t2)==2) {
dup = Baf.v().newDup2_x2Inst(t2,null,t,t);
} else {
dup = Baf.v().newDup1_x2Inst(t2,t,t);
}
units.insertBefore(dup,u);
units.insertBefore(Baf.v().newPopInst(t2),u);
/*units.insertAfter(clone,p);
Type t2 = clone.getOpType();
Unit dup;
if (category(t2)==2) {
dup = Baf.v().newDup2_x2Inst(t2,null,t,t);
} else {
dup = Baf.v().newDup1_x2Inst(t2,t,t);
}
units.insertAfter(dup,clone);
units.insertAfter(Baf.v().newPopInst(t2),dup);*/
} else {
if (category(clone.getOpType())==2 || Rand.getInt(10) > weight)
continue;
units.insertBefore(clone,u);
units.insertBefore(Baf.v().newSwapInst(IntType.v(),clone.getOpType()),u);
//units.insertAfter(clone,p);
//units.insertAfter(Baf.v().newSwapInst(IntType.v(),clone.getOpType()),clone);
}
movedloads++;
// remove old loads after the jump
for (int j = 0; j < succs.size(); j++) {
Unit suc = (Unit)succs.get(j);
List sucPreds = bug.getPredsOf(suc);
if (sucPreds.size() > 1) {
if (suc == ((TargetArgInst)u).getTarget())
((TargetArgInst)u).setTarget((Unit)bug.getSuccsOf(suc).get(0));
else {
units.insertAfter(Baf.v().newGotoInst((Unit)bug.getSuccsOf(suc).get(0)),u);
}
} else {
units.remove(suc);
}
}
if (i < candidates.size() - 1)
bug = new BriefUnitGraph(b);
changed = true;
}
if(changed) {
if (output)
out.println((movedloads - orig) + " loads moved above ifs in "+b.getMethod().getSignature());
if (debug)
StackTypeHeightCalculator.calculateStackHeights(b);
}
}
private boolean checkCandidate(List succs, BriefUnitGraph bug) {
if (succs.size() < 2)
return false;
Object o = succs.get(0);
for (int i = 1; i < succs.size(); i++) {
if (succs.get(i).getClass() != o.getClass())
return false;
}
if (o instanceof BLoadInst) {
BLoadInst bl = (BLoadInst)o;
Local l = bl.getLocal();
for (int i = 1; i < succs.size(); i++) {
BLoadInst bld = (BLoadInst)succs.get(i);
if (bld.getLocal() != l || bug.getPredsOf(bld).size() > 1)
return false;
}
return true;
}
return false;
}
private int category(Type t) {
return ((t instanceof LongType || t instanceof DoubleType) ? 2 : 1);
}
}