/* 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 soot.*;
import soot.util.*;
import soot.jbco.IJbcoTransform;
import soot.jbco.util.Rand;
import soot.jimple.*;
import java.util.*;
/**
* @author Michael Batchelder
*
* Created on 15-Feb-2006
*/
public class GotoInstrumenter extends BodyTransformer implements IJbcoTransform {
private int trapsAdded = 0;
private int gotosInstrumented = 0;
public static String dependancies[] = new String[] { "jtp.jbco_gia" };
public String[] getDependancies() {
return dependancies;
}
public static String name = "jtp.jbco_gia";
public String getName() {
return name;
}
public void outputSummary() {
out.println("Gotos Instrumented "+gotosInstrumented);
out.println("Traps Added "+trapsAdded);
}
static boolean verbose = G.v().soot_options_Options().verbose();
protected void internalTransform(Body b, String phaseName, Map options)
{
if (b.getMethod().getName().indexOf("<init>")>=0) return;
int weight = soot.jbco.Main.getWeight(phaseName, b.getMethod().getSignature());
if (weight == 0) return;
PatchingChain units = b.getUnits();
int size = units.size();
Unit first = null;
Iterator uit = units.iterator();
while (uit.hasNext()) {
Object o = uit.next();
if (o instanceof IdentityStmt) {
first=(Unit)o;
size--;
} else
break;
}
if (size < 8) return;
if (first == null)
first = (Unit)units.getFirst();
Chain traps = b.getTraps();
int i = 0, rand = 0;
while (i++ < 10)
{
rand = Rand.getInt(size);
if (rand<1)
rand = 1;
else if (rand == size - 1)
rand = size - 2;
if (isExceptionCaughtAt(units, rand + (units.size() - size), traps.iterator()))
continue;
break;
}
// if 10 tries, we give up
if (i>=10) return;
i = 0;
if (output) {
out.println("Applying Gotos to "+b.getMethod().getName());
}
/*Iterator it = units.iterator();
while(it.hasNext()) {
Unit x = (Unit)it.next();
System.out.println(i+++": "+x.toString() + " : "+isExceptionCaughtAt(units, x,traps.iterator()));
}*/
// move random-size chunk at beginning to end
first = (Unit)units.getSuccOf(first);
Unit u = first;
do {
Object toU[] = u.getBoxesPointingToThis().toArray();
for (Object element : toU)
u.removeBoxPointingToThis((UnitBox)element);
// unit box targets stay with a unit even if the unit is removed.
Unit u2 = (Unit)units.getSuccOf(u);
units.remove(u);
units.add(u);
for (Object element : toU)
u.addBoxPointingToThis((UnitBox)element);
u = u2;
} while (++i < rand);
Unit oldFirst = first;
// add goto as FIRST unit to point to new chunk location
if (first instanceof GotoStmt) {
oldFirst = ((GotoStmt)first).getTargetBox().getUnit();
first = Jimple.v().newGotoStmt(((GotoStmt)first).getTargetBox().getUnit());
} else
first = Jimple.v().newGotoStmt(first);
units.insertBeforeNoRedirect(first,u);
// add goto as LAST unit to point to new position of second chunk
if (((Unit)units.getLast()).fallsThrough()) {
Stmt gtS = null;
if (u instanceof GotoStmt)
gtS = Jimple.v().newGotoStmt(((GotoStmt)u).getTargetBox().getUnit());
else
gtS = Jimple.v().newGotoStmt(u);
units.add(gtS);
}
RefType throwable = G.v().soot_Scene().getRefType("java.lang.Throwable");
CaughtExceptionRef cexc = Jimple.v().newCaughtExceptionRef();
Local excLocal = Jimple.v().newLocal("jbco_gi_caughtExceptionLocal", throwable);
b.getLocals().add(excLocal);
Unit handler = Jimple.v().newIdentityStmt(excLocal,cexc);
units.add(handler);
units.add(Jimple.v().newThrowStmt(excLocal));
Unit trapEnd = (Unit)units.getSuccOf(oldFirst);
try {
while (trapEnd instanceof IdentityStmt)
trapEnd = (Unit)units.getSuccOf(trapEnd);
trapEnd = (Unit)units.getSuccOf(trapEnd);
b.getTraps().add(Jimple.v().newTrap(throwable.getSootClass(), (Unit)units.getPredOf(oldFirst), trapEnd, handler));
trapsAdded++;
} catch (Exception exc) {}
gotosInstrumented++;
}
private boolean isExceptionCaughtAt(Chain units, int idx, Iterator trapsIt)
{
Object u = null;
Iterator it = units.iterator();
while (it.hasNext())
{
if (idx--==0) {
u = it.next();
break;
}
it.next();
}
//System.out.println("\r\tselected unit is "+u);
while (trapsIt.hasNext())
{
Trap t = (Trap)trapsIt.next();
it = units.iterator(t.getBeginUnit(),units.getPredOf(t.getEndUnit()));
while (it.hasNext())
if (u.equals(it.next()))
return true;
if (t.getEndUnit().equals(u))
return true;
}
return false;
}
}