/* Soot - a J*va Optimization Framework
* Copyright (C) 2003 Jerome Miecznikowski
*
* 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.finders;
import soot.*;
import java.io.Serializable;
import java.util.*;
import soot.util.*;
import soot.dava.*;
import soot.jimple.*;
import soot.dava.internal.asg.*;
import soot.dava.internal.SET.*;
public class ExceptionFinder implements FactFinder
{
public ExceptionFinder( Singletons.Global g ) {}
public static ExceptionFinder v() { return G.v().soot_dava_toolkits_base_finders_ExceptionFinder(); }
public void find( DavaBody body, AugmentedStmtGraph asg, SETNode SET) throws RetriggerAnalysisException
{
Dava.v().log( "ExceptionFinder::find()");
Iterator it = body.get_ExceptionFacts().iterator();
while (it.hasNext()) {
ExceptionNode en = (ExceptionNode) it.next();
if (body.get_SynchronizedBlockFacts().contains( en))
continue;
IterableSet fullBody = new IterableSet();
Iterator cit = en.get_CatchList().iterator();
while (cit.hasNext())
fullBody.addAll( (IterableSet) cit.next());
fullBody.addAll( en.get_TryBody());
if (SET.nest( new SETTryNode( fullBody, en, asg, body)) == false)
throw new RetriggerAnalysisException();
}
}
public void preprocess( DavaBody body, AugmentedStmtGraph asg)
{
Dava.v().log( "ExceptionFinder::preprocess()");
IterableSet enlist = new IterableSet();
// Find the first approximation for all the try catch bodies.
{
Iterator trapIt = body.getTraps().iterator();
while (trapIt.hasNext()) {
Trap trap = (Trap) trapIt.next();
Unit endUnit = trap.getEndUnit();
// get the body of the try block as a raw read of the area of protection
IterableSet tryBody = new IterableSet();
Iterator btit = body.getUnits().iterator( trap.getBeginUnit());
for (Unit u = (Unit) btit.next(); u != endUnit; u = (Unit) btit.next())
tryBody.add( asg.get_AugStmt( (Stmt) u));
enlist.add( new ExceptionNode( tryBody, trap.getException(), asg.get_AugStmt( (Stmt) trap.getHandlerUnit())));
}
}
// Add in gotos that may escape the try body (created by the indirection introduced in DavaBody).
{
Iterator enlit = enlist.iterator();
while (enlit.hasNext()) {
ExceptionNode en = (ExceptionNode) enlit.next();
IterableSet try_body = en.get_TryBody();
Iterator tryIt = try_body.snapshotIterator();
while (tryIt.hasNext()) {
AugmentedStmt tras = (AugmentedStmt) tryIt.next();
Iterator ptIt = tras.cpreds.iterator();
while (ptIt.hasNext()) {
AugmentedStmt pas = (AugmentedStmt) ptIt.next();
Stmt ps = pas.get_Stmt();
if ((try_body.contains( pas) == false) && (ps instanceof GotoStmt)) {
boolean add_it = true;
Iterator cpit = pas.cpreds.iterator();
while (cpit.hasNext())
if ((add_it = try_body.contains( cpit.next())) == false)
break;
if (add_it)
en.add_TryStmt( pas);
}
}
}
}
}
// Split up the try blocks until they cause no nesting problems.
splitLoop:
while (true)
{
// refresh the catch bodies
{
Iterator enlit = enlist.iterator();
while (enlit.hasNext())
((ExceptionNode) enlit.next()).refresh_CatchBody( this);
}
// split for inter-exception nesting problems
{
ExceptionNode[] ena = new ExceptionNode[ enlist.size()];
Iterator enlit = enlist.iterator();
for (int i=0; enlit.hasNext(); i++)
ena[ i] = (ExceptionNode) enlit.next();
for (int i=0; i<ena.length-1; i++) {
ExceptionNode eni = ena[i];
for (int j=i+1; j<ena.length; j++) {
ExceptionNode enj = ena[j];
IterableSet
eniTryBody = eni.get_TryBody(),
enjTryBody = enj.get_TryBody();
if ((eniTryBody.equals( enjTryBody) == false) && (eniTryBody.intersects( enjTryBody))) {
if ((eniTryBody.isSupersetOf( enj.get_Body())) ||
(enjTryBody.isSupersetOf( eni.get_Body())))
continue;
IterableSet newTryBody = eniTryBody.intersection( enjTryBody);
if (newTryBody.equals( enjTryBody))
eni.splitOff_ExceptionNode( newTryBody, asg, enlist);
else
enj.splitOff_ExceptionNode( newTryBody, asg, enlist);
continue splitLoop;
}
}
}
}
// split for intra-try-body issues
{
Iterator enlit = enlist.iterator();
while (enlit.hasNext()) {
ExceptionNode en = (ExceptionNode) enlit.next();
// Get the try block entry points
IterableSet tryBody = en.get_TryBody();
LinkedList<AugmentedStmt> heads = new LinkedList<AugmentedStmt>();
Iterator trIt = tryBody.iterator();
while (trIt.hasNext()) {
AugmentedStmt as = (AugmentedStmt) trIt.next();
if (as.cpreds.isEmpty()) {
heads.add( as);
continue;
}
Iterator pit = as.cpreds.iterator();
while (pit.hasNext())
if (tryBody.contains( pit.next()) == false) {
heads.add( as);
break;
}
}
HashSet<AugmentedStmt> touchSet = new HashSet<AugmentedStmt>();
touchSet.addAll( heads);
// Break up the try block for all the so-far detectable parts.
AugmentedStmt head = heads.removeFirst();
IterableSet subTryBlock = new IterableSet();
LinkedList<AugmentedStmt> worklist = new LinkedList<AugmentedStmt>();
worklist.add( head);
while (worklist.isEmpty() == false) {
AugmentedStmt as = worklist.removeFirst();
subTryBlock.add( as);
Iterator sit = as.csuccs.iterator();
while (sit.hasNext()) {
AugmentedStmt sas = (AugmentedStmt) sit.next();
if ((tryBody.contains( sas) == false) || (touchSet.contains( sas)))
continue;
touchSet.add( sas);
if (sas.get_Dominators().contains( head))
worklist.add( sas);
else
heads.addLast( sas);
}
}
if (heads.isEmpty() == false) {
en.splitOff_ExceptionNode( subTryBlock, asg, enlist);
continue splitLoop;
}
}
}
break;
}
// Aggregate the try blocks.
{
LinkedList<ExceptionNode> reps = new LinkedList<ExceptionNode>();
HashMap<Serializable, LinkedList<IterableSet>>
hCode2bucket = new HashMap<Serializable, LinkedList<IterableSet>>();
HashMap<Serializable, ExceptionNode>
tryBody2exceptionNode = new HashMap<Serializable, ExceptionNode>();
Iterator enlit = enlist.iterator();
while (enlit.hasNext()) {
ExceptionNode en = (ExceptionNode) enlit.next();
int hashCode = 0;
IterableSet curTryBody = en.get_TryBody();
Iterator trit = curTryBody.iterator();
while (trit.hasNext())
hashCode ^= trit.next().hashCode();
Integer I = new Integer( hashCode);
LinkedList<IterableSet> bucket = hCode2bucket.get( I);
if (bucket == null) {
bucket = new LinkedList<IterableSet>();
hCode2bucket.put( I, bucket);
}
ExceptionNode repExceptionNode = null;
Iterator<IterableSet> bit = bucket.iterator();
while (bit.hasNext()) {
IterableSet bucketTryBody = bit.next();
if (bucketTryBody.equals( curTryBody)) {
repExceptionNode = tryBody2exceptionNode.get( bucketTryBody);
break;
}
}
if (repExceptionNode == null) {
tryBody2exceptionNode.put( curTryBody, en);
bucket.add( curTryBody);
reps.add( en);
}
else
repExceptionNode.add_CatchBody( en);
}
enlist.clear();
enlist.addAll( reps);
}
body.get_ExceptionFacts().clear();
body.get_ExceptionFacts().addAll( enlist);
}
public IterableSet get_CatchBody( AugmentedStmt handlerAugmentedStmt)
{
IterableSet catchBody = new IterableSet();
LinkedList catchQueue = new LinkedList();
catchBody.add( handlerAugmentedStmt);
catchQueue.addAll( handlerAugmentedStmt.csuccs);
while (catchQueue.isEmpty() == false) {
AugmentedStmt as = (AugmentedStmt) catchQueue.removeFirst();
if (catchBody.contains( as))
continue;
if (as.get_Dominators().contains( handlerAugmentedStmt)) {
catchBody.add( as);
catchQueue.addAll( as.csuccs);
}
}
return catchBody;
}
}