/* Soot - a J*va Optimization Framework
* Copyright (C) 1999 Patrick Lam, 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.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
package soot.jimple.toolkits.invoke;
import soot.*;
import soot.jimple.*;
import soot.util.*;
import java.util.*;
/** Utility methods for dealing with traps. */
public class ThrowManager
{
/** Iterate through the statements in b (starting at the end), returning
* the last instance of the following pattern:
*
* r928 = new java.lang.NullPointerException;
* specialinvoke r928."<init>"();
* throw r928;
*
* Creates if necessary.
*/
public static Stmt getNullPointerExceptionThrower(JimpleBody b)
{
Chain units = b.getUnits();
Set trappedUnits = TrapManager.getTrappedUnitsOf(b);
for (Stmt s = (Stmt)units.getLast(); s != units.getFirst();
s = (Stmt)units.getPredOf(s))
{
if (trappedUnits.contains(s))
continue;
if (s instanceof ThrowStmt)
{
Value throwee = ((ThrowStmt)s).getOp();
if (throwee instanceof Constant)
continue;
if (s == units.getFirst())
break;
Stmt prosInvoke = (Stmt)units.getPredOf(s);
if (!(prosInvoke instanceof InvokeStmt))
continue;
if (prosInvoke == units.getFirst())
break;
Stmt prosNew = (Stmt)units.getPredOf(prosInvoke);
if (!(prosNew instanceof AssignStmt))
continue;
InvokeExpr ie = ((InvokeStmt)prosInvoke).getInvokeExpr();
if (!(ie instanceof SpecialInvokeExpr))
continue;
if (((SpecialInvokeExpr)ie).getBase() != throwee ||
!ie.getMethodRef().name().equals("<init>"))
continue;
Value lo = ((AssignStmt)prosNew).getLeftOp();
Value ro = ((AssignStmt)prosNew).getRightOp();
if (lo != throwee || !(ro instanceof NewExpr))
continue;
Type newType = ((NewExpr)ro).getBaseType();
if (!newType.equals(RefType.v("java.lang.NullPointerException")))
continue;
// Whew!
return prosNew;
}
}
// Create.
Stmt last = (Stmt)units.getLast();
return addThrowAfter(b, last);
}
static Stmt addThrowAfter(JimpleBody b, Stmt target)
{
Chain units = b.getUnits();
Chain locals = b.getLocals();
int i = 0;
// Bah!
boolean canAddI = false;
do
{
canAddI = true;
Iterator localIt = locals.iterator();
while (localIt.hasNext())
{
Local l = (Local)localIt.next();
if (l.getName().equals("__throwee"+i))
canAddI = false;
}
if (!canAddI)
i++;
}
while (!canAddI);
Local l = Jimple.v().newLocal("__throwee"+i, RefType.v("java.lang.NullPointerException"));
b.getLocals().add(l);
Stmt newStmt = Jimple.v().newAssignStmt
(l, Jimple.v().newNewExpr(RefType.v("java.lang.NullPointerException")));
Stmt invStmt = Jimple.v().newInvokeStmt
(Jimple.v().newSpecialInvokeExpr(l, Scene.v().getMethod("<java.lang.NullPointerException: void <init>()>").makeRef()));
Stmt throwStmt = Jimple.v().newThrowStmt(l);
units.insertAfter(newStmt, target);
units.insertAfter(invStmt, newStmt);
units.insertAfter(throwStmt, invStmt);
return newStmt;
}
/** If exception e is caught at stmt s in body b, return the handler;
* otherwise, return null. */
static boolean isExceptionCaughtAt(SootClass e, Stmt stmt, Body b)
{
/* Look through the traps t of b, checking to see if:
* - caught exception is e;
* - and, stmt lies between t.beginUnit and t.endUnit */
Hierarchy h = new Hierarchy();
Iterator trapsIt = b.getTraps().iterator();
while (trapsIt.hasNext())
{
Trap t = (Trap)trapsIt.next();
/* Ah ha, we might win. */
if (h.isClassSubclassOfIncluding(e, t.getException()))
{
Iterator it = b.getUnits().iterator(t.getBeginUnit(),
t.getEndUnit());
while (it.hasNext())
if (stmt.equals(it.next()))
return true;
}
}
return false;
}
}