Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

Transformations.java

00001 package ca.mcgill.sable.soot.jimple;
00002 
00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00004  * Jimple, a 3-address code Java(TM) bytecode representation.        *
00005  * Copyright (C) 1997, 1998 Raja Vallee-Rai (kor@sable.mcgill.ca)    *
00006  * All rights reserved.                                              *
00007  *                                                                   *
00008  * Modifications by Etienne Gagnon (gagnon@sable.mcgill.ca) are      *
00009  * Copyright (C) 1998 Etienne Gagnon (gagnon@sable.mcgill.ca).  All  *
00010  * rights reserved.                                                  *
00011  *                                                                   *
00012  * Modifications by Patrick Lam (plam@sable.mcgill.ca) are           *
00013  * Copyright (C) 1999 Patrick Lam.  All rights reserved.             *
00014  *                                                                   *
00015  * This work was done as a project of the Sable Research Group,      *
00016  * School of Computer Science, McGill University, Canada             *
00017  * (http://www.sable.mcgill.ca/).  It is understood that any         *
00018  * modification not identified as such is not covered by the         *
00019  * preceding statement.                                              *
00020  *                                                                   *
00021  * This work is free software; you can redistribute it and/or        *
00022  * modify it under the terms of the GNU Library General Public       *
00023  * License as published by the Free Software Foundation; either      *
00024  * version 2 of the License, or (at your option) any later version.  *
00025  *                                                                   *
00026  * This work is distributed in the hope that it will be useful,      *
00027  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00028  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
00029  * Library General Public License for more details.                  *
00030  *                                                                   *
00031  * You should have received a copy of the GNU Library General Public *
00032  * License along with this library; if not, write to the             *
00033  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,      *
00034  * Boston, MA  02111-1307, USA.                                      *
00035  *                                                                   *
00036  * Java is a trademark of Sun Microsystems, Inc.                     *
00037  *                                                                   *
00038  * To submit a bug report, send a comment, or get the latest news on *
00039  * this project and other Sable Research Group projects, please      *
00040  * visit the web site: http://www.sable.mcgill.ca/                   *
00041  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00042 
00043 /*
00044  Reference Version
00045  -----------------
00046  This is the latest official version on which this file is based.
00047  The reference version is: $SootVersion: 1.beta.4 $
00048 
00049  Change History
00050  --------------
00051  A) Notes:
00052 
00053  Please use the following template.  Most recent changes should
00054  appear at the top of the list.
00055 
00056  - Modified on [date (March 1, 1900)] by [name]. [(*) if appropriate]
00057    [description of modification].
00058 
00059  Any Modification flagged with "(*)" was done as a project of the
00060  Sable Research Group, School of Computer Science,
00061  McGill University, Canada (http://www.sable.mcgill.ca/).
00062 
00063  You should add your copyright, using the following template, at
00064  the top of this file, along with other copyrights.
00065 
00066  *                                                                   *
00067  * Modifications by [name] are                                       *
00068  * Copyright (C) [year(s)] [your name (or company)].  All rights     *
00069  * reserved.                                                         *
00070  *                                                                   *
00071 
00072  B) Changes:
00073 
00074  - Modified on March 17, 1999 by Raja Vallee-Rai (rvalleerai@sable.mcgill.ca) (*)
00075    Corrected some aggregation bugs.
00076    Moved the local splitting code into its own file.
00077    Eliminated the multi-pass dead code elimination.  Calls a
00078    cascaded dead code eliminator.
00079 
00080  - Modified on March 5, 1999 by Raja Vallee-Rai (rvalleerai@sable.mcgill.ca) (*)
00081    Changed aggregate to be iterative.  No longer returns a value.
00082    
00083  - Modified on March 3, 1999 by Raja Vallee-Rai (rvalleerai@sable.mcgill.ca) (*)
00084    Fixed a bug with dead-code elimination concerning field/array references.  
00085    (they can throw null-pointer exceptions so they should not be eliminated) 
00086    Dead-code elimination is now done iteratively until nothing changes. (not sure why
00087    it wasn't done before) 
00088    
00089  - Modified on March 3, 1999 by Raja Vallee-Rai (rvalleerai@sable.mcgill.ca) (*)
00090    Improved the aggregator to move field accesses past some types of writes.
00091       
00092  - Modified on February 3, 1999 by Patrick Lam (plam@sable.mcgill.ca) (*)
00093    Added changes in support of the Grimp intermediate
00094    representation (with aggregated-expressions).
00095 
00096  - Modified on January 25, 1999 by Raja Vallee-Rai (rvalleerai@sable.mcgill.ca). (*)
00097    Made transformations class public.
00098     
00099  - Modified on January 20, 1999 by Raja Vallee-Rai (rvalleerai@sable.mcgill.ca). (*)
00100    Moved packLocals method to ChaitinAllocator.java
00101     
00102  - Modified on November 2, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca) (*)
00103    Repackaged all source files and performed extensive modifications.
00104    First initial release of Soot.
00105 
00106  - Modified on July 29,1998 by Etienne Gagnon (gagnon@sable.mcgill.ca). (*)
00107    Changed assignTypesToLocals. It now uses Etienne's type inference
00108    algorithm.
00109    Changed renameLocals. Gives a different name to address and error
00110    variables.
00111 
00112  - Modified on 23-Jun-1998 by Raja Vallee-Rai (kor@sable.mcgill.ca). (*)
00113    Changed Hashtable to HashMap.
00114 
00115  - Modified on 15-Jun-1998 by Raja Vallee-Rai (kor@sable.mcgill.ca). (*)
00116    First internal release (Version 0.1).
00117 */
00118 
00119 import ca.mcgill.sable.soot.*;
00120 import ca.mcgill.sable.util.*;
00121 
00122 public class Transformations
00123 {
00124   public static int nodeCount = 0;
00125   public static int aggrCount = 0;
00126 
00127 
00128 
00129   /** Traverse the statements in the given body, looking for
00130    *  aggregation possibilities; that is, given a def d and a use u,
00131    *  d has no other uses, u has no other defs, collapse d and u. */
00132    
00133     public static void aggregate(StmtBody body)
00134     {
00135         int aggregateCount = 1;
00136 
00137         if(Main.isProfilingOptimization)
00138             Main.aggregationTimer.start();
00139          boolean changed = false;
00140              
00141         do {
00142             if(Main.isVerbose)
00143                 System.out.println("[" + body.getMethod().getName() + "] Aggregating iteration " + aggregateCount + "...");
00144         
00145             changed = internalAggregate(body);
00146             
00147             aggregateCount++;
00148         } while(changed);
00149         
00150         if(Main.isProfilingOptimization)
00151             Main.aggregationTimer.end();
00152             
00153     }
00154     public static void assignTypesToLocals(JimpleBody listBody)
00155     {
00156         if(Main.isVerbose)
00157             System.out.println("[" + listBody.getMethod().getName() + "] Assigning types to locals...");
00158 
00159         //Jimple.printStmtListBody(listBody, System.out, false);
00160 
00161         if(!Main.oldTyping)
00162         {
00163             TypeResolver.assignTypesToLocals(listBody);
00164             return;
00165         }
00166 
00167         StmtList stmtList = listBody.getStmtList();
00168 
00169         // Set all local types to unknown.
00170         {
00171             Iterator localIt = listBody.getLocals().iterator();
00172 
00173             while(localIt.hasNext())
00174                 ((Local) localIt.next()).setType(UnknownType.v());
00175         }
00176 
00177         // Perform iterations on code, changing the types of the locals.
00178         {
00179             boolean hasChanged = true;
00180             SootClassManager cm = listBody.getMethod().getDeclaringClass().getManager();
00181 
00182             while(hasChanged)
00183             {
00184                 hasChanged = false;
00185 
00186                 Iterator stmtIt = stmtList.iterator();
00187 
00188                 while(stmtIt.hasNext())
00189                 {
00190                     Stmt s = (Stmt) stmtIt.next();
00191 
00192                     if(s instanceof DefinitionStmt)
00193                     {
00194                         DefinitionStmt def = (DefinitionStmt) s;
00195 
00196                         if(def.getLeftOp() instanceof Local)
00197                         {
00198                             Local local = (Local) def.getLeftOp();
00199                             Type previousType = local.getType();
00200 
00201                             Type newType = (Type.toMachineType(def.getRightOp().getType()))
00202                                 .merge(previousType, cm);
00203 
00204                             if(!previousType.equals(newType))
00205                                  hasChanged = true;
00206 
00207                             local.setType(newType);
00208                         }
00209                     }
00210                 }
00211             }
00212         }
00213 
00214         // Set all unknown locals to java.lang.Object
00215         {
00216             Iterator localIt = listBody.getLocals().iterator();
00217 
00218             while(localIt.hasNext())
00219             {
00220                 Local local = (Local) localIt.next();
00221 
00222                 if(local.getType().equals(UnknownType.v()))
00223                     local.setType(RefType.v("java.lang.Object"));
00224             }
00225         }
00226     }
00227     /**
00228         Cleans up the code of the method by performing copy/constant propagation and dead code elimination.
00229         
00230         Right now it must only be called on JimpleBody's (as opposed to GrimpBody's) because 
00231         it checks for the different forms on the rhs such as fieldref, etc to determine if a statement
00232         has a side effect.  (FieldRef can throw a null pointer exception)
00233         
00234         A better way to handle this would be to have a method which returns whether the statement
00235         has a side effect.
00236      */
00237      
00238     public static void cleanupCode(JimpleBody stmtBody)
00239     {
00240         ConstantAndCopyPropagator.propagateConstantsAndCopies(stmtBody);
00241         DeadCodeEliminator.eliminateDeadCode(stmtBody);
00242         
00243         //stmtBody.printDebugTo(new java.io.PrintWriter(System.out, true));
00244     }
00245   private static boolean internalAggregate(StmtBody body)
00246     {
00247       Iterator stmtIt;
00248       LocalUses localUses;
00249       LocalDefs localDefs;
00250       CompleteStmtGraph graph;
00251       boolean hadAggregation = false;
00252       StmtList stmtList = body.getStmtList();
00253       
00254 
00255       graph = new CompleteStmtGraph(stmtList);
00256       localDefs = new SimpleLocalDefs(graph);
00257       localUses = new SimpleLocalUses(graph, localDefs);
00258           
00259       stmtIt = stmtList.iterator();
00260       
00261       while (stmtIt.hasNext())
00262         {
00263           Stmt s = (Stmt)(stmtIt.next());
00264               
00265           /* could this be definitionStmt instead? */
00266           if (!(s instanceof AssignStmt))
00267             continue;
00268           
00269           Value lhs = ((AssignStmt)s).getLeftOp();
00270           if (!(lhs instanceof Local))
00271             continue;
00272           
00273           List lu = localUses.getUsesOf((AssignStmt)s);
00274           if (lu.size() != 1)
00275             continue;
00276             
00277           StmtValueBoxPair usepair = (StmtValueBoxPair)lu.get(0);
00278           Stmt use = usepair.stmt;
00279           ValueBox useBox = usepair.valueBox;
00280               
00281           List ld = localDefs.getDefsOfAt((Local)lhs, use);
00282           if (ld.size() != 1)
00283             continue;
00284    
00285           /* we need to check the path between def and use */
00286           /* to see if there are any intervening re-defs of RHS */
00287           /* in fact, we should check that this path is unique. */
00288           /* if the RHS uses only locals, then we know what
00289              to do; if RHS has a method invocation f(a, b,
00290              c) or field access, we must ban field writes, other method
00291              calls and (as usual) writes to a, b, c. */
00292           
00293           boolean cantAggr = false;
00294           boolean propagatingInvokeExpr = false;
00295           boolean propagatingFieldRef = false;
00296           FieldRef fieldRef = null;
00297       
00298           Value rhs = ((AssignStmt)s).getRightOp();
00299           LinkedList localsUsed = new LinkedList();
00300           for (Iterator useIt = (s.getUseBoxes()).iterator();
00301                useIt.hasNext(); )
00302             {
00303               Value v = ((ValueBox)(useIt.next())).getValue();
00304               if (v instanceof Local)
00305                 localsUsed.add(v);
00306                 if (v instanceof InvokeExpr)
00307                 propagatingInvokeExpr = true;
00308             else if(v instanceof FieldRef)
00309             {
00310                 propagatingFieldRef = true;
00311                 fieldRef = (FieldRef) v;
00312             }
00313             }
00314           
00315           // look for a path from s to use in graph.
00316           // only look in an extended basic block, though.
00317 
00318           List path = graph.getExtendedBasicBlockPathBetween(s, use);
00319       
00320           if (path == null)
00321             continue;
00322 
00323           Iterator pathIt = path.iterator();
00324 
00325           // skip s.
00326           if (pathIt.hasNext())
00327             pathIt.next();
00328 
00329           while (pathIt.hasNext() && !cantAggr)
00330           {
00331               Stmt between = (Stmt)(pathIt.next());
00332           
00333               if(between != use)    
00334               {
00335                 // Check for killing definitions
00336                 
00337                 for (Iterator it = between.getDefBoxes().iterator();
00338                        it.hasNext(); )
00339                   {
00340                       Value v = ((ValueBox)(it.next())).getValue();
00341                       if (localsUsed.contains(v))
00342                       { 
00343                             cantAggr = true; 
00344                             break; 
00345                       }
00346                       
00347                       if (propagatingInvokeExpr || propagatingFieldRef)
00348                       {
00349                           if (v instanceof FieldRef)
00350                           {
00351                               if(propagatingInvokeExpr)
00352                               {
00353                                   cantAggr = true; 
00354                                   break;
00355                               }
00356                               else {
00357                                   // Can't aggregate a field access if passing a definition of a field 
00358                                   // with the same name, because they might be aliased
00359                             
00360                                   if(((FieldRef) v).getField() == fieldRef.getField())
00361                                   {
00362                                       cantAggr = true;
00363                                       break;
00364                                   } 
00365                               } 
00366                            }
00367                       }
00368                   }
00369               }  
00370               
00371               // Check for intervening side effects
00372                 if(propagatingInvokeExpr || propagatingFieldRef)
00373                     {
00374                       for (Iterator useIt = (between.getUseBoxes()).iterator();
00375                            useIt.hasNext(); )
00376                         {
00377                           ValueBox box = (ValueBox) useIt.next();
00378                           
00379                           if(between == use && box == useBox)
00380                           {
00381                                 // Reached use point, stop looking for
00382                                 // side effects
00383                                 break;
00384                           }
00385                           
00386                           Value v = box.getValue();
00387                           
00388                           if (v instanceof InvokeExpr)
00389                             cantAggr = true;
00390                         }
00391                     }
00392             }
00393 
00394           // we give up: can't aggregate.
00395           if (cantAggr)
00396           {
00397             continue;
00398           }
00399           /* assuming that the d-u chains are correct, */
00400           /* we need not check the actual contents of ld */
00401           
00402           Value aggregatee = ((AssignStmt)s).getRightOp();
00403           
00404           if (usepair.valueBox.canContainValue(aggregatee))
00405             {
00406               usepair.valueBox.setValue(aggregatee);
00407               body.eliminateBackPointersTo(s);
00408               stmtIt.remove();
00409               hadAggregation = true;
00410               aggrCount++;
00411             }
00412           else
00413             {/*
00414             if(Main.isVerbose)
00415             {
00416                 System.out.println("[debug] failed aggregation");
00417                   System.out.println("[debug] tried to put "+aggregatee+
00418                                  " into "+usepair.stmt + 
00419                                  ": in particular, "+usepair.valueBox);
00420                   System.out.println("[debug] aggregatee instanceof Expr: "
00421                                  +(aggregatee instanceof Expr));
00422             }*/
00423             }
00424         }
00425       return hadAggregation;
00426     }
00427     public static void packLocals(StmtBody body)
00428     {
00429         Map localToGroup = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00430         Map groupToColorCount = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00431         Map localToColor = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00432         Map localToNewLocal;
00433         
00434         // Assign each local to a group, and set that group's color count to 0.
00435         {
00436             Iterator localIt = body.getLocals().iterator();
00437 
00438             while(localIt.hasNext())
00439             {
00440                 Local l = (Local) localIt.next();
00441                 Object g = l.getType();
00442                 
00443                 localToGroup.put(l, g);
00444                 
00445                 if(!groupToColorCount.containsKey(g))
00446                 {
00447                     groupToColorCount.put(g, new Integer(0));
00448                 }
00449             }
00450         }
00451 
00452         // Assign colors to the parameter locals.
00453         {
00454             Iterator codeIt = body.getStmtList().iterator();
00455 
00456             while(codeIt.hasNext())
00457             {
00458                 Stmt s = (Stmt) codeIt.next();
00459 
00460                 if(s instanceof IdentityStmt &&
00461                     ((IdentityStmt) s).getLeftOp() instanceof Local)
00462                 {
00463                     Local l = (Local) ((IdentityStmt) s).getLeftOp();
00464                     
00465                     Object group = localToGroup.get(l);
00466                     int count = ((Integer) groupToColorCount.get(group)).intValue();
00467                     
00468                     localToColor.put(l, new Integer(count));
00469                     
00470                     count++;
00471                     
00472                     groupToColorCount.put(group, new Integer(count));
00473                 }
00474             }
00475         }
00476         
00477         // Call the graph colorer.
00478             FastColorer.assignColorsToLocals(body, localToGroup,
00479                 localToColor, groupToColorCount);
00480                     
00481         // Map each local to a new local.
00482         {
00483             List originalLocals = new ArrayList();
00484             localToNewLocal = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00485             Map groupIntToLocal = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00486             
00487             originalLocals.addAll(body.getLocals());
00488             body.getLocals().clear();
00489 
00490             Iterator localIt = originalLocals.iterator();
00491 
00492             while(localIt.hasNext())
00493             {
00494                 Local original = (Local) localIt.next();
00495                 
00496                 Object group = localToGroup.get(original);
00497                 int color = ((Integer) localToColor.get(original)).intValue();
00498                 GroupIntPair pair = new GroupIntPair(group, color);
00499                 
00500                 Local newLocal;
00501                 
00502                 if(groupIntToLocal.containsKey(pair))
00503                     newLocal = (Local) groupIntToLocal.get(pair);
00504                 else {
00505                     newLocal = new Local(original.getName(), (Type) group);
00506                     groupIntToLocal.put(pair, newLocal);
00507                     body.getLocals().add(newLocal);
00508                 }
00509                 
00510                 localToNewLocal.put(original, newLocal);
00511             }
00512         }
00513 
00514         
00515         // Go through all valueBoxes of this method and perform changes
00516         {
00517             Iterator codeIt = body.getStmtList().iterator();
00518 
00519             while(codeIt.hasNext())
00520             {
00521                 Stmt s = (Stmt) codeIt.next();
00522 
00523                 //System.out.println("stmt s: " + s);
00524 
00525                 Iterator boxIt = s.getUseAndDefBoxes().iterator();
00526 
00527                 while(boxIt.hasNext())
00528                 {
00529                     ValueBox box = (ValueBox) boxIt.next();
00530 
00531                     //System.out.println("boxValue: " + box.getValue());
00532 
00533                     if(box.getValue() instanceof Local)
00534                     {
00535                         Local l = (Local) box.getValue();
00536                         box.setValue((Local) localToNewLocal.get(l));
00537 
00538                         //System.out.println("instance of local: " + l);
00539                         //System.out.println("ToNewLocal: " + (Local) localToNewLocal.get(l));
00540                         //System.out.println("value of box after set to new Local: " + box.getValue());
00541                     }
00542                 }
00543                 /*
00544                 //System.out.println("Test for use boxes: " +s);
00545                 boxIt = s.getUseBoxes().iterator();
00546                 while(boxIt.hasNext())
00547                   {
00548                     ValueBox box = (ValueBox) boxIt.next();
00549                     System.out.println("box value: " + box.getValue());
00550                   }
00551                 */
00552             }
00553         }
00554     }
00555     public static void removeUnusedLocals(StmtBody listBody)
00556     {
00557         StmtList stmtList = listBody.getStmtList();
00558         Set unusedLocals = new HashSet();
00559 
00560         // Set all locals as unused
00561             unusedLocals.addAll(listBody.getLocals());
00562 
00563         // Traverse statements noting all the uses
00564         {
00565             Iterator stmtIt = stmtList.iterator();
00566 
00567             while(stmtIt.hasNext())
00568             {
00569                 Stmt s = (Stmt) stmtIt.next();
00570 
00571                 // Remove all locals in defBoxes from unusedLocals
00572                 {
00573                     Iterator boxIt = s.getDefBoxes().iterator();
00574 
00575                     while(boxIt.hasNext())
00576                     {
00577                         Value value = ((ValueBox) boxIt.next()).getValue();
00578 
00579                         if(value instanceof Local && unusedLocals.contains(value))
00580                             unusedLocals.remove(value);
00581                     }
00582                 }
00583 
00584                 // Remove all locals in useBoxes from unusedLocals
00585                 {
00586                     Iterator boxIt = s.getUseBoxes().iterator();
00587 
00588                     while(boxIt.hasNext())
00589                     {
00590                         Value value = ((ValueBox) boxIt.next()).getValue();
00591 
00592                         if(value instanceof Local && unusedLocals.contains(value))
00593                             unusedLocals.remove(value);
00594                     }
00595                 }
00596             }
00597 
00598         }
00599 
00600         // Remove all locals in unusedLocals
00601         {
00602             Iterator it = unusedLocals.iterator();
00603             List locals = listBody.getLocals();
00604             
00605             while(it.hasNext())
00606             {
00607                 Local local = (Local) it.next();
00608 
00609                 locals.remove(local);
00610             }
00611         }
00612     }
00613     public static void renameLocals(StmtBody body)
00614     {
00615         StmtList stmtList = body.getStmtList();
00616 
00617         // Change the names to the standard forms now.
00618         {
00619             int objectCount = 0;
00620             int intCount = 0;
00621             int longCount = 0;
00622             int floatCount = 0;
00623             int doubleCount = 0;
00624             int addressCount = 0;
00625             int errorCount = 0;
00626             int nullCount = 0;
00627 
00628             Iterator localIt = body.getLocals().iterator();
00629 
00630             while(localIt.hasNext())
00631             {
00632                 Local l = (Local) localIt.next();
00633 
00634                 if(l.getType().equals(IntType.v()))
00635                     l.setName("i" + intCount++);
00636                 else if(l.getType().equals(LongType.v()))
00637                     l.setName("l" + longCount++);
00638                 else if(l.getType().equals(DoubleType.v()))
00639                     l.setName("d" + doubleCount++);
00640                 else if(l.getType().equals(FloatType.v()))
00641                     l.setName("f" + floatCount++);
00642                 else if(l.getType().equals(StmtAddressType.v()))
00643                     l.setName("a" + addressCount++);
00644                 else if(l.getType().equals(ErroneousType.v()) ||
00645                     l.getType().equals(UnknownType.v()))
00646                 {
00647                     l.setName("e" + errorCount++);
00648                 }
00649                 else if(l.getType().equals(NullType.v()))
00650                     l.setName("n" + nullCount++);
00651                 else
00652                     l.setName("r" + objectCount++);
00653             }
00654         }
00655     }
00656 }

Generated at Thu Feb 7 06:57:56 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001