[Soot-list] Return Stmt

Chris Pickett chris.pickett at mail.mcgill.ca
Thu May 10 23:39:14 EDT 2007


Although I suppose that if you call restructureReturn the block 
invariant holds, sorry Eric, I guess I missed that subtlety.

Chris

Chris Pickett wrote:
> Mario said "block" and not "body" but I'm still not sure that the 
> invariant holds.  You can test it by inserting a statement after a 
> return, writing out the class file, reading it back into Soot, and 
> seeing if it's still there.  Quite possibly a dead code elimination pass 
> will get rid of it, but that pass could be turned off...
> 
> Chris
> 
> Eric Bodden wrote:
>> No, sorry but that's not at all true. There can be finitely many
>> return statements per body. However, the abc compiler
>> (www.aspectbench.org) has the class Restructure that implements the
>> method restructureReturn(SootMethod). After applying this method, the
>> invariant holds. I have the class attached for your conveninence.
>> However, please respect the appropriate licensing terms in the header
>> (LGPL) if making use of it.
>>
>> Cheers,
>> Eric
>>
>> On 10/05/07, Mario Mendez <mario at cs.unm.edu> wrote:
>>> Can your confirm that the invariant "if a return statement is present in
>>> a block, it is always the last stmt of that block" is true?
>>>
>>> As always,thanks!
>>> _______________________________________________
>>> Soot-list mailing list
>>> Soot-list at sable.mcgill.ca
>>> http://mailman.cs.mcgill.ca/mailman/listinfo/soot-list
>>>
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> /* abc - The AspectBench Compiler
>>  * Copyright (C) 2004 Laurie Hendren
>>  * Copyright (C) 2004 Ondrej Lhotak
>>  * Copyright (C) 2004 Jennifer Lhotak
>>  * Copyright (C) 2004 Sascha Kuzins
>>  * Copyright (C) 2004 Ganesh Sittampalam
>>  *
>>  * This compiler 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 compiler 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 compiler, in the file LESSER-GPL;
>>  * if not, write to the Free Software Foundation, Inc.,
>>  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
>>  */
>>
>> package abc.soot.util;
>>
>> import java.util.*;
>>
>> import polyglot.util.InternalCompilerError;
>>
>> import soot.*;
>> import soot.util.*;
>> import soot.jimple.*;
>> import soot.javaToJimple.LocalGenerator;
>> import soot.jimple.toolkits.scalar.*;
>>
>> import abc.weaving.weaver.*;
>> import abc.weaving.aspectinfo.MethodCategory;
>>
>>
>>
>> /** This class contains a variety of helper methods to restructure Soot
>>  *    method Bodies.
>>  *
>>  * @author Laurie Hendren
>>  * @author Ondrej Lhotak
>>  * @author Jennifer Lhotak
>>  * @author Sascha Kuzins
>>  * @author Ganesh Sittampalam
>>  */
>>
>> public class Restructure {
>>
>>     public static void reset() {
>>     //returns=new Hashtable();
>>     //thiscopies=new Hashtable();
>>     invokeassignstmts=new Hashtable();
>>     }
>>
>>    private static void debug(String message)
>>      { if (abc.main.Debug.v().restructure)
>>          System.err.println("RST*** " + message);
>>      }
>>
>>    /* ------------------- Utility restructurers 
>> ----------------------- */
>>
>>   /** Given a Chain for a body of an <init> method, find the call to
>>    *  the <init> corresponding to either a this() or super() call.  Check
>>    *  that there is exactly one such <init>, otherwise throw a    *  
>> InternalCompilerError.   Return the <init> Stmt.
>>    */
>>   public static InvokeStmt findInitStmt(Chain units)
>>     { // look for the <init>       Iterator it = 
>> units.snapshotIterator();
>>       InvokeStmt initstmt = null;
>>
>>       // need to track all locals containing refs to "this"
>>       LinkedList receivercopies = new LinkedList();
>>
>>       // get the "this", should be first identity statement
>>       Stmt first = (Stmt) it.next();
>>       Local thisloc = null;
>>       if ( (first instanceof IdentityStmt) &&        ((IdentityStmt) 
>> first).getRightOp() instanceof ThisRef
>>      )
>>         { thisloc = (Local)             ((IdentityStmt) 
>> first).getLeftOp();//the local for "this"           // add to list of 
>> locals containing this
>>           receivercopies.add(thisloc);
>>     }
>>     else
>>       throw new InternalCompilerError("Expecting an identity stmt for 
>> this");
>>     
>>       int countinits = 0;
>>       debug("--- Starting to look through statement list ..... ");
>>       while ( it.hasNext() )
>>         { Stmt u = (Stmt) it.next();
>>           debug(" ... Looking at stmt " + u);
>>
>>       // if we find a stmt lhs = rhs, where rhs is already a copy
>>       //     of "this",  add lhs to receivercopies
>>       if ((u instanceof AssignStmt) &&
>>           receivercopies.contains(((AssignStmt) u).getRightOp()))
>>         receivercopies.add(((AssignStmt) u).getLeftOp());
>>
>>           if ((u instanceof InvokeStmt) &&           ((InvokeStmt) 
>> u).getInvokeExpr() instanceof SpecialInvokeExpr &&
>>           ((InvokeStmt) u).getInvokeExpr().getMethodRef().name()
>>           .equals(SootMethod.constructorName) &&
>>           receivercopies.contains
>>           (((SpecialInvokeExpr) ((InvokeStmt) 
>> u).getInvokeExpr()).getBase()))
>>         { debug("Found <init> " + u);
>>           countinits++;
>>           if (countinits == 1) // great, found it
>>             initstmt = (InvokeStmt) u;            else
>>             throw new InternalCompilerError("Expecting only one <init>");
>>              }               } // all units
>>             debug("--- Finished looking through statement list ..... ");
>>        if (countinits == 0)              throw new 
>> InternalCompilerError("Could not find a matching <init>");
>>
>>        return(initstmt);
>>      }
>>
>>    /** Given a Chain for the body of a method,  find the first "real"
>>     *  stmt (i.e. not an identity stmt or the copy of "this" we often 
>> make)     *  and return a reference to it.
>>     */
>>     public static Stmt findFirstRealStmt(SootMethod m,Chain units)
>>     {
>>     return findFirstRealStmt(m,units,false);
>>     }
>>
>>     public static Stmt findFirstRealStmtOrNop(SootMethod m,Chain units)
>>     {
>>     return findFirstRealStmt(m,units,true);
>>     }
>>
>>     private static Stmt findFirstRealStmt(SootMethod m,Chain 
>> units,boolean allowNops)
>>      { Iterator it = units.snapshotIterator();
>>        while ( it.hasNext() ) {          Stmt u = (Stmt) it.next();
>>          if(u instanceof IdentityStmt) continue;
>>          if(u instanceof NopStmt && !allowNops) continue;
>>          // skip over any copy of "this" we made
>>          //if(u instanceof AssignStmt)
>>          //if(thiscopies.containsKey(m))            //  
>> if(((AssignStmt) u).getLeftOp()==thiscopies.get(m))
>>              //continue;
>>          return u;
>>           }
>>         throw new InternalCompilerError("Expecting to find a real stmt");
>>       }
>>     public static Stmt findFirstRealStmtOrNull(SootMethod m,Chain units)
>>     {         Iterator it = units.iterator();
>>       while ( it.hasNext() ) {          Stmt u = (Stmt) it.next();
>>          if(u instanceof IdentityStmt)              continue;
>>          return u;
>>        }
>>        return null;
>>      }
>>    /** update all traps that used to end at oldend to now end at newend
>>     */
>>    public static void resetTrapsEnd(Body b, Stmt oldend, Stmt newend)
>>      { for( Iterator trIt = b.getTraps().iterator(); trIt.hasNext(); ) 
>>          { final Trap tr = (Trap) trIt.next();
>>            if( tr.getEndUnit() == oldend )          
>> tr.setEndUnit(newend);        }
>>       }
>>
>>    /** update all traps that used to start at oldstart to now start at 
>> newstart
>>     */
>>    public static void resetTrapsStart(Body b, Stmt oldstart, Stmt 
>> newstart)
>>      { for( Iterator trIt = b.getTraps().iterator(); trIt.hasNext(); ) 
>>          { final Trap tr = (Trap) trIt.next();
>>            if( tr.getBeginUnit() == oldstart )          
>> tr.setBeginUnit(newstart);        }
>>       }
>>
>>    // This caching is not safe because around lifts shadows out of 
>> their bodies,
>>    // in which case the restructuring should be redone for subsequent 
>> applications.
>>   //private static Map/*<Body,Stmt>*/ returns=new Hashtable();
>>
>>   /** Given a SootMethod, restructure its body so that the body ends
>>    *  with   L1:nop; return;    or   L1:nop; return(<local>);.
>>    *  Rewire all other returns in the body to assign to <local> and
>>    *  goto L1.   Return a reference to the nop at L1.
>>    */
>>   public static Stmt restructureReturn(SootMethod method) {
>>         Body b = method.getActiveBody();
>>         //if (returns.containsKey(b)) {           
>>         //    return ((Stmt) returns.get(b));
>>         //}
>>         LocalGenerator localgen = new LocalGenerator(b);
>>        
>>         Chain units = b.getUnits(); // want a patching chain here, to 
>> make sure
>>         // gotos are rewired to go to the inserted nop
>>         Stmt last = (Stmt) units.getLast();
>>        
>>         Stmt endnop;// = Jimple.v().newNopStmt();
>>         try { // preserve existing endnop
>>             endnop=(NopStmt)units.getPredOf(last);
>>             if (endnop==null)
>>                 throw new RuntimeException();
>>         } catch(Throwable e) {
>>             endnop=Jimple.v().newNopStmt();
>> //             insert the nop just before the return stmt
>>             if (last instanceof ReturnStmt || last instanceof 
>> ReturnVoidStmt) {
>>                 units.insertBefore(endnop, units.getLast());
>>             } else {
>>                 units.insertAfter(endnop, units.getLast());
>>             }
>>             if (!units.contains(endnop))
>>                 throw new InternalCompilerError("");
>>         }
>>         if (!units.contains(endnop))
>>             throw new InternalCompilerError("");
>>        
>>         Local ret = null;
>>         if (last instanceof ReturnStmt) {
>>             ReturnStmt lastRet = (ReturnStmt) last;
>>             Value op = lastRet.getOp();
>>             if (op instanceof Local) {// return(<local>)
>>                 ret = (Local)op;
>>                 Type returnType = method.getReturnType();
>>                 Local tmp = localgen.generateLocal(returnType);
>>                 // Make sure returned local is used in the shadow once
>>                 // by assigning it to a temporary and back.
>>                 // This makes the around weaver's analyses 
>> simpler.           
>>                 units.insertBefore(Jimple.v().newAssignStmt(tmp, op), 
>> endnop);
>>                 units.insertBefore(Jimple.v().newAssignStmt(op, tmp), 
>> endnop);
>>             } else if (op instanceof Constant) // return(<constant>)
>>             { // change to ret := <constant>; return(ret);
>>                 Type returnType = method.getReturnType();
>>                 ret = localgen.generateLocal(returnType);
>>                 if (!units.contains(endnop))
>>                     throw new InternalCompilerError("");
>>                 units.insertBefore(Jimple.v().newAssignStmt(ret, op), 
>> endnop);
>>                 lastRet.setOp(ret);
>>             } else
>>                 throw new InternalCompilerError(
>>                         "Expecting return of <local> or <constant>");
>>         } else if (last instanceof ReturnVoidStmt) { // do nothing
>>         } else {
>>             Type returnType = method.getReturnType();
>>             if (returnType instanceof VoidType) {
>>                 units.insertAfter(Jimple.v().newReturnVoidStmt(), 
>> endnop);
>>             } else {
>>                 ret = localgen.generateLocal(returnType);
>>                 units.insertAfter(Jimple.v().newReturnStmt(ret), endnop);
>>             }
>>         }
>>
>>         // now the last stmt should always be return ret; or return;
>>         if (units.getLast() instanceof ReturnStmt) {
>>             ReturnStmt lastRet = (ReturnStmt) units.getLast();
>>             if (lastRet.getOp() != ret)
>>                 throw new InternalCompilerError(
>>                         "Expecting last stmt to Return ret");
>>         } else if (!(units.getLast() instanceof ReturnVoidStmt)) {
>>             throw new InternalCompilerError(
>>                     "Last stmt should be ReturnStmt or ReturnVoidStmt");
>>         }
>>
>>        
>>        
>>
>>         resetTrapsEnd(b, (Stmt) units.getLast(), endnop);
>>
>>         // Look for returns in the middle of the method
>>         Iterator it = units.snapshotIterator();
>>         while (it.hasNext()) {
>>             Stmt u = (Stmt) it.next();
>>             if (u == units.getLast())
>>                 continue;
>>             if (u instanceof ReturnStmt) {
>>                 ReturnStmt ur = (ReturnStmt) u;
>>                 units.insertBefore(Jimple.v().newAssignStmt(ret, 
>> ur.getOp()),
>>                         ur);
>>             }
>>             if (u instanceof ReturnVoidStmt || u instanceof ReturnStmt) {
>>                 Stmt gotoStmt = Jimple.v().newGotoStmt(endnop);
>>                 units.swapWith(u, gotoStmt);
>>                 for (Iterator trIt = b.getTraps().iterator(); 
>> trIt.hasNext();) {
>>                     final Trap tr = (Trap) trIt.next();
>>                     for (Iterator boxIt = 
>> tr.getUnitBoxes().iterator(); boxIt
>>                             .hasNext();) {
>>                         final UnitBox box = (UnitBox) boxIt.next();
>>                         if (box.getUnit() == u)
>>                             box.setUnit(gotoStmt);
>>                     } // each box in trap
>>                 } // each trap
>>             } // if return stmt
>>         } // each stmt in body
>>         //returns.put(b, endnop);
>>         return (endnop);
>>     }
>>
>>
>>   /**
>>    * inline a call to this() if one exists, return a 
>> ConstructorInliningMap if
>>    * an inlining was done, null otherwise (no this() to inline).
>>    */
>>   public static ConstructorInliningMap inlineThisCall(SootMethod method){
>>         // assure body is a constructor
>>         if (!method.getName().equals("<init>"))
>>        throw new InternalCompilerError          ("trying to inline a 
>> this() in a method that is not an <init>");
>>
>>     // get the body
>>     Body b = method.getActiveBody();
>>
>>     // get the units
>>         Chain containerUnits = b.getUnits();
>>
>>         // if the first invoke is a this() and not a super() inline 
>> the this()
>>         InvokeStmt invokeStmt = findInitStmt(containerUnits);
>>
>>         SpecialInvokeExpr specInvokeExpr =         
>> (SpecialInvokeExpr)invokeStmt.getInvokeExpr();
>>
>>         // if it is a this() call, need to do the inlining
>>         if (specInvokeExpr.getMethodRef().declaringClass().equals(
>>                              b.getMethod().getDeclaringClass())){
>>                         // put locals from inlinee into container
>>             SootMethod inlinee = specInvokeExpr.getMethodRef().resolve();
>>             if (!inlinee.hasActiveBody()){
>>                 inlinee.retrieveActiveBody();
>>             }
>>
>>         Body inlineeBody=inlinee.getActiveBody();
>>
>>             HashMap oldLocalsToNew = new HashMap();
>>                         Iterator localsIt = 
>> inlineeBody.getLocals().iterator();
>>             while (localsIt.hasNext()){
>>                 Local l = (Local)localsIt.next();
>>                 Local newLocal = (Local)l.clone();
>>                 b.getLocals().add(newLocal);
>>                 oldLocalsToNew.put(l, newLocal);
>>             }
>>                        //find identity stmt of original method
>>             IdentityStmt origIdStmt = findIdentityStmt(b);
>>                        HashMap oldStmtsToNew = new HashMap();
>>                         //System.out.println("locals: "+b.getLocals());
>>             Iterator inlineeIt = inlineeBody.getUnits().iterator();
>>             while (inlineeIt.hasNext()){
>>                 Stmt inlineeStmt = (Stmt)inlineeIt.next();
>>                                // handle identity stmts
>>                 if (inlineeStmt instanceof IdentityStmt){
>>                     IdentityStmt idStmt = (IdentityStmt)inlineeStmt;
>>                                         if (idStmt.getRightOp() 
>> instanceof ThisRef) {
>>                         Stmt newThis = 
>> Jimple.v().newAssignStmt((Local)oldLocalsToNew.get(idStmt.getLeftOp()), 
>> origIdStmt.getLeftOp());                                 
>> newThis.addAllTagsOf(idStmt);
>>                         containerUnits.insertBefore(newThis, invokeStmt);
>>                         oldStmtsToNew.put(inlineeStmt, newThis);
>>                     }
>>                                         else if (idStmt.getRightOp() 
>> instanceof CaughtExceptionRef){
>>                         Stmt newInlinee = (Stmt)inlineeStmt.clone();
>>                         Iterator localsToPatch = 
>> newInlinee.getUseAndDefBoxes().iterator();
>>                         while (localsToPatch.hasNext()){
>>                             ValueBox next = 
>> (ValueBox)localsToPatch.next();
>>                             if (next.getValue() instanceof Local){
>>                                 
>> next.setValue((Local)oldLocalsToNew.get(next.getValue()));
>>                             }
>>                         }
>>                                                
>> newInlinee.addAllTagsOf(inlineeStmt);
>>                         containerUnits.insertBefore(newInlinee, 
>> invokeStmt);
>>                         oldStmtsToNew.put(inlineeStmt, newInlinee);
>>                     }
>>                     else if (idStmt.getRightOp() instanceof 
>> ParameterRef) {
>>                         Stmt newParam = 
>> Jimple.v().newAssignStmt((Local)oldLocalsToNew.get(idStmt.getLeftOp()), 
>> specInvokeExpr.getArg(((ParameterRef)idStmt.getRightOp()).getIndex()));         
>>                         newParam.addAllTagsOf(idStmt);
>>                         containerUnits.insertBefore(newParam, 
>> invokeStmt);
>>                         oldStmtsToNew.put(inlineeStmt, newParam);
>>                     }
>>                 }
>>
>>                 // handle return void stmts (cannot return anything 
>> else                 // from a constructor)
>>                 else if (inlineeStmt instanceof ReturnVoidStmt){
>>                     Stmt newRet = 
>> Jimple.v().newGotoStmt((Stmt)containerUnits.getSuccOf(invokeStmt));
>>                     newRet.addAllTagsOf(inlineeStmt);
>>                     containerUnits.insertBefore(newRet, invokeStmt);
>>                     debug("adding to stmt map: "+inlineeStmt+" and 
>> "+newRet);
>>                     oldStmtsToNew.put(inlineeStmt, newRet);
>>                 }
>>
>>                 else {
>>                     Stmt newInlinee = (Stmt)inlineeStmt.clone();
>>                     Iterator localsToPatch = 
>> newInlinee.getUseAndDefBoxes().iterator();
>>                     while (localsToPatch.hasNext()){
>>                         ValueBox next = (ValueBox)localsToPatch.next();
>>                         if (next.getValue() instanceof Local){
>>                             
>> next.setValue((Local)oldLocalsToNew.get(next.getValue()));
>>                         }
>>                     }
>>
>>                     newInlinee.addAllTagsOf(inlineeStmt);   
>>                     containerUnits.insertBefore(newInlinee, invokeStmt);
>>                     oldStmtsToNew.put(inlineeStmt, newInlinee);
>>                 }
>>                             }
>>                             // handleTraps
>>             Iterator trapsIt = inlineeBody.getTraps().iterator();
>>             while (trapsIt.hasNext()){
>>                 Trap t = (Trap)trapsIt.next();
>>                 debug("begin: "+t.getBeginUnit());
>>                 Stmt newBegin = 
>> (Stmt)oldStmtsToNew.get(t.getBeginUnit());
>>                 debug("end: "+t.getEndUnit());
>>                 Stmt newEnd = (Stmt)oldStmtsToNew.get(t.getEndUnit());
>>                 debug("handler: "+t.getHandlerUnit());
>>                 Stmt newHandler = 
>> (Stmt)oldStmtsToNew.get(t.getHandlerUnit());
>>
>>                 if (newBegin == null || newEnd == null || newHandler 
>> == null)
>>                     throw new RuntimeException("couldn't map trap!");
>>
>>                 b.getTraps().add(Jimple.v().newTrap(t.getException(), 
>> newBegin, newEnd, newHandler));
>>             }
>>
>>             // patch gotos
>>             inlineeIt = inlineeBody.getUnits().iterator();
>>             while (inlineeIt.hasNext()){
>>                 Stmt newStmt = (Stmt) 
>> oldStmtsToNew.get(inlineeIt.next());
>>         Iterator unitBoxesIt=newStmt.getUnitBoxes().iterator();
>>         while(unitBoxesIt.hasNext()) {
>>             UnitBox box=(UnitBox) unitBoxesIt.next();
>>             if(oldStmtsToNew.containsKey(box.getUnit()))
>>             box.setUnit((Stmt) oldStmtsToNew.get(box.getUnit()));
>>         }
>>         }
>>                             // remove original invoke
>>             containerUnits.remove(invokeStmt);
>>                            // resolve name collisions
>>             LocalNameStandardizer.v().transform(b, "ji.lns");
>>
>>             ConstructorInliningMap cim = new 
>> ConstructorInliningMap(inlinee, method);
>>             cim.add(oldLocalsToNew);
>>             cim.add(oldStmtsToNew);
>>
>>         // return cim to indicate an inlining happened
>>         return cim;
>>         }
>>     return null; // no inlining
>>     }
>>
>>     private static IdentityStmt findIdentityStmt(Body b){
>>         Iterator it = b.getUnits().iterator();
>>         while (it.hasNext()){
>>             Stmt s = (Stmt)it.next();
>>             if ((s instanceof IdentityStmt) && 
>> (((IdentityStmt)s).getRightOp() instanceof ThisRef)){
>>                 return (IdentityStmt)s;
>>             }
>>         }
>>         return null;
>>     }
>>
>>     //private static Map/*<SootMethod,Local>*/ thiscopies=new 
>> Hashtable();
>>
>>     /** Restructure the method to place a copy of 'this' in a new local
>>      *  variable. Why is this useful? The local bound by the relevant 
>>      *  identity statement will always point to local variable slot 0
>>      *  (ignoring ITD stuff), which will always be 'this' at method entry
>>      *  However, optimised bytecode might reuse slot 0 at a later point,
>>      *  and we want to be sure we really have a handle on the value of
>>      *  'this', not whatever it gets reused for later (which might even
>>      *  be the wrong type).
>>      *      *  UPDATE: Experiments show that the this-local never 
>> changes throughout the method,
>>      *  even if the byte-code assigns to slot 0. In this case, Jimple 
>> creates a new local
>>      *  to assign to.
>>      *  FIXME relational aspects will actually set the this-local to 
>> another value...
>>      *  (Eric)
>>      */
>>     public static Local getThisLocal(SootMethod m) {
>>     //if(thiscopies.containsKey(m)) return ((Local) thiscopies.get(m));
>>     
>>     Body b=m.getActiveBody();
>>     if (MethodCategory.hasThisAsFirstParameter(m)) {
>>         return b.getParameterLocal(0);
>>     } else {
>>         return b.getThisLocal();
>>     }
>>     
>>     /*
>>     
>>     // don't want exceptions "fixed" up
>>     Chain units=b.getUnits().getNonPatchingChain();
>>     for(Stmt stmt=(Stmt) units.getFirst(); ;
>>         stmt=(Stmt) units.getSuccOf(stmt)) {
>>                 if(stmt==null) throw new RuntimeException
>>                    ("internal error: didn't find identitystmt binding 
>> this "
>>                 +"in method "+m);
>>
>>         if(stmt instanceof IdentityStmt) {
>>             IdentityStmt istmt=(IdentityStmt) stmt;
>>            
>>             // for ITDs "this" means the first parameter
>>             if (MethodCategory.hasThisAsFirstParameter(m)) {
>>                 if (istmt.getRightOp() instanceof ParameterRef) {
>>                     ParameterRef parref = (ParameterRef) 
>> istmt.getRightOp();
>>                     if (parref.getIndex()==0) {
>>                        Value tr=istmt.getLeftOp();
>>                        do {                        stmt=(Stmt) 
>> units.getSuccOf(stmt);                        } while(stmt instanceof 
>> IdentityStmt);
>>                        
>> units.insertBefore(Jimple.v().newAssignStmt(l,tr),stmt);
>>                        break;
>>                     }
>>                 }
>>             } else             // the normal non-ITD case
>>             if(istmt.getRightOp() instanceof ThisRef) {
>>                 Value tr=istmt.getLeftOp();
>>                 do {                 stmt=(Stmt) 
>> units.getSuccOf(stmt);                 } while(stmt instanceof 
>> IdentityStmt);
>>                 units.insertBefore(Jimple.v().newAssignStmt(l,tr),stmt);
>>                 break;
>>             }
>>         }
>>     }
>>     thiscopies.put(m,l);
>>     return l;*/
>>     }
>>
>>     private static Map/*<InvokeStmt,AssignStmt>*/ 
>> invokeassignstmts=new Hashtable();
>>         public static AssignStmt getEquivAssignStmt(SootMethod 
>> m,InvokeStmt stmt) {
>>     // We assume that a statement will only ever occur in one method
>>     // If this is not true, then use a separate table to check whether
>>     // the assignstmt has been repatched into a particular method
>>
>>     if(invokeassignstmts.containsKey(stmt))         return 
>> ((AssignStmt) (invokeassignstmts.get(stmt)));
>>
>>     Body b=m.getActiveBody();
>>     Chain units=b.getUnits();
>>     InvokeExpr e=stmt.getInvokeExpr();
>>     Local l=new 
>> LocalGeneratorEx(b).generateLocal(e.getMethodRef().returnType(),"retval"); 
>>
>>     AssignStmt a=Jimple.v().newAssignStmt(l,e);
>>
>>     units.swapWith(stmt,a);
>>     if(stmt.hasTag("SourceLnPosTag")) 
>> a.addTag(stmt.getTag("SourceLnPosTag"));
>>     invokeassignstmts.put(stmt,a);
>>     return a;
>>     }
>>     
>>     /**
>>      * Sanity check for methods.
>>      * Checks for:
>>      *     - @this identity statement as the first statement
>>      *  - parameter identity statements in the right order for all 
>> parameters
>>      * @param method
>>      */
>>     public static void validateMethod(SootMethod method) {
>>         debug("validating " + method.getName());
>>        
>>         if (method.isAbstract())
>>             return;
>>        
>>         Body body=method.getActiveBody();
>>         Chain units=body.getUnits().getNonPatchingChain();
>>         List params=method.getParameterTypes();
>>        
>>         Iterator itUnits=units.iterator();
>>         if (!method.isStatic()) {
>>             Stmt first=(Stmt)itUnits.next();       
>>            
>>             IdentityStmt id=(IdentityStmt) first;
>>             Local local=(Local)id.getLeftOp();
>>             ThisRef ref=(ThisRef)id.getRightOp();
>>             if 
>> (!ref.getType().equals(method.getDeclaringClass().getType()))
>>                 throw new RuntimeException();
>>            
>>             if 
>> (!local.getType().equals(method.getDeclaringClass().getType()))
>>                 throw new RuntimeException();
>>            
>>         }   
>>        
>>         Iterator it=params.iterator();
>>         int i=0;
>>         while (it.hasNext()) {
>>             Type type=(Type)it.next();
>>             Stmt stmt=(Stmt)itUnits.next();
>>             IdentityStmt id=(IdentityStmt)stmt;
>>             Local local=(Local)id.getLeftOp();
>>            
>>             debug("  parameter " + i + ": " + type.toString() + ":" + 
>> local.getName());
>>             debug("   rightOp: " + id.getRightOp());
>>             ParameterRef ref=(ParameterRef)id.getRightOp();
>>        
>>                    
>>            
>>             if 
>> (!Type.toMachineType(local.getType()).equals(Type.toMachineType(type))) {
>>                 debug("type mismatch: local: " + local.getType() + " 
>> param: " + type);
>>                 throw new RuntimeException();
>>             }
>>             if (ref.getIndex()!=i++) {
>>                 throw new RuntimeException();
>>             }
>>             if (!ref.getType().equals(type)) {
>>                 throw new RuntimeException();
>>             }               
>>         }
>>        
>>     }
>>
>>     /**
>>      * This class helps implement boxing.
>>      * It assigns integer IDs to the simple Java types and
>>      * one ID to all the reference types.
>>      *      * It contains methods to retrieve the boxing classes of 
>> simple types
>>      * and their value methods (intVal() etc.)      *      * @author 
>> Sascha Kuzins      */
>>     public static class JavaTypeInfo {
>>         public final static int booleanType=0;
>>         public final static int byteType=1;
>>         public final static int shortType=2;
>>         public final static int charType=3;
>>         public final static int intType=4;
>>         public final static int longType=5;
>>         public final static int floatType=6;
>>         public final static int doubleType=7;
>>         public final static int refType=8;
>>         public final static int typeCount=9;
>>        
>>         /*
>>          * This table is from Java in a Nutshell 3rd edition, page 28
>>          * X - same type
>>          * N - forbidden conversion
>>          * Y - widening conversion
>>          * C - narrowing conversion
>>          */
>>         private final static char [][] simple_conversions =
>>             {                 { 'X', 'N', 'N', 'N', 'N', 'N', 'N', 'N'},
>>                 { 'N', 'X', 'Y', 'C', 'Y', 'Y', 'Y', 'Y'},
>>                 { 'N', 'C', 'X', 'C', 'Y', 'Y', 'Y', 'Y'},
>>                 { 'N', 'C', 'C', 'X', 'Y', 'Y', 'Y', 'Y'},
>>                 { 'N', 'C', 'C', 'C', 'X', 'Y', 'Y', 'Y'},
>>                 { 'N', 'C', 'C', 'C', 'C', 'X', 'Y', 'Y'},
>>                 { 'N', 'C', 'C', 'C', 'C', 'C', 'X', 'Y'},
>>                 { 'N', 'C', 'C', 'C', 'C', 'C', 'C', 'X'}
>>             };
>>         public static char getSimpleTypeConversionInfo(Type from, Type 
>> to) {
>>             int f=sootTypeToInt(from);
>>             if (!isSimpleType(f))
>>                 throw new RuntimeException();
>>             int t=sootTypeToInt(to);
>>             if (!isSimpleType(t))
>>                 throw new RuntimeException();
>>            
>>             //if (simple_conversions[longType][intType]!='C')
>>             //    throw new RuntimeException();
>>            
>>             return simple_conversions[f][t];
>>         }
>>        
>>         public static boolean isSimpleType(Type t) {
>>             return isSimpleType(sootTypeToInt(t));
>>         }
>>        
>>         public static boolean isSimpleType(int type) {
>>             return type!=refType;
>>         }
>>         public static boolean isSimpleWideningConversion(Type from, 
>> Type to) {
>>             char c=getSimpleTypeConversionInfo(from, to);
>>             return c=='Y' || c=='X';         }
>>         // returns if the classes contain a method with the same name 
>> and signature         // but different return type
>>         public static boolean haveCollidingMethod(SootClass cl, 
>> SootClass cl2) {
>>             for( Iterator mIt = cl.getMethods().iterator(); 
>> mIt.hasNext(); ) {
>>                 final SootMethod m = (SootMethod) mIt.next();
>>                 try {
>>                    
>>                     SootMethod m2=cl2.getMethod(m.getName(), 
>> m.getParameterTypes());
>>                     if (!m2.getReturnType().equals(m.getReturnType()))
>>                         return true;
>>                    
>>                 } catch (RuntimeException e) {
>>                     if (e.getMessage().matches("ambiguous method"))
>>                         throw new RuntimeException("Internal error, 
>> unexpected exception.");
>>                 }
>>             }
>>             return false;
>>         }
>>        
>>         public static boolean implementsInterfaceRecursive(SootClass 
>> cl, String interfaceName)  {
>>             if (cl.implementsInterface(interfaceName))
>>                 return true;
>>             else {
>>                 if (cl.hasSuperclass())
>>                     return 
>> implementsInterfaceRecursive(cl.getSuperclass(), interfaceName);
>>                 else
>>                     return false;
>>             }
>>         }
>>         /*
>>          * The aim is to return true for cases which javac would 
>>          * identify as an invalid cast at compile time.
>>          * (For example boolean to int, or unrelated RefTypes).
>>          * Based on 5.1.7 of the Java Language Spec, second edition, 
>> page 64.
>>          * Also see 5.5, Casting Conversion.          * The #numbers 
>> in the code indicate the bullet point to which the test          * 
>> refers.
>>          */
>>         public static boolean isForbiddenConversion(Type from, Type to) {
>>             // AnySubType is only used for points-to analysis
>>             if (from instanceof AnySubType) throw new RuntimeException();
>>             if (to instanceof AnySubType) throw new RuntimeException();
>>            
>>             // #4
>>             if (to instanceof NullType && !(from instanceof NullType ))
>>                 return true;           
>>            
>>             if (to.equals(from))
>>                 return false;
>>            
>>             if (from instanceof NullType && to instanceof RefLikeType)
>>                 return false;   
>>            
>>             // #3
>>             if (from instanceof NullType && isSimpleType(to))
>>                 return true;
>>            
>>             if (isSimpleType(from) && isSimpleType(to))
>>                 return isForbiddenSimpleConversion(from, to); // #5,6
>>            
>>            
>>             // At this stage, they are not both simple types.           
>>             // #1, #2
>>             if (isSimpleType(from) || isSimpleType(to))
>>                 return true;
>>            
>>             if (!(from instanceof RefType && to instanceof RefType)) {
>>                 // not both are reftypes
>>                
>>                 // #12,13
>>                 if (from instanceof ArrayType && to instanceof RefType &&
>>                     ! (        
>> to.equals(RefType.v("java.lang.Object")) || 
>>                             
>> to.equals(RefType.v("java.io.Serializable")) ||
>>                             
>> to.equals(RefType.v("java.lang.Cloneable")) ))                     
>> return true; // cast from array to non-object reftype
>>                
>>                 // #9
>>                 if (to instanceof ArrayType && from instanceof RefType &&
>>                         !from.equals(RefType.v("java.lang.Object"))) 
>>                     return true; // cast from non-object reftype to array
>>                
>>                
>>                 // #14
>>                 if (to instanceof ArrayType && from instanceof 
>> ArrayType) {
>>                      ArrayType ato=(ArrayType)to;
>>                      ArrayType afrom=(ArrayType)from;
>>                      return                         
>> isForbiddenConversion(afrom.baseType, 
>> ato.baseType);                                          }               
>>                
>>                 return false;
>>             }
>>            
>>             RefType rFrom=(RefType)from;
>>             RefType rTo=(RefType)to;
>>            
>>             // #11
>>             if (rFrom.getSootClass().isInterface() && 
>> rTo.getSootClass().isInterface()) {
>>                 if (haveCollidingMethod(rFrom.getSootClass(), 
>> rTo.getSootClass()))
>>                     return true;
>>                 else
>>                     return false;
>>             }
>>             // #8
>>             if (rTo.getSootClass().isInterface())  {
>>                 if 
>> (Modifier.isFinal(rFrom.getSootClass().getModifiers()) &&
>>                     implementsInterfaceRecursive(rFrom.getSootClass(), 
>> rTo.getSootClass().getName()))
>>                     return true;
>>                 else
>>                     return false; // from could implement this interface
>>             }
>>             // #10
>>             if (rFrom.getSootClass().isInterface()) {                  
>> if (Modifier.isFinal(rTo.getSootClass().getModifiers()) &&
>>                         
>> implementsInterfaceRecursive(rTo.getSootClass(), 
>> rFrom.getSootClass().getName()))
>>                     return true;
>>                 else                        // from can implement 
>> other interfaces and
>>                     return false;            // a non-interface type, 
>> so cast could be possible
>>             }
>>            
>>            
>>            
>>             FastHierarchy hier=Scene.v().getOrMakeFastHierarchy();
>>             // #7
>>             if (hier.isSubclass(rFrom.getSootClass(), 
>> rTo.getSootClass()) ||
>>                 hier.isSubclass(rTo.getSootClass(), 
>> rFrom.getSootClass()))                 return false;
>>             else
>>                 return true;
>>         }
>>         public static boolean isForbiddenSimpleConversion(Type from, 
>> Type to) {
>>             char c=getSimpleTypeConversionInfo(from, to);
>>             return c=='N';
>>         }
>>        
>>         public static int sootTypeToInt(Type type) {
>>             if (type.equals(IntType.v()))
>>                 return intType;
>>             else if (type.equals(BooleanType.v()))                 
>> return booleanType;
>>             else if (type.equals(ByteType.v()))                 return 
>> byteType;
>>             else if (type.equals(ShortType.v())) 
>>                             return shortType;
>>             else if (type.equals(CharType.v())) 
>>                             return charType;
>>             else if (type.equals(LongType.v())) 
>>                             return longType;
>>             else if (type.equals(FloatType.v())) 
>>                             return floatType;
>>             else if (type.equals(DoubleType.v())) 
>>                             return doubleType;
>>             else                 return refType;
>>         }
>>         public static Value getDefaultValue(Type type) {
>>             if (type.equals(IntType.v()))
>>                 return IntConstant.v(0);
>>             else if (type.equals(BooleanType.v()))                 
>> return IntConstant.v(0);             else if 
>> (type.equals(ByteType.v()))                 return IntConstant.v(0); ///
>>             else if (type.equals(ShortType.v()))                 
>> return IntConstant.v(0); ///
>>             else if (type.equals(CharType.v()))                 return 
>> IntConstant.v(0); ///
>>             else if (type.equals(LongType.v()))                 return 
>> LongConstant.v(0);
>>             else if (type.equals(FloatType.v()))                 
>> return FloatConstant.v(0.0f);
>>             else if (type.equals(DoubleType.v()))                 
>> return DoubleConstant.v(0.0);
>>             else                 return NullConstant.v();
>>         }
>>         public static SootClass getBoxingClass(Type type) {
>>             if (type.equals(IntType.v()))
>>                 return Scene.v().getSootClass("java.lang.Integer");
>>             else if (type.equals(BooleanType.v()))                 
>> return Scene.v().getSootClass("java.lang.Boolean");
>>             else if (type.equals(ByteType.v()))                 return 
>> Scene.v().getSootClass("java.lang.Byte");
>>             else if (type.equals(ShortType.v()))                 
>> return Scene.v().getSootClass("java.lang.Short");
>>             else if (type.equals(CharType.v()))                 return 
>> Scene.v().getSootClass("java.lang.Character");
>>             else if (type.equals(LongType.v()))                 return 
>> Scene.v().getSootClass("java.lang.Long");
>>             else if (type.equals(FloatType.v()))                 
>> return Scene.v().getSootClass("java.lang.Float");
>>             else if (type.equals(DoubleType.v()))                 
>> return Scene.v().getSootClass("java.lang.Double");
>>             else                 throw new RuntimeException();
>>         }
>>
>>         public static String getBoxingClassMethodName(Type type) {
>>             return getSimpleTypeBoxingClassMethodName(
>>                     
>> getBoxingClassPrimType(((RefType)type).getSootClass()));
>>         }
>>         public static String getSimpleTypeBoxingClassMethodName(Type 
>> type) {   
>>             if (type.equals(IntType.v()))
>>                 return "intValue";
>>             else if (type.equals(BooleanType.v()))                 
>> return "booleanValue";
>>             else if (type.equals(ByteType.v()))                 return 
>> "byteValue";
>>             else if (type.equals(ShortType.v()))                 
>> return "shortValue";
>>             else if (type.equals(CharType.v()))                 return 
>> "charValue";
>>             else if (type.equals(LongType.v()))                 return 
>> "longValue";
>>             else if (type.equals(FloatType.v()))                 
>> return "floatValue";
>>             else if (type.equals(DoubleType.v()))                 
>> return "doubleValue";
>>             else                 throw new RuntimeException("no method 
>> for type " + type);
>>         }
>>        
>>         /** Given the boxing class, what was the primitive type?
>>          *          * @param boxingClass the boxing class (eg Integer)
>>          * @return the primitive type (eg int)
>>          */
>>         public static Type getBoxingClassPrimType(SootClass 
>> boxingClass) {
>>             if (boxingClass.equals(getBoxingClass(IntType.v())))
>>                 return IntType.v();
>>             else if 
>> (boxingClass.equals(getBoxingClass(BooleanType.v())))                 
>> return BooleanType.v();
>>             else if (boxingClass.equals(getBoxingClass(ByteType.v()))) 
>>                 return ByteType.v();
>>             else if 
>> (boxingClass.equals(getBoxingClass(ShortType.v())))                 
>> return ShortType.v();
>>             else if (boxingClass.equals(getBoxingClass(CharType.v()))) 
>>                 return CharType.v();
>>             else if (boxingClass.equals(getBoxingClass(LongType.v()))) 
>>                 return LongType.v();
>>             else if (boxingClass.equals(getBoxingClass(FloatType.v())))
>>                 return FloatType.v();
>>             else if 
>> (boxingClass.equals(getBoxingClass(DoubleType.v())))                 
>> return DoubleType.v();
>>             else                 throw new RuntimeException();
>>         }
>>         public static boolean isBoxingType(Type type) {
>>             if (type instanceof RefType) {
>>                 RefType rt=(RefType)type;
>>                 try {
>>                     getBoxingClassPrimType(rt.getSootClass());
>>                     return true;
>>                 } catch(RuntimeException e) {
>>                     return false;
>>                 }
>>             } else
>>                 return false;
>>         }
>>     }
>>     /**
>>      * Converts the assignment statement into a sequence      * of 
>> statements performing a typecast.
>>      * Boxes/unboxes if the assignment is from/to an Object to/from a 
>> simple type.      * @param body
>>      * @param stmt
>>      */
>>     public static boolean insertBoxingCast(Body body, AssignStmt stmt, 
>> boolean allowBoxing) {
>>         boolean bDidUnBox=false;
>>         ValueBox source=stmt.getRightOpBox();
>>         Value targetVal=stmt.getLeftOp();
>>         Type targetType=stmt.getLeftOp().getType();
>>         Chain units=body.getUnits().getNonPatchingChain();
>>         Type sourceType=source.getValue().getType();
>>         if (!sourceType.equals(targetType) &&               
>> !(sourceType instanceof RefType &&
>>                 targetType instanceof RefType &&
>>                 isBaseClass(((RefType)targetType).getSootClass(), 
>>                             ((RefType)sourceType).getSootClass()))) {
>>                
>>            
>>            
>>             LocalGeneratorEx localgen=new LocalGeneratorEx(body);
>>             Local castLocal=localgen.generateLocal(sourceType, 
>> "castTmp");
>>             debug("cast: source has type " + sourceType.toString());
>>             debug("cast: target has type " + targetType.toString());
>>             stmt.setLeftOp(castLocal);
>>            
>>             AssignStmt tmpStmt=Jimple.v().newAssignStmt(targetVal, 
>> targetVal /*dummy*/);
>>             units.insertAfter(tmpStmt, stmt);
>>                        
>>             Value castedExpr;
>>             //debug("boxing: source " + sourceType + " target " + 
>> targetType);
>>             // boxing
>>             if (allowBoxing && 
>> JavaTypeInfo.sootTypeToInt(sourceType)!=JavaTypeInfo.refType &&
>>                 
>> targetType.equals(Scene.v().getSootClass("java.lang.Object").getType())) 
>> {
>>                 SootClass 
>> boxClass=JavaTypeInfo.getBoxingClass(sourceType);   
>>                  Local box=localgen.generateLocal(boxClass.getType(), 
>> "box");
>>                  Stmt newAssignStmt = Jimple.v().newAssignStmt( box, 
>> Jimple.v().newNewExpr( boxClass.getType() ) );
>>                  List initParams=new LinkedList();
>>                  initParams.add(sourceType);
>>                  Stmt initBox=Jimple.v().newInvokeStmt( 
>>                      Jimple.v().newSpecialInvokeExpr( box, 
>> Scene.v().makeConstructorRef(boxClass,initParams), 
>>                              castLocal)) ;
>>                 units.insertBefore(newAssignStmt, tmpStmt);
>>                 units.insertBefore(initBox, tmpStmt);
>>                 castedExpr=box;
>>                 bDidUnBox=true;
>>             } else if /*unboxing*/
>>                 (allowBoxing && 
>> JavaTypeInfo.sootTypeToInt(targetType)!=JavaTypeInfo.refType &&
>>                     
>> sourceType.equals(Scene.v().getSootClass("java.lang.Object").getType())    
>> ){                 SootClass 
>> boxClass=JavaTypeInfo.getBoxingClass(targetType);   
>>                 Local box=localgen.generateLocal(boxClass.getType(), 
>> "box");
>>                 Stmt newAssignStmt=Jimple.v().newAssignStmt(box, 
>>                     Jimple.v().newCastExpr(castLocal, 
>> boxClass.getType()));
>>                 SootMethodRef method=Scene.v().makeMethodRef
>>                     (boxClass,
>>                      
>> JavaTypeInfo.getSimpleTypeBoxingClassMethodName(targetType),
>>                      new ArrayList(),
>>                      targetType,
>>                      false);
>>                 castedExpr=Jimple.v().newVirtualInvokeExpr(box, 
>>                          method);       
>>                 units.insertBefore(newAssignStmt, tmpStmt);   
>>                 bDidUnBox=true;
>>             } else { // normal cast
>>                 CastExpr 
>> castExpr=Jimple.v().newCastExpr(castLocal,targetType);
>>                 castedExpr=castExpr;   
>>             }
>>            
>>             tmpStmt.setRightOp(castedExpr);
>>         //    Jimple.v().newCastExpr()
>>             /*
>>             if (stmt instanceof AssignStmt) {
>>                 source.setValue(castedExpr);
>>             } else {
>>                 Local tmpLocal=localgen.generateLocal(targetType, 
>> "castTarget");
>>                 AssignStmt tmpStmt2=Jimple.v().newAssignStmt(tmpLocal, 
>> castedExpr);
>>                 units.insertBefore(tmpStmt2, stmt);
>>                 source.setValue(tmpLocal);
>>             }*/
>>         }        
>>         return bDidUnBox;
>>     }
>>     /**
>>      * Retrieves the identity statement of the argument at position arg
>>      * @param method
>>      * @param arg
>>      * @return
>>      */
>>     public static IdentityStmt 
>> getParameterIdentityStatement(SootMethod method, int arg) {
>>         if (arg>=method.getParameterCount())
>>             throw new RuntimeException();
>>         Chain 
>> units=method.getActiveBody().getUnits().getNonPatchingChain();
>>         Iterator it=units.iterator();
>>         while (it.hasNext()) {
>>             Stmt stmt=(Stmt)it.next();
>>             if (stmt instanceof IdentityStmt) {
>>                 IdentityStmt ids=(IdentityStmt)stmt;
>>                 if (ids.getRightOp() instanceof ParameterRef) {
>>                     ParameterRef paramRef=(ParameterRef)ids.getRightOp();
>>                     if (paramRef.getIndex()==arg)
>>                         return ids;
>>                    
>>                 } else if (ids.getRightOp() instanceof ThisRef) {
>>                    
>>                 } else                     throw new RuntimeException();
>>             } else
>>                 throw new RuntimeException();
>>         }
>>         throw new RuntimeException();
>>     }
>>     /**
>>      * Adds a new parameter to a method and creates the matching 
>> identity statement.
>>      * Returns the local of the newly created parameter.
>>      * @param method
>>      * @param type
>>      * @param suggestedName
>>      * @return
>>      */
>>     public static Local addParameterToMethod(SootMethod method, Type 
>> type, String suggestedName) {
>>         //validateMethod(method);
>>         Body body=method.getActiveBody();
>>         Chain units=body.getUnits().getNonPatchingChain();
>>         List params=new LinkedList(method.getParameterTypes());
>>        
>>         IdentityStmt lastIDStmt=null;
>>         if (params.isEmpty()) {
>>             if (units.isEmpty()) {
>>                 if (!method.isStatic())
>>                     throw new RuntimeException();
>>             } else {
>>                 lastIDStmt=(IdentityStmt)units.getFirst();
>>                 if (! (lastIDStmt.getRightOp() instanceof ThisRef))
>>                     if (!method.isStatic())
>>                         throw new RuntimeException();
>>             }
>>         } else {
>>         //    debug("param id: " + (params.size()-1));
>>             
>> lastIDStmt=Restructure.getParameterIdentityStatement(method, 
>> params.size()-1);
>>         }
>>         params.add(type);
>>         method.setParameterTypes(params);
>>         LocalGeneratorEx lg=new LocalGeneratorEx(body);
>>         Local l=lg.generateLocal(type, suggestedName);
>>         IdentityStmt newIDStmt=Jimple.v().newIdentityStmt(l, 
>>             Jimple.v().newParameterRef(type, params.size()-1));
>>         if (lastIDStmt==null)
>>             units.addFirst(newIDStmt);
>>         else
>>             units.insertAfter(newIDStmt, lastIDStmt);
>>         return l;       
>>     }
>>
>>     public static boolean isBaseClass(SootClass baseClass, SootClass 
>> subClass) {
>>         SootClass sub = subClass;
>>     
>>         while (sub.hasSuperclass()) {
>>             SootClass superClass = sub.getSuperclass();
>>             if (superClass.equals(baseClass))
>>                 return true;
>>     
>>             sub = superClass;
>>         }
>>         return false;
>>     }   
>>     
>>
>> } // class Restructure
>>
>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> Soot-list mailing list
>> Soot-list at sable.mcgill.ca
>> http://mailman.cs.mcgill.ca/mailman/listinfo/soot-list
> 


More information about the Soot-list mailing list