/* 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.jimpleTransformations;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import soot.*;
import soot.jbco.util.Rand;
import soot.jbco.*;
import soot.jimple.*;
import soot.toolkits.graph.BriefUnitGraph;
import soot.toolkits.scalar.*;
import soot.util.*;
/**
* @author Michael Batchelder
*
* Created on 10-Jul-2006
*/
public class AddSwitches extends BodyTransformer implements IJbcoTransform {
int switchesadded = 0;
public void outputSummary() {
out.println("Switches added: "+switchesadded);
}
public static String dependancies[] = new String[] { "wjtp.jbco_fr", "jtp.jbco_adss", "bb.jbco_ful"};
public String[] getDependancies() {
return dependancies;
}
public static String name = "jtp.jbco_adss";
public String getName() {
return name;
}
public boolean checkTraps(Unit u, Body b) {
Iterator it = b.getTraps().iterator();
while (it.hasNext()) {
Trap t = (Trap)it.next();
if (t.getBeginUnit() == u ||
t.getEndUnit() == u ||
t.getHandlerUnit() == u)
return true;
}
return false;
}
protected void internalTransform(Body b, String phaseName, Map options)
{
if (b.getMethod().getSignature().indexOf("<clinit>") >= 0) return;
int weight = soot.jbco.Main.getWeight(phaseName, b.getMethod().getSignature());
if (weight == 0) return;
New2InitFlowAnalysis fa = new New2InitFlowAnalysis(new BriefUnitGraph(b));
Vector zeroheight = new Vector();
PatchingChain units = b.getUnits();
Unit first = null;
Iterator it = units.snapshotIterator();
while (it.hasNext()) {
Unit unit = (Unit)it.next();
if (unit instanceof IdentityStmt)
continue;
first = unit;
break;
}
it = units.snapshotIterator();
while (it.hasNext()) {
Unit unit = (Unit)it.next();
if (unit instanceof IdentityStmt || checkTraps(unit,b))
continue;
// very conservative estimate about where new-<init> ranges are
if (((FlowSet)fa.getFlowAfter(unit)).size() == 0
&& ((FlowSet)fa.getFlowBefore(unit)).size() == 0)
zeroheight.add(unit);
}
if (zeroheight.size()<3) return;
int idx = 0;
Unit u = null;
for (int i = 0; i < zeroheight.size(); i++)
{
idx = Rand.getInt(zeroheight.size()-1) + 1;
u = (Unit)zeroheight.get(idx);
if (u.fallsThrough())
break;
u = null;
}
// couldn't find a unit that fell through
if (u == null || Rand.getInt(10) > weight) return;
zeroheight.remove(idx);
while(zeroheight.size() > (weight>3?weight:3)) {
zeroheight.remove(Rand.getInt(zeroheight.size()));
}
Chain locals = b.getLocals();
ArrayList targs = new ArrayList();
targs.addAll(zeroheight);
SootField ops[] = FieldRenamer.getRandomOpaques();
Local b1 = Jimple.v().newLocal("addswitchesbool1", BooleanType.v());
locals.add(b1);
Local b2 = Jimple.v().newLocal("addswitchesbool2", BooleanType.v());
locals.add(b2);
if (ops[0].getType() instanceof PrimType) {
units.insertBefore(Jimple.v().newAssignStmt(b1,Jimple.v().newStaticFieldRef(ops[0].makeRef())),u);
} else {
RefType rt = (RefType)ops[0].getType();
SootMethod m = rt.getSootClass().getMethodByName("booleanValue");
Local B = Jimple.v().newLocal("addswitchesBOOL1", rt);
locals.add(B);
units.insertBefore(Jimple.v().newAssignStmt(B,Jimple.v().newStaticFieldRef(ops[0].makeRef())),u);
units.insertBefore(Jimple.v().newAssignStmt(b1,Jimple.v().newVirtualInvokeExpr(B,m.makeRef(),new ArrayList())),u);
}
if (ops[1].getType() instanceof PrimType) {
units.insertBefore(Jimple.v().newAssignStmt(b2,Jimple.v().newStaticFieldRef(ops[1].makeRef())),u);
} else {
RefType rt = (RefType)ops[1].getType();
SootMethod m = rt.getSootClass().getMethodByName("booleanValue");
Local B = Jimple.v().newLocal("addswitchesBOOL2", rt);
locals.add(B);
units.insertBefore(Jimple.v().newAssignStmt(B,Jimple.v().newStaticFieldRef(ops[1].makeRef())),u);
units.insertBefore(Jimple.v().newAssignStmt(b2,Jimple.v().newVirtualInvokeExpr(B,m.makeRef(),new ArrayList())),u);
}
IfStmt ifstmt = Jimple.v().newIfStmt(Jimple.v().newNeExpr(b1,b2),u);
units.insertBefore(ifstmt,u);
Local l = Jimple.v().newLocal("addswitchlocal",IntType.v());
locals.add(l);
units.insertBeforeNoRedirect(Jimple.v().newAssignStmt(l, IntConstant.v(0)), first);
units.insertAfter(Jimple.v().newTableSwitchStmt(l,1,zeroheight.size(),targs,u),ifstmt);
switchesadded += zeroheight.size() + 1;
Iterator tit = targs.iterator();
while (tit.hasNext()) {
Unit nxt = (Unit)tit.next();
if (Rand.getInt(5) < 4) {
units.insertBefore(Jimple.v().newAssignStmt(l,Jimple.v().newAddExpr(l,IntConstant.v(Rand.getInt(3)+1))), nxt);
}
}
ifstmt.setTarget(u);
}
}