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

JasminClass.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 (plam@sable.mcgill.ca).  All       *
00014  * rights reserved.                                                  *
00015  *                                                                   *
00016  * This work was done as a project of the Sable Research Group,      *
00017  * School of Computer Science, McGill University, Canada             *
00018  * (http://www.sable.mcgill.ca/).  It is understood that any         *
00019  * modification not identified as such is not covered by the         *
00020  * preceding statement.                                              *
00021  *                                                                   *
00022  * This work is free software; you can redistribute it and/or        *
00023  * modify it under the terms of the GNU Library General Public       *
00024  * License as published by the Free Software Foundation; either      *
00025  * version 2 of the License, or (at your option) any later version.  *
00026  *                                                                   *
00027  * This work is distributed in the hope that it will be useful,      *
00028  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00029  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
00030  * Library General Public License for more details.                  *
00031  *                                                                   *
00032  * You should have received a copy of the GNU Library General Public *
00033  * License along with this library; if not, write to the             *
00034  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,      *
00035  * Boston, MA  02111-1307, USA.                                      *
00036  *                                                                   *
00037  * Java is a trademark of Sun Microsystems, Inc.                     *
00038  *                                                                   *
00039  * To submit a bug report, send a comment, or get the latest news on *
00040  * this project and other Sable Research Group projects, please      *
00041  * visit the web site: http://www.sable.mcgill.ca/                   *
00042  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00043 
00044 /*
00045  Reference Version
00046  -----------------
00047  This is the latest official version on which this file is based.
00048  The reference version is: $SootVersion: 1.beta.4 $
00049 
00050  Change History
00051  --------------
00052  A) Notes:
00053 
00054  Please use the following template.  Most recent changes should
00055  appear at the top of the list.
00056 
00057  - Modified on [date (March 1, 1900)] by [name]. [(*) if appropriate]
00058    [description of modification].
00059 
00060  Any Modification flagged with "(*)" was done as a project of the
00061  Sable Research Group, School of Computer Science,
00062  McGill University, Canada (http://www.sable.mcgill.ca/).
00063 
00064  You should add your copyright, using the following template, at
00065  the top of this file, along with other copyrights.
00066 
00067  *                                                                   *
00068  * Modifications by [name] are                                       *
00069  * Copyright (C) [year(s)] [your name (or company)].  All rights     *
00070  * reserved.                                                         *
00071  *                                                                   *
00072 
00073  B) Changes:
00074 
00075  - Modified on March 13, 1999 by Raja Vallee-Rai (rvalleerai@sable.mcgill.ca) (*)
00076    Re-organized the timers.
00077 
00078  - Modified on March 4, 1999 by Patrick Lam (plam@sable.mcgill.ca) (*)
00079    Added peephole optimizations for the code generation of ++ like structures.
00080       
00081  - Modified on February 19, 1999 by Raja Vallee-Rai (kor@sable.mcgill.ca) (*)
00082    Uses bipush & sipush instead of ldc
00083    More efficient branch generation.
00084    Uses the iinc bytecode instruction to generate more efficient code.
00085    
00086  - Modified on February 17, 1999 by Raja Vallee-Rai (kor@sable.mcgill.ca) (*)
00087    Added the emitting of stack height.
00088    
00089  - Modified on February 15, 1999 by Patrick Lam (plam@sable.mcgill.ca) (*)
00090    Fixed bug with booleans, chars, bytes and shorts and if_cmpxx.
00091    Fixed bug with type casts of bytes/chars/booleans/shorts to ints.
00092 
00093  - Modified on November 18, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca) (*)
00094    Fixed a jsr generation bug.
00095    Fixed generation of 'and's.
00096    Changed the output of constants.  (uses L and F)
00097    
00098  - Modified on November 2, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca) (*)
00099    Repackaged all source files and performed extensive modifications.
00100    First initial release of Soot.
00101 
00102  - Modified on October 4, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca (*)
00103    Method names in the .jasmin format now are output as strings.
00104    Class which has no superclass should indicate in its .jasmin file
00105    that it is its own superclass.
00106 
00107  - Modified on October 2, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca (*)
00108    Fixed the generation of code for acmp_ifne and acmp_ifeq, aload, astore
00109     when nulls are involved.
00110 
00111  - Modified on September 25, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca (*)
00112    Does not output empty exception ranges.  (verifier doesn't like that)
00113    Fixed the generation of invokeinterface.
00114    Fixed the generation of array references.
00115    Fixed the generation of bastores.
00116    Fixed the generation of castores.
00117 
00118  - Modified on September 22, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca (*)
00119    Fixed the generation of jsr code.
00120    Added support for casts.
00121    Fixed a bug with the return instruction.
00122 
00123  - Modified on September 15, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca (*)
00124    Implemented the jsr jump. (needs some type checks however)
00125 
00126  - Modified on September 12, 1998 by Raja Vallee-Rai (kor@sable.mcgill.ca (*)
00127    Changed PrintStream to PrintWriter.
00128 
00129  - Modified on 23-Jul-1998 by Raja Vallee-Rai (kor@sable.mcgill.ca (*)
00130    Renamed Hashtable to Hashmap, and minor changes.
00131 
00132  - Modified on July 5, 1998 by Etienne Gagnon (gagnon@sable.mcgill.ca). (*)
00133    Changed caseDefault to defaultCase, to avoid name conflicts (and conform
00134    to the standard).
00135 
00136  - Modified on 15-Jun-1998 by Raja Vallee-Rai (kor@sable.mcgill.ca). (*)
00137    First internal release (Version 0.1).
00138 */
00139 
00140 import ca.mcgill.sable.soot.*;
00141 import ca.mcgill.sable.util.*;
00142 import java.io.*;
00143 
00144 public class JasminClass
00145 {
00146     Map stmtToLabel;
00147     Map localToSlot;
00148     Map subroutineToReturnAddressSlot;
00149 
00150     List code;
00151 
00152     boolean isEmittingMethodCode;
00153     int labelCount;
00154 
00155     boolean isNextGotoAJsr;
00156     int returnAddressSlot;
00157     int currentStackHeight = 0;
00158     int maxStackHeight = 0;
00159 
00160     Map localToGroup;
00161     Map groupToColorCount;
00162     Map localToColor; 
00163             
00164     /* try to pre-duplicate a local and fix-up its dup_xn parameter. */
00165     /* if we find that we're unable to proceed, we swap the dup_xn */
00166     /* for a store pl, load pl combination */
00167     Value plusPlusValue;
00168     Local plusPlusHolder;
00169     int plusPlusState;
00170     int plusPlusPlace;
00171     int plusPlusHeight;
00172     Stmt plusPlusIncrementer;
00173 
00174     public JasminClass(SootClass SootClass, BodyExpr bodyExpr)
00175     {
00176         code = new LinkedList();
00177 
00178         // Emit the header
00179         {
00180             int modifiers = SootClass.getModifiers();
00181 
00182             if(Modifier.isInterface(modifiers))
00183             {
00184                 modifiers -= Modifier.INTERFACE;
00185 
00186                 emit(".interface " + Modifier.toString(modifiers) + " " + slashify(SootClass.getName()));
00187             }
00188             else
00189                 emit(".class " + Modifier.toString(modifiers) + " " + slashify(SootClass.getName()));
00190 
00191             if(SootClass.hasSuperClass())
00192                 emit(".super " + slashify(SootClass.getSuperClass().getName()));
00193             else
00194                 emit(".super " + slashify(SootClass.getName()));
00195 
00196             emit("");
00197         }
00198 
00199         // Emit the interfaces
00200         {
00201             Iterator interfaceIt = SootClass.getInterfaces().iterator();
00202 
00203             while(interfaceIt.hasNext())
00204             {
00205                 SootClass inter = (SootClass) interfaceIt.next();
00206 
00207                 emit(".implements " + slashify(inter.getName()));
00208             }
00209 
00210             if(SootClass.getInterfaceCount() != 0)
00211                 emit("");
00212         }
00213 
00214         // Emit the fields
00215         {
00216             Iterator fieldIt = SootClass.getFields().iterator();
00217 
00218             while(fieldIt.hasNext())
00219             {
00220                 SootField field = (SootField) fieldIt.next();
00221 
00222                 emit(".field " + Modifier.toString(field.getModifiers()) + " " +
00223                      "\"" + field.getName() + "\"" + " " + jasminDescriptorOf(field.getType()));
00224             }
00225 
00226             if(SootClass.getFieldCount() != 0)
00227                 emit("");
00228         }
00229 
00230         // Emit the methods
00231         {
00232             Iterator methodIt = SootClass.getMethods().iterator();
00233 
00234             while(methodIt.hasNext())
00235             {
00236                 emitMethod((SootMethod) methodIt.next(), bodyExpr);
00237                 emit("");
00238             }
00239         }
00240     }
00241     int argCountOf(SootMethod m)
00242     {
00243         int argCount = 0;
00244         Iterator typeIt = m.getParameterTypes().iterator();
00245 
00246         while(typeIt.hasNext())
00247         {
00248             Type t = (Type) typeIt.next();
00249 
00250             argCount += sizeOfType(t);
00251         }
00252 
00253         return argCount;
00254     }
00255     void assignColorsToLocals(StmtBody body)
00256     {
00257         if(Main.isVerbose)
00258             System.out.println("[" + body.getMethod().getName() +
00259                 "] Assigning colors to locals...");
00260         
00261         if(Main.isProfilingOptimization)
00262             Main.packTimer.start();
00263 
00264         localToGroup = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00265         groupToColorCount = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00266         localToColor = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00267         
00268         // Assign each local to a group, and set that group's color count to 0.
00269         {
00270             Iterator localIt = body.getLocals().iterator();
00271 
00272             while(localIt.hasNext())
00273             {
00274                 Local l = (Local) localIt.next();
00275                 Object g;
00276                 
00277                 if(sizeOfType(l.getType()) == 1)
00278                     g = IntType.v();
00279                 else
00280                     g = LongType.v();
00281                 
00282                 localToGroup.put(l, g);
00283                 
00284                 if(!groupToColorCount.containsKey(g))
00285                 {
00286                     groupToColorCount.put(g, new Integer(0));
00287                 }
00288             }
00289         }
00290 
00291         // Assign colors to the parameter locals.
00292         {
00293             Iterator codeIt = body.getStmtList().iterator();
00294 
00295             while(codeIt.hasNext())
00296             {
00297                 Stmt s = (Stmt) codeIt.next();
00298 
00299                 if(s instanceof IdentityStmt &&
00300                     ((IdentityStmt) s).getLeftOp() instanceof Local)
00301                 {
00302                     Local l = (Local) ((IdentityStmt) s).getLeftOp();
00303                     
00304                     Object group = localToGroup.get(l);
00305                     int count = ((Integer) groupToColorCount.get(group)).intValue();
00306                     
00307                     localToColor.put(l, new Integer(count));
00308                     
00309                     count++;
00310                     
00311                     groupToColorCount.put(group, new Integer(count));
00312                 }
00313             }
00314         }
00315         
00316         // Call the graph colorer.
00317             FastColorer.assignColorsToLocals(body, localToGroup,
00318                 localToColor, groupToColorCount);
00319 
00320         if(Main.isProfilingOptimization)
00321             Main.packTimer.end();
00322                     
00323     }
00324     void emit(String s)
00325     {
00326         okayEmit(s);
00327     }
00328     void emit(String s, int stackChange)
00329     {
00330         modifyStackHeight(stackChange);        
00331         okayEmit(s);
00332     }
00333     void emitAssignStmt(AssignStmt stmt)
00334     {
00335         final Value lvalue = stmt.getLeftOp();
00336         final Value rvalue = stmt.getRightOp();
00337 
00338         // Handle simple subcase where you can use the efficient iinc bytecode
00339             if(lvalue instanceof Local && (rvalue instanceof AddExpr || rvalue instanceof SubExpr))
00340             {
00341                 Local l = (Local) lvalue;
00342                 BinopExpr expr = (BinopExpr) rvalue;
00343                 Value op1 = expr.getOp1();
00344                 Value op2 = expr.getOp2();
00345                                 
00346                 if(l.getType().equals(IntType.v()))
00347                 {
00348                     boolean isValidCase = false;
00349                     int x = 0;
00350                     
00351                     if(op1 == l && op2 instanceof IntConstant) 
00352                     {
00353                         x = ((IntConstant) op2).value;
00354                         isValidCase = true;
00355                     }
00356                     else if(expr instanceof AddExpr && 
00357                         op2 == l && op1 instanceof IntConstant)
00358                     {
00359                         // Note expr can't be a SubExpr because that would be x = 3 - x
00360                         
00361                         x = ((IntConstant) op1).value;
00362                         isValidCase = true;
00363                     }
00364                     
00365                     if(isValidCase && x >= Short.MIN_VALUE && x <= Short.MAX_VALUE)
00366                     {
00367                         emit("iinc " + ((Integer) localToSlot.get(l)).intValue() + " " +  
00368                             ((expr instanceof AddExpr) ? x : -x), 0);
00369                         return;
00370                     }        
00371                 }
00372             }
00373 
00374         lvalue.apply(new AbstractJimpleValueSwitch()
00375         {
00376         public void caseArrayRef(ArrayRef v)
00377         {
00378             emitValue(v.getBase());
00379             emitValue(v.getIndex());
00380             emitValue(rvalue);
00381             
00382             v.getType().apply(new TypeSwitch()
00383             {
00384             public void caseArrayType(ArrayType t)
00385             {
00386                 emit("aastore", -3);
00387             }
00388 
00389             public void caseDoubleType(DoubleType t)
00390             {
00391                 emit("dastore", -4);
00392             }
00393 
00394             public void caseFloatType(FloatType t)
00395                         {
00396                 emit("fastore", -3);
00397             }
00398 
00399             public void caseIntType(IntType t)
00400                         {
00401                 emit("iastore", -3);
00402             }
00403 
00404             public void caseLongType(LongType t)
00405                         {
00406                 emit("lastore", -4);
00407             }
00408 
00409             public void caseRefType(RefType t)
00410                         {
00411                 emit("aastore", -3);
00412             }
00413 
00414             public void caseByteType(ByteType t)
00415                         {
00416                 emit("bastore", -3);
00417             }
00418 
00419             public void caseBooleanType(BooleanType t)
00420                         {
00421                 emit("bastore", -3);
00422             }
00423 
00424             public void caseCharType(CharType t)
00425                         {
00426                 emit("castore", -3);
00427             }
00428 
00429             public void caseShortType(ShortType t)
00430                         {
00431                 emit("sastore", -3);
00432             }
00433 
00434             public void defaultCase(Type t)
00435                         {
00436                 throw new RuntimeException("Invalid type: " + t);
00437             }
00438             });
00439         }
00440         
00441         public void defaultCase(Value v)
00442             {
00443             throw new RuntimeException("Can't store in value " + v);
00444             }
00445         
00446         public void caseInstanceFieldRef(InstanceFieldRef v)
00447             {
00448             emitValue(v.getBase());
00449             emitValue(rvalue);
00450             
00451             emit("putfield " + slashify(v.getField().getDeclaringClass().getName()) + "/" +
00452                  v.getField().getName() + " " + jasminDescriptorOf(v.getField().getType()), 
00453                  -1 + -sizeOfType(v.getField().getType()));
00454             }
00455         
00456         public void caseLocal(final Local v)
00457         {
00458             final int slot = ((Integer) localToSlot.get(v)).intValue();
00459             
00460             v.getType().apply(new TypeSwitch()
00461             {
00462             public void caseArrayType(ArrayType t)
00463             {
00464                 emitValue(rvalue);
00465 
00466                 if(slot >= 0 && slot <= 3)
00467                 emit("astore_" + slot, -1);
00468                 else
00469                 emit("astore " + slot, -1);
00470             }
00471 
00472             public void caseDoubleType(DoubleType t)
00473             {
00474                 emitValue(rvalue);
00475 
00476                 if(slot >= 0 && slot <= 3)
00477                 emit("dstore_" + slot, -2);
00478                 else
00479                 emit("dstore " + slot, -2);
00480             }
00481             
00482             public void caseFloatType(FloatType t)
00483             {
00484                 emitValue(rvalue);
00485                 
00486                 if(slot >= 0 && slot <= 3)
00487                 emit("fstore_" + slot, -1);
00488                 else
00489                 emit("fstore " + slot, -1);
00490             }
00491 
00492             public void caseIntType(IntType t)
00493                 {
00494                 emitValue(rvalue);
00495                 
00496                 if(slot >= 0 && slot <= 3)
00497                     emit("istore_" + slot, -1);
00498                 else
00499                     emit("istore " + slot, -1);
00500                 }
00501 
00502             public void caseLongType(LongType t)
00503                 {
00504                 emitValue(rvalue);
00505                 
00506                 if(slot >= 0 && slot <= 3)
00507                     emit("lstore_" + slot, -2);
00508                 else
00509                     emit("lstore " + slot, -2);
00510                 }
00511             
00512             public void caseRefType(RefType t)
00513                 {
00514                 emitValue(rvalue);
00515                 
00516                 if(slot >= 0 && slot <= 3)
00517                     emit("astore_" + slot, -1);
00518                 else
00519                     emit("astore " + slot, -1);
00520                 }
00521 
00522             public void caseStmtAddressType(StmtAddressType t)
00523                 {
00524                 isNextGotoAJsr = true;
00525                 returnAddressSlot = slot;
00526                 
00527                 /*
00528                   if ( slot >= 0 && slot <= 3)
00529                   emit("astore_" + slot,  );
00530                   else
00531                   emit("astore " + slot,  );
00532                   
00533                 */
00534                 
00535                 }
00536             
00537             public void caseNullType(NullType t)
00538                 {
00539                 emitValue(rvalue);
00540                 
00541                 if(slot >= 0 && slot <= 3)
00542                     emit("astore_" + slot, -1);
00543                 else
00544                     emit("astore " + slot, -1);
00545                 }
00546             
00547             public void defaultCase(Type t)
00548                 {
00549                 throw new RuntimeException("Invalid local type: " + t);
00550                 }
00551             });
00552         }
00553         
00554         public void caseStaticFieldRef(StaticFieldRef v)
00555             {
00556             SootField field = v.getField();
00557             
00558             emitValue(rvalue);
00559             emit("putstatic " + slashify(field.getDeclaringClass().getName()) + "/" +
00560                  field.getName() + " " + jasminDescriptorOf(field.getType()),
00561                  -sizeOfType(v.getField().getType()));
00562             }
00563         });
00564     }
00565     public void emitBooleanBranch(String s)
00566     {
00567         int count;
00568         
00569         if(s.indexOf("icmp") != -1 || s.indexOf("acmp") != -1)
00570             count = -2;
00571         else
00572             count = -1;
00573             
00574         emit(s + " label" + labelCount, count);
00575         emit("iconst_0", 1);
00576         emit("goto label" + labelCount+1, 0);
00577         emit("label" + labelCount++ + ":");
00578         emit("iconst_1", 1);
00579         emit("label" + labelCount++ + ":");
00580     }
00581     void emitIfStmt(IfStmt stmt)
00582     {
00583         Value cond = stmt.getCondition();
00584 
00585         final Value op1 = ((BinopExpr) cond).getOp1();
00586         final Value op2 = ((BinopExpr) cond).getOp2();
00587         final String label = (String) stmtToLabel.get(stmt.getTarget());
00588 
00589         // Handle simple subcase where op1 is null
00590             if(op2 instanceof NullConstant || op1 instanceof NullConstant)
00591             {
00592                 if(op2 instanceof NullConstant)
00593                     emitValue(op1);
00594                 else
00595                     emitValue(op2);
00596                     
00597                 if(cond instanceof EqExpr)
00598                     emit("ifnull " + label, -1);
00599                 else if(cond instanceof NeExpr)  
00600                     emit("ifnonnull "+ label, -1);
00601                 else
00602                     throw new RuntimeException("invalid condition");
00603                     
00604                 return;
00605             }
00606 
00607         // Handle simple subcase where op2 is 0  
00608             if(op2 instanceof IntConstant && ((IntConstant) op2).value == 0)
00609             {
00610                 emitValue(op1);
00611                 
00612                 cond.apply(new AbstractJimpleValueSwitch()
00613                 {
00614                     public void caseEqExpr(EqExpr expr)
00615                     {
00616                         emit("ifeq " + label, -1);
00617                     }
00618         
00619                     public void caseNeExpr(NeExpr expr)
00620                     {
00621                         emit("ifne " + label, -1);
00622                     }
00623         
00624                     public void caseLtExpr(LtExpr expr)
00625                     {
00626                         emit("iflt " + label, -1); 
00627                     }
00628                     
00629                     public void caseLeExpr(LeExpr expr)
00630                     {
00631                         emit("ifle " + label, -1);
00632                     }
00633         
00634                     public void caseGtExpr(GtExpr expr)
00635                     {
00636                         emit("ifgt " + label, -1);
00637                     }
00638         
00639                     public void caseGeExpr(GeExpr expr)
00640                     {
00641                         emit("ifge " + label, -1);
00642                     }
00643         
00644                     public void defaultCase(Value v)
00645                     {
00646                         throw new RuntimeException("invalid condition " + v);
00647                     }
00648                 });               
00649                  
00650                 return;
00651             }
00652         
00653         // Handle simple subcase where op1 is 0  (flip directions)
00654             if(op1 instanceof IntConstant && ((IntConstant) op1).value == 0)
00655             {
00656                 emitValue(op2);
00657                 
00658                 cond.apply(new AbstractJimpleValueSwitch()
00659                 {
00660                     public void caseEqExpr(EqExpr expr)
00661                     {
00662                         emit("ifeq " + label, -1);
00663                     }
00664         
00665                     public void caseNeExpr(NeExpr expr)
00666                     {
00667                         emit("ifne " + label, -1);
00668                     }
00669         
00670                     public void caseLtExpr(LtExpr expr)
00671                     {
00672                         emit("ifgt " + label, -1); 
00673                     }
00674                     
00675                     public void caseLeExpr(LeExpr expr)
00676                     {
00677                         emit("ifge " + label, -1);
00678                     }
00679         
00680                     public void caseGtExpr(GtExpr expr)
00681                     {
00682                         emit("iflt " + label, -1);
00683                     }
00684         
00685                     public void caseGeExpr(GeExpr expr)
00686                     {
00687                         emit("ifle " + label, -1);
00688                     }
00689         
00690                     public void defaultCase(Value v)
00691                     {
00692                         throw new RuntimeException("invalid condition " + v);
00693                     }
00694                 });               
00695                  
00696                 return;
00697             }
00698         
00699         emitValue(op1);
00700         emitValue(op2);
00701 
00702         cond.apply(new AbstractJimpleValueSwitch()
00703         {
00704             public void caseEqExpr(EqExpr expr)
00705             {
00706                 op1.getType().apply(new TypeSwitch()
00707                 {
00708                     public void caseIntType(IntType t)
00709                     {
00710                         emit("if_icmpeq " + label, -2);
00711                     }
00712 
00713             public void caseBooleanType(BooleanType t)
00714             {
00715                 emit("if_icmpeq " + label, -2);
00716             }
00717 
00718             public void caseShortType(ShortType t)
00719             {
00720                 emit("if_icmpeq " + label, -2);
00721             }
00722 
00723             public void caseCharType(CharType t)
00724             {
00725                 emit("if_icmpeq " + label, -2);
00726             }
00727 
00728             public void caseByteType(ByteType t)
00729             {
00730                 emit("if_icmpeq " + label, -2);
00731             }
00732 
00733                     public void caseDoubleType(DoubleType t)
00734                     {
00735                         emit("dcmpg", -3);
00736                         emit("ifeq " + label, -1);
00737                     }
00738 
00739                     public void caseLongType(LongType t)
00740                     {
00741                         emit("lcmp", -3);
00742                         emit("ifeq " + label, -1);
00743                     }
00744 
00745                     public void caseFloatType(FloatType t)
00746                     {
00747                         emit("fcmpg", -1);
00748                         emit("ifeq " + label, -1);
00749                     }
00750 
00751                     public void caseArrayType(ArrayType t)
00752                     {
00753                         emit("if_acmpeq " + label, -2);
00754                     }
00755 
00756                     public void caseRefType(RefType t)
00757                     {
00758                         emit("if_acmpeq " + label, -2);
00759                     }
00760 
00761                     public void caseNullType(NullType t)
00762                     {
00763                         emit("if_acmpeq " + label, -2);
00764                     }
00765 
00766                     public void defaultCase(Type t)
00767                     {
00768                         throw new RuntimeException("invalid type");
00769                     }
00770                 });
00771             }
00772 
00773             public void caseNeExpr(NeExpr expr)
00774             {
00775                 op1.getType().apply(new TypeSwitch()
00776                 {
00777                     public void caseIntType(IntType t)
00778                     {
00779                         emit("if_icmpne " + label, -2);
00780                     }
00781 
00782             public void caseBooleanType(BooleanType t)
00783             {
00784                 emit("if_icmpne " + label, -2);
00785             }
00786 
00787             public void caseShortType(ShortType t)
00788             {
00789                 emit("if_icmpne " + label, -2);
00790             }
00791 
00792             public void caseCharType(CharType t)
00793             {
00794                 emit("if_icmpne " + label, -2);
00795             }
00796 
00797             public void caseByteType(ByteType t)
00798             {
00799                 emit("if_icmpne " + label, -2);
00800             }
00801 
00802                     public void caseDoubleType(DoubleType t)
00803                     {
00804                         emit("dcmpg", -3);
00805                         emit("ifne " + label, -1);
00806                     }
00807 
00808                     public void caseLongType(LongType t)
00809                     {
00810                         emit("lcmp", -3);
00811                         emit("ifne " + label, -1);
00812                     }
00813 
00814                     public void caseFloatType(FloatType t)
00815                     {
00816                         emit("fcmpg", -1);
00817                         emit("ifne " + label, -1);
00818                     }
00819 
00820                     public void caseArrayType(ArrayType t)
00821                     {
00822                         emit("if_acmpne " + label, -2);
00823                     }
00824 
00825                     public void caseRefType(RefType t)
00826                     {
00827                         emit("if_acmpne " + label, -2);
00828                     }
00829 
00830                     public void caseNullType(NullType t)
00831                     {
00832                         emit("if_acmpne " + label, -2);
00833                     }
00834 
00835                     public void defaultCase(Type t)
00836                     {
00837                         throw new RuntimeException("invalid type for NeExpr: " + t);
00838                     }
00839                 });
00840             }
00841 
00842             public void caseLtExpr(LtExpr expr)
00843             {
00844                 op1.getType().apply(new TypeSwitch()
00845                 {
00846                     public void caseIntType(IntType t)
00847                     {
00848                         emit("if_icmplt " + label, -2);
00849                     }
00850 
00851             public void caseBooleanType(BooleanType t)
00852             {
00853                 emit("if_icmplt " + label, -2);
00854             }
00855 
00856             public void caseShortType(ShortType t)
00857             {
00858                 emit("if_icmplt " + label, -2);
00859             }
00860 
00861             public void caseCharType(CharType t)
00862             {
00863                 emit("if_icmplt " + label, -2);
00864             }
00865 
00866             public void caseByteType(ByteType t)
00867             {
00868                 emit("if_icmplt " + label, -2);
00869             }
00870 
00871 
00872                     public void caseDoubleType(DoubleType t)
00873                     {
00874                         emit("dcmpg", -3);
00875                         emit("iflt " + label, -1);
00876                     }
00877 
00878                     public void caseLongType(LongType t)
00879                     {
00880                         emit("lcmp", -3);
00881                         emit("iflt " + label, -1);
00882                     }
00883 
00884                     public void caseFloatType(FloatType t)
00885                     {
00886                         emit("fcmpg", -1);
00887                         emit("iflt " + label, -1);
00888                     }
00889 
00890                     public void defaultCase(Type t)
00891                     {
00892                         throw new RuntimeException("invalid type");
00893                     }
00894                 });
00895             }
00896 
00897             public void caseLeExpr(LeExpr expr)
00898             {
00899                 op1.getType().apply(new TypeSwitch()
00900                 {
00901                     public void caseIntType(IntType t)
00902                     {
00903                         emit("if_icmple " + label, -2);
00904                     }
00905 
00906             public void caseBooleanType(BooleanType t)
00907             {
00908                 emit("if_icmple " + label, -2);
00909             }
00910 
00911             public void caseShortType(ShortType t)
00912             {
00913                 emit("if_icmple " + label, -2);
00914             }
00915 
00916             public void caseCharType(CharType t)
00917             {
00918                 emit("if_icmple " + label, -2);
00919             }
00920 
00921             public void caseByteType(ByteType t)
00922             {
00923                 emit("if_icmple " + label, -2);
00924             }
00925 
00926                     public void caseDoubleType(DoubleType t)
00927                     {
00928                         emit("dcmpg", -3);
00929                         emit("ifle " + label, -1);
00930                     }
00931 
00932                     public void caseLongType(LongType t)
00933                     {
00934                         emit("lcmp", -3);
00935                         emit("ifle " + label, -1);
00936                     }
00937 
00938                     public void caseFloatType(FloatType t)
00939                     {
00940                         emit("fcmpg", -1);
00941                         emit("ifle " + label, -1);
00942                     }
00943 
00944                     public void defaultCase(Type t)
00945                     {
00946                         throw new RuntimeException("invalid type");
00947                     }
00948                 });
00949             }
00950 
00951             public void caseGtExpr(GtExpr expr)
00952             {
00953                 op1.getType().apply(new TypeSwitch()
00954                 {
00955                     public void caseIntType(IntType t)
00956                     {
00957                         emit("if_icmpgt " + label, -2);
00958                     }
00959 
00960             public void caseBooleanType(BooleanType t)
00961             {
00962                 emit("if_icmpgt " + label, -2);
00963             }
00964 
00965             public void caseShortType(ShortType t)
00966             {
00967                 emit("if_icmpgt " + label, -2);
00968             }
00969 
00970             public void caseCharType(CharType t)
00971             {
00972                 emit("if_icmpgt " + label, -2);
00973             }
00974 
00975             public void caseByteType(ByteType t)
00976             {
00977                 emit("if_icmpgt " + label, -2);
00978             }
00979 
00980                     public void caseDoubleType(DoubleType t)
00981                     {
00982                         emit("dcmpg", -3);
00983                         emit("ifgt " + label, -1);
00984                     }
00985 
00986                     public void caseLongType(LongType t)
00987                     {
00988                         emit("lcmp", -3);
00989                         emit("ifgt " + label, -1);
00990                     }
00991 
00992                     public void caseFloatType(FloatType t)
00993                     {
00994                         emit("fcmpg", -1);
00995                         emit("ifgt " + label, -1);
00996                     }
00997 
00998                     public void defaultCase(Type t)
00999                     {
01000                         throw new RuntimeException("invalid type");
01001                     }
01002                 });
01003             }
01004 
01005             public void caseGeExpr(GeExpr expr)
01006             {
01007                 op1.getType().apply(new TypeSwitch()
01008                 {
01009                     public void caseIntType(IntType t)
01010                     {
01011                         emit("if_icmpge " + label, -2);
01012                     }
01013 
01014             public void caseBooleanType(BooleanType t)
01015             {
01016                 emit("if_icmpge " + label, -2);
01017             }
01018 
01019             public void caseShortType(ShortType t)
01020             {
01021                 emit("if_icmpge " + label, -2);
01022             }
01023 
01024             public void caseCharType(CharType t)
01025             {
01026                 emit("if_icmpge " + label, -2);
01027             }
01028 
01029             public void caseByteType(ByteType t)
01030             {
01031                 emit("if_icmpge " + label, -2);
01032             }
01033 
01034                     public void caseDoubleType(DoubleType t)
01035                     {
01036                         emit("dcmpg", -3);
01037                         emit("ifge " + label, -1);
01038                     }
01039 
01040                     public void caseLongType(LongType t)
01041                     {
01042                         emit("lcmp", -3);
01043                         emit("ifge " + label, -1);
01044                     }
01045 
01046                     public void caseFloatType(FloatType t)
01047                     {
01048                         emit("fcmpg", -1);
01049                         emit("ifge " + label, -1);
01050                     }
01051 
01052                     public void defaultCase(Type t)
01053                     {
01054                         throw new RuntimeException("invalid type");
01055                     }
01056                 });
01057             }
01058 
01059             public void defaultCase(Value v)
01060             {
01061                 throw new RuntimeException("invalid condition " + v);
01062             }
01063         });
01064     }
01065     void emitLocal(Local v)
01066     {
01067     final int slot = ((Integer) localToSlot.get(v)).intValue();
01068     final Local vAlias = v;
01069 
01070     v.getType().apply(new TypeSwitch()
01071         {
01072         public void caseArrayType(ArrayType t)
01073         {
01074         if(slot >= 0 && slot <= 3)
01075             emit("aload_" + slot, 1);
01076         else
01077             emit("aload " + slot, 1);
01078         }
01079         
01080         public void defaultCase(Type t)
01081         {
01082         throw new RuntimeException("invalid local type to load" + t);
01083         }
01084 
01085         public void caseDoubleType(DoubleType t)
01086         {
01087         if(slot >= 0 && slot <= 3)
01088             emit("dload_" + slot, 2);
01089         else
01090             emit("dload " + slot, 2);
01091         }
01092 
01093         public void caseFloatType(FloatType t)
01094         {
01095         if(slot >= 0 && slot <= 3)
01096             emit("fload_" + slot, 1);
01097         else
01098             emit("fload " + slot, 1);
01099         }
01100         
01101         public void caseIntType(IntType t)
01102         {
01103         if (vAlias.equals(plusPlusHolder))
01104         {
01105             switch(plusPlusState)
01106             {
01107             case 0:    
01108             // ok, we're called upon to emit the
01109             // ++ target, whatever it was.
01110             
01111             // now we need to emit a statement incrementing
01112             // the correct value.  
01113                         // actually, just remember the local to be incremented.
01114 
01115             plusPlusState = 1;
01116             
01117             emitStmt(plusPlusIncrementer);
01118                         int diff = plusPlusHeight - currentStackHeight + 1;
01119                         if (diff > 0)
01120                           code.set(plusPlusPlace, "    dup_x"+diff);
01121             plusPlusHolder = null;
01122 
01123             // afterwards we have the value on the stack.
01124             return;
01125             case 1:
01126             plusPlusHeight = currentStackHeight;
01127 
01128                         emitValue(plusPlusValue);
01129 
01130                         plusPlusPlace = code.size();
01131             emit("dup", 1);
01132 
01133             return;
01134             }
01135         }
01136         if(slot >= 0 && slot <= 3)
01137             emit("iload_" + slot, 1);
01138         else
01139             emit("iload " + slot, 1);
01140         }
01141 
01142         public void caseLongType(LongType t)
01143         {
01144         if(slot >= 0 && slot <= 3)
01145             emit("lload_" + slot, 2);
01146         else
01147             emit("lload " + slot, 2);
01148         }
01149 
01150         public void caseRefType(RefType t)
01151         {
01152         if(slot >= 0 && slot <= 3)
01153             emit("aload_" + slot, 1);
01154         else
01155             emit("aload " + slot, 1);
01156         }
01157 
01158         public void caseNullType(NullType t)
01159         {
01160         if(slot >= 0 && slot <= 3)
01161             emit("aload_" + slot, 1);
01162         else
01163             emit("aload " + slot, 1);
01164         }
01165     });
01166     }
01167     void emitMethod(SootMethod method, BodyExpr bodyExpr)
01168     {
01169         StmtBody body = (StmtBody) bodyExpr.resolveFor(method);
01170         StmtList stmtList = body.getStmtList();
01171 
01172         // let's create a u-d web for the ++ peephole optimization.
01173 
01174         if(Main.isVerbose)
01175             System.out.println("[" + body.getMethod().getName() +
01176                 "] Performing peephole optimizations...");
01177 
01178         CompleteStmtGraph stmtGraph = new CompleteStmtGraph(stmtList);
01179 
01180         LocalDefs ld = new SimpleLocalDefs(stmtGraph);
01181         LocalUses lu = new SimpleLocalUses(stmtGraph, ld);
01182 
01183         int stackLimitIndex;
01184         
01185         // Emit prologue
01186             emit(".method " + Modifier.toString(method.getModifiers()) + " " +
01187                  method.getName() + jasminDescriptorOf(method));
01188 
01189         subroutineToReturnAddressSlot = new HashMap(10, 0.7f);
01190 
01191         // Determine the stmtToLabel map
01192         {
01193             Iterator boxIt = body.getUnitBoxes().iterator();
01194 
01195             stmtToLabel = new HashMap(stmtList.size() * 2 + 1, 0.7f);
01196             labelCount = 0;
01197 
01198             while(boxIt.hasNext())
01199             {
01200                 // Assign a label for each statement reference
01201                 {
01202                     StmtBox box = (StmtBox) boxIt.next();
01203 
01204                     if(!stmtToLabel.containsKey(box.getUnit()))
01205                         stmtToLabel.put(box.getUnit(), "label" + labelCount++);
01206                 }
01207             }
01208         }
01209 
01210         // Emit the exceptions
01211         {
01212             Iterator trapIt = body.getTraps().iterator();
01213 
01214             while(trapIt.hasNext())
01215             {
01216                 Trap trap = (Trap) trapIt.next();
01217 
01218                 if(trap.getBeginUnit() != trap.getEndUnit())
01219                     emit(".catch " + slashify(trap.getException().getName()) + " from " +
01220                         stmtToLabel.get(trap.getBeginUnit()) + " to " + stmtToLabel.get(trap.getEndUnit()) +
01221                         " using " + stmtToLabel.get(trap.getHandlerUnit()));
01222             }
01223         }
01224 
01225         // Determine where the locals go
01226         {
01227             int localCount = 0;
01228             int[] paramSlots = new int[method.getParameterCount()];
01229             int thisSlot = 0;
01230             Set assignedLocals = new HashSet();
01231             Map groupColorPairToSlot = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
01232             
01233             localToSlot = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
01234 
01235             assignColorsToLocals(body);
01236             
01237             // Determine slots for 'this' and parameters
01238             {
01239                 List paramTypes = method.getParameterTypes();
01240 
01241                 if(!method.isStatic())
01242                 {
01243                     thisSlot = 0;
01244                     localCount++;
01245                 }
01246 
01247                 for(int i = 0; i < paramTypes.size(); i++)
01248                 {
01249                     paramSlots[i] = localCount;
01250                     localCount += sizeOfType((Type) paramTypes.get(i));
01251                 }
01252             }
01253 
01254             // Handle identity statements
01255             {
01256                 Iterator stmtIt = stmtList.iterator();
01257 
01258                 while(stmtIt.hasNext())
01259                 {
01260                     Stmt s = (Stmt) stmtIt.next();
01261 
01262                     if(s instanceof IdentityStmt && ((IdentityStmt) s).getLeftOp() instanceof Local)
01263                     {
01264                         Local l = (Local) ((IdentityStmt) s).getLeftOp();
01265                         IdentityRef identity = (IdentityRef) ((IdentityStmt) s).getRightOp();
01266 
01267                         int slot = 0;
01268                                                 
01269                         if(identity instanceof ThisRef)
01270                         {
01271                             if(method.isStatic())
01272                                 throw new RuntimeException("Attempting to use 'this' in static method");
01273 
01274                             slot = thisSlot;
01275                         }
01276                         else if(identity instanceof ParameterRef)
01277                             slot = paramSlots[((ParameterRef) identity).getIndex()];
01278                         else {
01279                             // Exception ref.  Skip over this
01280                             continue;
01281                         }
01282                         
01283                         // Make this (group, color) point to the given slot,
01284                         // so that all locals of the same color can be pointed here too
01285                         {
01286                             
01287                             GroupIntPair pair = new GroupIntPair(localToGroup.get(l), 
01288                                 ((Integer) localToColor.get(l)).intValue());
01289                                 
01290                             groupColorPairToSlot.put(pair, new Integer(slot));
01291                         }
01292                             
01293                         localToSlot.put(l, new Integer(slot));
01294                         assignedLocals.add(l);
01295                         
01296                     }
01297                 }
01298             }
01299 
01300             // Assign the rest of the locals
01301             {
01302                 Iterator localIt = body.getLocals().iterator();
01303 
01304                 while(localIt.hasNext())
01305                 {
01306                     Local local = (Local) localIt.next();
01307 
01308                     if(!assignedLocals.contains(local))
01309                     {
01310                         GroupIntPair pair = new GroupIntPair(localToGroup.get(local), 
01311                                 ((Integer) localToColor.get(local)).intValue());
01312                             
01313                         int slot;
01314 
01315                         if(groupColorPairToSlot.containsKey(pair))
01316                         {
01317                             // This local should share the same slot as the previous local with
01318                             // the same (group, color);
01319                             
01320                             slot = ((Integer) groupColorPairToSlot.get(pair)).intValue();
01321                         }
01322                         else { 
01323                             slot = localCount;           
01324                             localCount += sizeOfType(local.getType());
01325                     
01326                             groupColorPairToSlot.put(pair, new Integer(slot));
01327                          }
01328                             
01329                         localToSlot.put(local, new Integer(slot));
01330                         assignedLocals.add(local);
01331                     }
01332                 }
01333 
01334                 emit("    .limit stack ?");
01335                 stackLimitIndex = code.size() - 1;
01336                 
01337                 emit("    .limit locals " + localCount);
01338             }
01339         }
01340 
01341         // Emit code in one pass
01342         {
01343             Iterator codeIt = stmtList.iterator();
01344 
01345             isEmittingMethodCode = true;
01346             maxStackHeight = 0; 
01347             isNextGotoAJsr = false;
01348 
01349             while(codeIt.hasNext())
01350             {
01351                 Stmt s = (Stmt) codeIt.next();
01352 
01353                 if(stmtToLabel.containsKey(s))
01354                     emit(stmtToLabel.get(s) + ":");
01355 
01356                 if(subroutineToReturnAddressSlot.containsKey(s))
01357                 {
01358                     AssignStmt assignStmt = (AssignStmt) s;
01359 
01360                     modifyStackHeight(1); // simulate the pushing of address onto the stack by the jsr
01361 
01362                     emit("astore " + localToSlot.get(assignStmt.getLeftOp()), -1);
01363 
01364                     //emit("astore " + ( ( Integer ) subroutineToReturnAddressSlot.get( s ) ).intValue() );
01365 
01366                 }
01367 
01368 
01369                 // Test for postincrement operators ++ and --
01370                 // We can optimize them further.
01371 
01372         boolean contFlag = false;
01373                 // this is a fake do, to give us break;
01374                 do
01375                   {
01376                     if (!(s instanceof AssignStmt))
01377                       break;
01378 
01379                     AssignStmt stmt = (AssignStmt)s;
01380 
01381                     // sanityCheck: see that we have another statement after s.
01382                     if (!codeIt.hasNext())
01383                       break;
01384 
01385                     Stmt ns = (Stmt)(stmtGraph.getSuccsOf(stmt).get(0));
01386                     if (!(ns instanceof AssignStmt))
01387                       break;
01388                     AssignStmt nextStmt = (AssignStmt)ns;
01389 
01390                     List l = stmtGraph.getSuccsOf(nextStmt);
01391                     if (l.size() != 1)
01392                       break;
01393 
01394                     Stmt nextNextStmt = (Stmt)(l.get(0));
01395 
01396                     final Value lvalue = stmt.getLeftOp();
01397                     final Value rvalue = stmt.getRightOp();
01398 
01399                     if (!(lvalue instanceof Local))
01400                       break;
01401 
01402                     // we're looking for this pattern: 
01403                     // local = <lvalue>; <lvalue> = local +/- 1; use(local);
01404 
01405                     // we need some notion of equals 
01406                     // for rvalue & nextStmt.getLeftOp().
01407 
01408                     if (!(lvalue instanceof Local)
01409                         || !nextStmt.getLeftOp().equals(rvalue)
01410                         || !(nextStmt.getRightOp() instanceof AddExpr))
01411                       break;
01412 
01413                     AddExpr addexp = (AddExpr)nextStmt.getRightOp();
01414                     if (!addexp.getOp1().equals(lvalue))
01415                       break;
01416 
01417                     Value added /* tax? */ = addexp.getOp2();
01418                         
01419                     if (!(added instanceof IntConstant)
01420                         || ((IntConstant)(added)).value != 1)
01421                       break;
01422 
01423             /* check that we have two uses and that these */
01424             /* uses live precisely in nextStmt and nextNextStmt */
01425             /* LocalDefs tells us this: if there was no use, */
01426             /* there would be no corresponding def. */
01427                     if (lu.getUsesOf(stmt).size() != 2 ||
01428             ld.getDefsOfAt((Local)lvalue, nextStmt).size() != 1 ||
01429             ld.getDefsOfAt((Local)lvalue, nextNextStmt).size() !=1)
01430                       break;
01431 
01432             /* emit dup slot */
01433 
01434             /*
01435                     System.out.println("found ++ instance:");
01436                     System.out.println(s); System.out.println(nextStmt);
01437                     System.out.println(nextNextStmt);
01438                 */
01439             /* this should be redundant, but we do it */
01440             /* just in case. */
01441             if (lvalue.getType() != IntType.v())
01442             break;
01443 
01444             /* our strategy is as follows: eat the */
01445             /* two incrementing statements, push the lvalue to */
01446             /* be incremented & its holding local on a */
01447             /* plusPlusStack and deal with it in */
01448             /* emitLocal. */
01449                
01450             currentStackHeight = 0;
01451 
01452             /* emit statements as before */
01453             plusPlusValue = rvalue;
01454             plusPlusHolder = (Local)lvalue;
01455             plusPlusIncrementer = nextStmt;
01456             plusPlusState = 0;
01457 
01458             /* emit new statement with quickness */
01459             emitStmt(nextNextStmt);
01460 
01461             /* hm.  we didn't use local.  emit incrementage */
01462             if (plusPlusHolder != null)
01463             { emitStmt(stmt); emitStmt(nextStmt); }
01464 
01465                     if(currentStackHeight != 0)
01466                         throw new RuntimeException("Stack has height " + currentStackHeight + " after execution of stmt: " + s);
01467             contFlag = true;
01468             codeIt.next(); codeIt.next();
01469                   }
01470                 while(false);
01471         if (contFlag) 
01472             continue;
01473 
01474                 // emit this statement
01475                 {
01476                     currentStackHeight = 0;
01477                     emitStmt(s);
01478                         
01479                     if(currentStackHeight != 0)
01480                         throw new RuntimeException("Stack has height " + currentStackHeight + " after execution of stmt: " + s);
01481                 }
01482             }
01483 
01484             isEmittingMethodCode = false;
01485             
01486             code.set(stackLimitIndex, "    .limit stack " + maxStackHeight);
01487         }
01488 
01489         // Emit epilogue
01490             emit(".end method");
01491 
01492     }
01493     void emitStmt(Stmt stmt)
01494     {
01495         stmt.apply(new AbstractStmtSwitch()
01496         {
01497             public void caseAssignStmt(AssignStmt s)
01498             {
01499                 emitAssignStmt(s);
01500             }
01501 
01502             public void caseIdentityStmt(IdentityStmt s)
01503             {
01504                 if(s.getRightOp() instanceof CaughtExceptionRef &&
01505                     s.getLeftOp() instanceof Local)
01506                 {
01507                     int slot = ((Integer) localToSlot.get(s.getLeftOp())).intValue();
01508 
01509                     modifyStackHeight(1); // simulate the pushing of the exception onto the 
01510                                           // stack by the jvm
01511                     emit("astore " + slot, -1);
01512                 }
01513             }
01514 
01515             public void caseBreakpointStmt(BreakpointStmt s)
01516             {
01517                 emit("breakpoint", 0);
01518             }
01519 
01520             public void caseInvokeStmt(InvokeStmt s)
01521             {
01522                 emitValue(s.getInvokeExpr());
01523 
01524                 Type returnType = ((InvokeExpr) s.getInvokeExpr()).getMethod().getReturnType();
01525 
01526                 if(!returnType.equals(VoidType.v()))
01527                 {
01528                     // Need to do some cleanup because this value is not used.
01529 
01530                     if(sizeOfType(returnType) == 1)
01531                         emit("pop", -1);
01532                     else
01533                         emit("pop2", -2);
01534                 }
01535             }
01536 
01537             public void defaultCase(Stmt s)
01538             {
01539                 throw new RuntimeException("invalid stmt: " + s);
01540             }
01541 
01542             public void caseEnterMonitorStmt(EnterMonitorStmt s)
01543             {
01544                 emitValue(s.getOp());
01545                 emit("monitorenter", -1);
01546             }
01547 
01548             public void caseExitMonitorStmt(ExitMonitorStmt s)
01549             {
01550                 emitValue(s.getOp());
01551                 emit("monitorexit", -1);
01552             }
01553 
01554             public void caseGotoStmt(GotoStmt s)
01555             {
01556                 if(isNextGotoAJsr)
01557                 {
01558                     emit("jsr " + stmtToLabel.get(s.getTarget()));
01559                     isNextGotoAJsr = false;
01560 
01561                     subroutineToReturnAddressSlot.put(s.getTarget(), new Integer(returnAddressSlot));
01562                 }
01563                 else
01564                     emit("goto " + stmtToLabel.get(s.getTarget()));
01565             }
01566 
01567 
01568             public void caseIfStmt(IfStmt s)
01569             {
01570                 emitIfStmt(s);
01571             }
01572 
01573             public void caseLookupSwitchStmt(LookupSwitchStmt s)
01574             {
01575                 emitValue(s.getKey());
01576                 emit("lookupswitch", -1);
01577 
01578                 List lookupValues = s.getLookupValues();
01579                 List targets = s.getTargets();
01580 
01581                 for(int i = 0; i < lookupValues.size(); i++)
01582                     emit("  " + lookupValues.get(i) + " : " + stmtToLabel.get(targets.get(i)));
01583 
01584                 emit("  default : " + stmtToLabel.get(s.getDefaultTarget()));
01585             }
01586 
01587             public void caseNopStmt(NopStmt s)
01588             {
01589                 emit("nop", 0);
01590             }
01591 
01592             public void caseRetStmt(RetStmt s)
01593             {
01594                 emit("ret " + localToSlot.get(s.getStmtAddress()), 0);
01595             }
01596 
01597             public void caseReturnStmt(ReturnStmt s)
01598             {
01599                 emitValue(s.getReturnValue());
01600 
01601                 Value returnValue = s.getReturnValue();
01602 
01603                 returnValue.getType().apply(new TypeSwitch()
01604                 {
01605                     public void defaultCase(Type t)
01606                     {
01607                         throw new RuntimeException("invalid return type " + t.toString());
01608                      }
01609 
01610                      public void caseDoubleType(DoubleType t)
01611                      {
01612                         emit("dreturn", -2);
01613                      }
01614 
01615                      public void caseFloatType(FloatType t)
01616                      {
01617                         emit("freturn", -1);
01618                      }
01619 
01620                      public void caseIntType(IntType t)
01621                      {
01622                         emit("ireturn", -1);
01623                      }
01624 
01625                      public void caseByteType(ByteType t)
01626                      {
01627                         emit("ireturn", -1);
01628                      }
01629 
01630                      public void caseShortType(ShortType t)
01631                      {
01632                         emit("ireturn", -1);
01633                      }
01634 
01635                      public void caseCharType(CharType t)
01636                      {
01637                         emit("ireturn", -1);
01638                      }
01639 
01640                      public void caseBooleanType(BooleanType t)
01641                      {
01642                         emit("ireturn", -1);
01643                      }
01644 
01645                      public void caseLongType(LongType t)
01646                      {
01647                         emit("lreturn", -2);
01648                      }
01649 
01650                      public void caseArrayType(ArrayType t)
01651                      {
01652                         emit("areturn", -1);
01653                      }
01654 
01655                      public void caseRefType(RefType t)
01656                      {
01657                         emit("areturn", -1);
01658                      }
01659 
01660                      public void caseNullType(NullType t)
01661                      {
01662                         emit("areturn", -1);
01663                      }
01664 
01665                 });
01666             }
01667 
01668             public void caseReturnVoidStmt(ReturnVoidStmt s)
01669             {
01670                 emit("return", 0);
01671             }
01672 
01673             public void caseTableSwitchStmt(TableSwitchStmt s)
01674             {
01675                 emitValue(s.getKey());
01676                 emit("tableswitch " + s.getLowIndex() + " ; high = " + s.getHighIndex(), -1);
01677 
01678                 List targets = s.getTargets();
01679 
01680                 for(int i = 0; i < targets.size(); i++)
01681                     emit("  " + stmtToLabel.get(targets.get(i)));
01682 
01683                 emit("default : " + stmtToLabel.get(s.getDefaultTarget()));
01684             }
01685 
01686             public void caseThrowStmt(ThrowStmt s)
01687             {
01688                 emitValue(s.getOp());
01689                 emit("athrow", -1);
01690             }
01691         });
01692     }
01693     void emitValue(Value value)
01694     {
01695         value.apply(new AbstractJimpleValueSwitch()
01696         {
01697             public void caseAddExpr(AddExpr v)
01698             {
01699                 emitValue(v.getOp1());
01700                 emitValue(v.getOp2());
01701 
01702                 v.getType().apply(new TypeSwitch()
01703                 {
01704                     private void handleIntCase()
01705                     {
01706                         emit("iadd", -1);
01707                     }
01708             
01709                     public void caseIntType(IntType t) { handleIntCase(); }
01710             public void caseBooleanType(BooleanType t) { handleIntCase(); }
01711             public void caseShortType(ShortType t) { handleIntCase(); }
01712             public void caseCharType(CharType t) { handleIntCase(); }
01713             public void caseByteType(ByteType t) { handleIntCase(); }
01714 
01715                     public void caseLongType(LongType t)
01716                     {
01717                         emit("ladd", -2);
01718                     }
01719 
01720                     public void caseDoubleType(DoubleType t)
01721                     {
01722                         emit("dadd", -2);
01723                     }
01724 
01725                     public void caseFloatType(FloatType t)
01726                     {
01727                         emit("fadd", -1);
01728                     }
01729 
01730                     public void defaultCase(Type t)
01731                     {
01732                         throw new RuntimeException("Invalid argument type for add");
01733                     }
01734                 });
01735 
01736             }
01737 
01738             public void caseAndExpr(AndExpr v)
01739             {
01740                 emitValue(v.getOp1());
01741                 emitValue(v.getOp2());
01742 
01743                 v.getType().apply(new TypeSwitch()
01744                 {
01745                     private void handleIntCase()
01746                     {
01747                         emit("iand", -1);
01748                     }
01749 
01750                     public void caseIntType(IntType t) { handleIntCase(); }
01751             public void caseBooleanType(BooleanType t) { handleIntCase(); }
01752             public void caseShortType(ShortType t) { handleIntCase(); }
01753             public void caseCharType(CharType t) { handleIntCase(); }
01754             public void caseByteType(ByteType t) { handleIntCase(); }
01755 
01756                     public void caseLongType(LongType t)
01757                     {
01758                         emit("land", -2);
01759                     }
01760 
01761                     public void defaultCase(Type t)
01762                     {
01763                         throw new RuntimeException("Invalid argument type for and");
01764                     }
01765                 });
01766             }
01767 
01768             public void caseArrayRef(ArrayRef v)
01769             {
01770                 emitValue(v.getBase());
01771                 emitValue(v.getIndex());
01772 
01773                 v.getType().apply(new TypeSwitch()
01774                 {
01775                     public void caseArrayType(ArrayType ty)
01776                     {
01777                         emit("aaload", -1);
01778                     }
01779 
01780                     public void caseBooleanType(BooleanType ty)
01781                     {
01782                         emit("baload", -1);
01783                     }
01784 
01785                     public void caseByteType(ByteType ty)
01786                     {
01787                         emit("baload", -1);
01788                     }
01789 
01790                     public void caseCharType(CharType ty)
01791                     {
01792                         emit("caload", -1);
01793                     }
01794 
01795                     public void defaultCase(Type ty)
01796                     {
01797                         throw new RuntimeException("invalid base type");
01798                     }
01799 
01800                     public void caseDoubleType(DoubleType ty)
01801                     {
01802                         emit("daload", 0);
01803                     }
01804 
01805                     public void caseFloatType(FloatType ty)
01806                     {
01807                         emit("faload", -1);
01808                     }
01809 
01810                     public void caseIntType(IntType ty)
01811                     {
01812                         emit("iaload", -1);
01813                     }
01814 
01815                     public void caseLongType(LongType ty)
01816                     {
01817                         emit("laload", 0);
01818                     }
01819 
01820                     public void caseNullType(NullType ty)
01821                     {
01822                         emit("aaload", -1);
01823                     }
01824                     public void caseRefType(RefType ty)
01825                     {
01826                         emit("aaload", -1);
01827                     }
01828 
01829                     public void caseShortType(ShortType ty)
01830                     {
01831                         emit("saload", -1);
01832                     }
01833                 });
01834             }
01835 
01836             public void caseCastExpr(final CastExpr v)
01837             {
01838                 final Type toType = v.getCastType();
01839                 final Type fromType = v.getOp().getType();
01840 
01841                 emitValue(v.getOp());
01842 
01843                 if(toType instanceof RefType)
01844                     emit("checkcast " + slashify(toType.toString()), 0);
01845                 else if(toType instanceof ArrayType)
01846                     emit("checkcast " + jasminDescriptorOf(toType), 0);
01847                 else {
01848                     fromType.apply(new TypeSwitch()
01849                     {
01850                         public void defaultCase(Type ty)
01851                         {
01852                             throw new RuntimeException("invalid fromType " + fromType);
01853                         }
01854 
01855                         public void caseDoubleType(DoubleType ty)
01856                         {
01857                             if(toType.equals(IntType.v()))
01858                                 emit("d2i", -1);
01859                             else if(toType.equals(LongType.v()))
01860                                 emit("d2l", 0);
01861                             else if(toType.equals(FloatType.v()))
01862                                 emit("d2f", -1);
01863                             else
01864                                 throw new RuntimeException("invalid toType from double: " + toType);
01865                         }
01866 
01867                         public void caseFloatType(FloatType ty)
01868                         {
01869                             if(toType.equals(IntType.v()))
01870                                 emit("f2i", 0);
01871                             else if(toType.equals(LongType.v()))
01872                                 emit("f2l", 1);
01873                             else if(toType.equals(DoubleType.v()))
01874                                 emit("f2d", 1);
01875                             else
01876                                 throw new RuntimeException("invalid toType from float: " + toType);
01877                         }
01878 
01879                         public void caseIntType(IntType ty)
01880                         {
01881                 emitIntToTypeCast();
01882             }
01883 
01884             public void caseBooleanType(BooleanType ty)
01885             {
01886                 emitIntToTypeCast();
01887             }
01888 
01889                         public void caseByteType(ByteType ty)
01890                         {
01891                 emitIntToTypeCast();
01892             }
01893 
01894                         public void caseCharType(CharType ty)
01895                         {
01896                 emitIntToTypeCast();
01897             }
01898 
01899                         public void caseShortType(ShortType ty)
01900                         {
01901                 emitIntToTypeCast();
01902             }
01903 
01904             private void emitIntToTypeCast()
01905             {
01906                             if(toType.equals(ByteType.v()))
01907                                 emit("i2b", 0);
01908                             else if(toType.equals(CharType.v()))
01909                                 emit("i2c", 0);
01910                             else if(toType.equals(ShortType.v()))
01911                                 emit("i2s", 0);
01912                             else if(toType.equals(FloatType.v()))
01913                                 emit("i2f", 0);
01914                             else if(toType.equals(LongType.v()))
01915                                 emit("i2l", 1);
01916                             else if(toType.equals(DoubleType.v()))
01917                                 emit("i2d", 1);
01918                 else if(toType.equals(IntType.v()))
01919                     ;  // this shouldn't happen?
01920                             else
01921                                 throw new RuntimeException("invalid toType from int: " + toType +
01922                                     " " + v.toString());
01923                         }
01924 
01925                         public void caseLongType(LongType ty)
01926                         {
01927                             if(toType.equals(IntType.v()))
01928                                 emit("l2i", -1);
01929                             else if(toType.equals(FloatType.v()))
01930                                 emit("l2f", -1);
01931                             else if(toType.equals(DoubleType.v()))
01932                                 emit("l2d", 0);
01933                 else if(toType.equals(ByteType.v()))
01934                   { emit("l2i", -1); emitIntToTypeCast(); }
01935                 else if(toType.equals(ShortType.v()))
01936                   { emit("l2i", -1); emitIntToTypeCast(); }
01937                 else if(toType.equals(CharType.v()))
01938                   { emit("l2i", -1); emitIntToTypeCast(); }
01939                 else if(toType.equals(BooleanType.v()))
01940                   { emit("l2i", -1); emitIntToTypeCast(); }
01941                             else
01942                                 throw new RuntimeException("invalid toType from long: " + toType);
01943                         }
01944                     });
01945                 }
01946             }
01947 
01948             public void caseCmpExpr(CmpExpr v)
01949             {
01950                 emitValue(v.getOp1());
01951                 emitValue(v.getOp2());
01952                 emit("lcmp", -3);
01953             }
01954 
01955             public void caseCmpgExpr(CmpgExpr v)
01956             {
01957                 emitValue(v.getOp1());
01958                 emitValue(v.getOp2());
01959 
01960                 if(v.getOp1().getType().equals(FloatType.v()))
01961                     emit("fcmpg", -1);
01962                 else
01963                     emit("dcmpg", -3);
01964             }
01965 
01966             public void caseCmplExpr(CmplExpr v)
01967             {
01968                 emitValue(v.getOp1());
01969                 emitValue(v.getOp2());
01970 
01971                 if(v.getOp1().getType().equals(FloatType.v()))
01972                     emit("fcmpl", -1);
01973                 else
01974                     emit("dcmpl", -3);
01975             }
01976 
01977             public void defaultCase(Value v)
01978             {
01979                 throw new RuntimeException("Can't load value: " + v);
01980             }
01981 
01982             public void caseDivExpr(DivExpr v)
01983             {
01984                 emitValue(v.getOp1());
01985                 emitValue(v.getOp2());
01986 
01987                 v.getType().apply(new TypeSwitch()
01988                 {
01989                     private void handleIntCase()
01990                     {
01991                         emit("idiv", -1);
01992                     }
01993 
01994                     public void caseIntType(IntType t) { handleIntCase(); }
01995             public void caseBooleanType(BooleanType t) { handleIntCase(); }
01996             public void caseShortType(ShortType t) { handleIntCase(); }
01997             public void caseCharType(CharType t) { handleIntCase(); }
01998             public void caseByteType(ByteType t) { handleIntCase(); }
01999 
02000                     public void caseLongType(LongType t)
02001                     {
02002                         emit("ldiv", -2);
02003                     }
02004 
02005                     public void caseDoubleType(DoubleType t)
02006                     {
02007                         emit("ddiv", -2);
02008                     }
02009 
02010                     public void caseFloatType(FloatType t)
02011                     {
02012                         emit("fdiv", -1);
02013                     }
02014 
02015                     public void defaultCase(Type t)
02016                     {
02017                         throw new RuntimeException("Invalid argument type for div");
02018                     }
02019                 });
02020 
02021             }
02022 
02023             public void caseDoubleConstant(DoubleConstant v)
02024             {
02025                 if(v.value == 0)
02026                     emit("dconst_0", 2);
02027                 else if(v.value == 1)
02028                     emit("dconst_1", 2);
02029                 else {
02030                     String s = v.toString();
02031                     
02032                     if(s.equals("Infinity"))
02033                         s="+DoubleInfinity";
02034                     if(s.equals("-Infinity"))
02035                         s="-DoubleInfinity";
02036                         
02037                     emit("ldc2_w " + s, 2);
02038                 }
02039             }
02040 
02041             public void caseFloatConstant(FloatConstant v)
02042             {
02043                 if(v.value == 0)
02044                     emit("fconst_0", 1);
02045                 else if(v.value == 1)
02046                     emit("fconst_1", 1);
02047                 else if(v.value == 2)
02048                     emit("fconst_2", 1);
02049                 else {
02050                     String s = v.toString();
02051                     
02052                     if(s.equals("Infinity"))
02053                         s="+FloatInfinity";
02054                     if(s.equals("-Infinity"))
02055                         s="-FloatInfinity";
02056                         
02057                     emit("ldc " + s, 1);
02058                 }
02059             }
02060 
02061 
02062             public void caseInstanceFieldRef(InstanceFieldRef v)
02063             {
02064                 emitValue(v.getBase());
02065 
02066                 emit("getfield " + slashify(v.getField().getDeclaringClass().getName()) + "/" +
02067                     v.getField().getName() + " " + jasminDescriptorOf(v.getField().getType()), 
02068                     -1 + sizeOfType(v.getField().getType()));
02069             }
02070 
02071             public void caseInstanceOfExpr(InstanceOfExpr v)
02072             {
02073                 emitValue(v.getOp());
02074 
02075                 emit("instanceof " + slashify(v.getCheckType().toString()), 0);
02076             }
02077 
02078             public void caseIntConstant(IntConstant v)
02079             {
02080                 if(v.value == -1)
02081                     emit("iconst_m1", 1);
02082                 else if(v.value >= 0 && v.value <= 5)
02083                     emit("iconst_" + v.value, 1);
02084                 else if(v.value >= Byte.MIN_VALUE && v.value <= Byte.MAX_VALUE)
02085                     emit("bipush " + v.value, 1);
02086                 else if(v.value >= Short.MIN_VALUE && v.value <= Short.MAX_VALUE)
02087                     emit("sipush " + v.value, 1);
02088                 else
02089                     emit("ldc " + v.toString(), 1);
02090             }
02091 
02092             public void caseInterfaceInvokeExpr(InterfaceInvokeExpr v)
02093             {
02094                 SootMethod m = v.getMethod();
02095 
02096                 emitValue(v.getBase());
02097 
02098                 for(int i = 0; i < m.getParameterCount(); i++)
02099                     emitValue(v.getArg(i));
02100 
02101                 emit("invokeinterface " + slashify(m.getDeclaringClass().getName()) + "/" +
02102                     m.getName() + jasminDescriptorOf(m) + " " + (argCountOf(m) + 1),
02103                     -(argCountOf(m) + 1) + sizeOfType(m.getReturnType()));
02104             }
02105 
02106             public void caseLengthExpr(LengthExpr v)
02107             {
02108                 emitValue(v.getOp());
02109                 emit("arraylength", 0);
02110             }
02111 
02112             public void caseLocal(Local v)
02113             {
02114         emitLocal(v);
02115             }
02116 
02117             public void caseLongConstant(LongConstant v)
02118             {
02119                 if(v.value == 0)
02120                     emit("lconst_0", 2);
02121                 else if(v.value == 1)
02122                     emit("lconst_1", 2);
02123                 else
02124                     emit("ldc2_w " + v.toString(), 2);
02125             }
02126 
02127 
02128             public void caseMulExpr(MulExpr v)
02129             {
02130                 emitValue(v.getOp1());
02131                 emitValue(v.getOp2());
02132 
02133                 v.getType().apply(new TypeSwitch()
02134                 {
02135                     private void handleIntCase()
02136                     {
02137                         emit("imul", -1);
02138                     }
02139 
02140                     public void caseIntType(IntType t) { handleIntCase(); }
02141             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02142             public void caseShortType(ShortType t) { handleIntCase(); }
02143             public void caseCharType(CharType t) { handleIntCase(); }
02144             public void caseByteType(ByteType t) { handleIntCase(); }
02145 
02146                     public void caseLongType(LongType t)
02147                     {
02148                         emit("lmul", -2);
02149                     }
02150 
02151                     public void caseDoubleType(DoubleType t)
02152                     {
02153                         emit("dmul", -2);
02154                     }
02155 
02156                     public void caseFloatType(FloatType t)
02157                     {
02158                         emit("fmul", -1);
02159                     }
02160 
02161                     public void defaultCase(Type t)
02162                     {
02163                         throw new RuntimeException("Invalid argument type for mul");
02164                     }
02165                 });
02166             }
02167 
02168             public void caseLtExpr(LtExpr v)
02169             {
02170                 emitValue(v.getOp1());
02171                 emitValue(v.getOp2());
02172 
02173                 v.getOp1().getType().apply(new TypeSwitch()
02174                 {
02175                     public void caseDoubleType(DoubleType t)
02176                     {
02177                         emit("dcmpg", -3);
02178                         emitBooleanBranch("iflt");
02179                     }
02180 
02181                     public void caseFloatType(FloatType t)
02182                     {
02183                         emit("fcmpg", -1);
02184                         emitBooleanBranch("iflt");
02185                     }
02186 
02187                     private void handleIntCase()
02188                     {
02189                         emit("if_icmplt", -2);
02190                     }
02191 
02192 
02193                     public void caseIntType(IntType t) { handleIntCase(); }
02194             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02195             public void caseShortType(ShortType t) { handleIntCase(); }
02196             public void caseCharType(CharType t) { handleIntCase(); }
02197             public void caseByteType(ByteType t) { handleIntCase(); }
02198 
02199                     public void caseLongType(LongType t)
02200                     {
02201                         emit("lcmp", -3);
02202                         emitBooleanBranch("iflt");
02203                     }
02204 
02205                     public void defaultCase(Type t)
02206                     {
02207                         throw new RuntimeException("invalid type");
02208                     }
02209                 });
02210             }
02211 
02212             public void caseLeExpr(LeExpr v)
02213             {
02214                 emitValue(v.getOp1());
02215                 emitValue(v.getOp2());
02216 
02217                 v.getOp1().getType().apply(new TypeSwitch()
02218                 {
02219                     public void caseDoubleType(DoubleType t)
02220                     {
02221                         emit("dcmpg", -3);
02222                         emitBooleanBranch("ifle");
02223                     }
02224 
02225                     public void caseFloatType(FloatType t)
02226                     {
02227                         emit("fcmpg", -1);
02228                         emitBooleanBranch("ifle");
02229                     }
02230 
02231                     private void handleIntCase()
02232                     {
02233                         emit("if_icmple", -2);
02234                     }
02235 
02236                     public void caseIntType(IntType t) { handleIntCase(); }
02237             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02238             public void caseShortType(ShortType t) { handleIntCase(); }
02239             public void caseCharType(CharType t) { handleIntCase(); }
02240             public void caseByteType(ByteType t) { handleIntCase(); }
02241 
02242                     public void caseLongType(LongType t)
02243                     {
02244                         emit("lcmp", -3);
02245                         emitBooleanBranch("ifle");
02246                     }
02247 
02248                     public void defaultCase(Type t)
02249                     {
02250                         throw new RuntimeException("invalid type");
02251                     }
02252                 });
02253             }
02254 
02255             public void caseGtExpr(GtExpr v)
02256             {
02257                 emitValue(v.getOp1());
02258                 emitValue(v.getOp2());
02259 
02260                 v.getOp1().getType().apply(new TypeSwitch()
02261                 {
02262                     public void caseDoubleType(DoubleType t)
02263                     {
02264                         emit("dcmpg", -3);
02265                         emitBooleanBranch("ifgt");
02266                     }
02267 
02268                     public void caseFloatType(FloatType t)
02269                     {
02270                         emit("fcmpg", -1);
02271                         emitBooleanBranch("ifgt");
02272                     }
02273 
02274                     private void handleIntCase()
02275                     {
02276                         emit("if_icmpgt", -2);
02277                     }
02278 
02279                     public void caseIntType(IntType t) { handleIntCase(); }
02280             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02281             public void caseShortType(ShortType t) { handleIntCase(); }
02282             public void caseCharType(CharType t) { handleIntCase(); }
02283             public void caseByteType(ByteType t) { handleIntCase(); }
02284 
02285                     public void caseLongType(LongType t)
02286                     {
02287                         emit("lcmp", -3);
02288                         emitBooleanBranch("ifgt");
02289                     }
02290 
02291                     public void defaultCase(Type t)
02292                     {
02293                         throw new RuntimeException("invalid type");
02294                     }
02295                 });
02296             }
02297 
02298             public void caseGeExpr(GeExpr v)
02299             {
02300                 emitValue(v.getOp1());
02301                 emitValue(v.getOp2());
02302 
02303                 v.getOp1().getType().apply(new TypeSwitch()
02304                 {
02305                     public void caseDoubleType(DoubleType t)
02306                     {
02307                         emit("dcmpg", -3);
02308                         emitBooleanBranch("ifge");
02309                     }
02310 
02311                     public void caseFloatType(FloatType t)
02312                     {
02313                         emit("fcmpg", -1);
02314                         emitBooleanBranch("ifge");
02315                     }
02316 
02317                     private void handleIntCase()
02318                     {
02319                         emit("if_icmpge", -2);
02320                     }
02321 
02322                     public void caseIntType(IntType t) { handleIntCase(); }
02323             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02324             public void caseShortType(ShortType t) { handleIntCase(); }
02325             public void caseCharType(CharType t) { handleIntCase(); }
02326             public void caseByteType(ByteType t) { handleIntCase(); }
02327 
02328                     public void caseLongType(LongType t)
02329                     {
02330                         emit("lcmp", -3);
02331                         emitBooleanBranch("ifge");
02332                     }
02333 
02334                     public void defaultCase(Type t)
02335                     {
02336                         throw new RuntimeException("invalid type");
02337                     }
02338                 });
02339             }
02340 
02341             public void caseNeExpr(NeExpr v)
02342             {
02343                 emitValue(v.getOp1());
02344                 emitValue(v.getOp2());
02345 
02346                 v.getOp1().getType().apply(new TypeSwitch()
02347                 {
02348                     public void caseDoubleType(DoubleType t)
02349                     {
02350                         emit("dcmpg", -3);
02351                         emit("iconst_0", 1);
02352                         emitBooleanBranch("if_icmpne");
02353                     }
02354 
02355                     public void caseFloatType(FloatType t)
02356                     {
02357                         emit("fcmpg", -1);
02358                         emit("iconst_0", 1);
02359                         emitBooleanBranch("if_icmpne");
02360                     }
02361 
02362                     private void handleIntCase()
02363                     {
02364                         emit("if_icmpne", -2);
02365                     }
02366 
02367                     public void caseIntType(IntType t) { handleIntCase(); }
02368             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02369             public void caseShortType(ShortType t) { handleIntCase(); }
02370             public void caseCharType(CharType t) { handleIntCase(); }
02371             public void caseByteType(ByteType t) { handleIntCase(); }
02372 
02373                     public void caseLongType(LongType t)
02374                     {
02375                         emit("lcmp", -3);
02376                         emit("iconst_0", 1);
02377                         emitBooleanBranch("if_icmpne");
02378                     }
02379 
02380                     public void caseArrayType(ArrayType t)
02381                     {
02382                         emitBooleanBranch("if_acmpne");
02383                     }
02384 
02385                     public void caseRefType(RefType t)
02386                     {
02387                         emitBooleanBranch("if_acmpne");
02388                     }
02389 
02390                     public void defaultCase(Type t)
02391                     {
02392                         throw new RuntimeException("invalid type");
02393                     }
02394                 });
02395             }
02396 
02397             public void caseEqExpr(EqExpr v)
02398             {
02399                 emitValue(v.getOp1());
02400                 emitValue(v.getOp2());
02401 
02402                 v.getOp1().getType().apply(new TypeSwitch()
02403                 {
02404                     public void caseDoubleType(DoubleType t)
02405                     {
02406                         emit("dcmpg", -3);
02407                         emit("iconst_0", 1);
02408                         emitBooleanBranch("if_icmpeq");
02409                     }
02410 
02411                     public void caseFloatType(FloatType t)
02412                     {
02413                         emit("fcmpg", -3);
02414                         emit("iconst_0", 1);
02415                         emitBooleanBranch("if_icmpeq");
02416                     }
02417 
02418                     private void handleIntCase()
02419                     {
02420                         emit("if_icmpeq", -2);
02421                     }
02422 
02423                     public void caseIntType(IntType t) { handleIntCase(); }
02424             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02425             public void caseShortType(ShortType t) { handleIntCase(); }
02426             public void caseCharType(CharType t) { handleIntCase(); }
02427             public void caseByteType(ByteType t) { handleIntCase(); }
02428 
02429                     public void caseLongType(LongType t)
02430                     {
02431                         emit("lcmp", -3);
02432                         emit("iconst_0", 1);
02433                         emitBooleanBranch("if_icmpeq");
02434                     }
02435 
02436                     public void caseArrayType(ArrayType t)
02437                     {
02438                         emitBooleanBranch("if_acmpeq");
02439                     }
02440 
02441                     public void casbeRefType(RefType t)
02442                     {
02443                         emitBooleanBranch("if_acmpeq");
02444                     }
02445 
02446                     public void defaultCase(Type t)
02447                     {
02448                         throw new RuntimeException("invalid type");
02449                     }
02450                 });
02451             }
02452 
02453             public void caseNegExpr(NegExpr v)
02454             {
02455                 emitValue(v.getOp());
02456 
02457                 v.getType().apply(new TypeSwitch()
02458                 {
02459                     private void handleIntCase()
02460                     {
02461                         emit("ineg", 0);
02462                     }
02463 
02464                     public void caseIntType(IntType t) { handleIntCase(); }
02465             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02466             public void caseShortType(ShortType t) { handleIntCase(); }
02467             public void caseCharType(CharType t) { handleIntCase(); }
02468             public void caseByteType(ByteType t) { handleIntCase(); }
02469 
02470                     public void caseLongType(LongType t)
02471                     {
02472                         emit("lneg", 0);
02473                     }
02474 
02475                     public void caseDoubleType(DoubleType t)
02476                     {
02477                         emit("dneg", 0);
02478                     }
02479 
02480                     public void caseFloatType(FloatType t)
02481                     {
02482                         emit("fneg", 0);
02483                     }
02484 
02485                     public void defaultCase(Type t)
02486                     {
02487                         throw new RuntimeException("Invalid argument type for neg");
02488                     }
02489                 });
02490 
02491             }
02492 
02493             public void caseNewArrayExpr(NewArrayExpr v)
02494             {
02495                 Value size = v.getSize();
02496 
02497                 emitValue(size);
02498 
02499                 if(v.getBaseType() instanceof RefType)
02500                     emit("anewarray " + slashify(v.getBaseType().toString()), 0);
02501                 else if(v.getBaseType() instanceof ArrayType)
02502                     emit("anewarray " + jasminDescriptorOf(v.getBaseType()), 0);
02503                 else
02504                     emit("newarray " + v.getBaseType().toString(), 0);
02505             }
02506 
02507             public void caseNewMultiArrayExpr(NewMultiArrayExpr v)
02508             {
02509                 List sizes = v.getSizes();
02510 
02511                 for(int i = 0; i < sizes.size(); i++)
02512                     emitValue((Value) sizes.get(i));
02513 
02514                 emit("multianewarray " + jasminDescriptorOf(v.getBaseType()) + " " + sizes.size(), -sizes.size() + 1);
02515             }
02516 
02517             public void caseNewExpr(NewExpr v)
02518             {
02519                 emit("new " + slashify(v.getBaseType().toString()), 1);
02520             }
02521 
02522             public void caseNewInvokeExpr(NewInvokeExpr v)
02523             {
02524                 emit("new " + slashify(v.getBaseType().toString()), 1);
02525                 emit("dup", 1);
02526                 
02527                 SootMethod m = v.getMethod();
02528 
02529                 // emitValue(v.getBase());
02530                 // already on the stack
02531                 
02532                 for(int i = 0; i < m.getParameterCount(); i++)
02533                     emitValue(v.getArg(i));
02534 
02535                 emit("invokespecial " + slashify(m.getDeclaringClass().getName()) + "/" +
02536                     m.getName() + jasminDescriptorOf(m),
02537                     -(argCountOf(m) + 1) + sizeOfType(m.getReturnType()));
02538             }
02539 
02540             public void caseNullConstant(NullConstant v)
02541             {
02542                 emit("aconst_null", 1);
02543             }
02544 
02545             public void caseOrExpr(OrExpr v)
02546             {
02547                 emitValue(v.getOp1());
02548                 emitValue(v.getOp2());
02549 
02550                 v.getType().apply(new TypeSwitch()
02551                 {
02552                     private void handleIntCase()
02553                     {
02554                         emit("ior", -1);
02555                     }
02556 
02557                     public void caseIntType(IntType t) { handleIntCase(); }
02558             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02559             public void caseShortType(ShortType t) { handleIntCase(); }
02560             public void caseCharType(CharType t) { handleIntCase(); }
02561             public void caseByteType(ByteType t) { handleIntCase(); }
02562 
02563                     public void caseLongType(LongType t)
02564                     {
02565                         emit("lor", -2);
02566                     }
02567 
02568                     public void defaultCase(Type t)
02569                     {
02570                         throw new RuntimeException("Invalid argument type for or");
02571                     }
02572                 });
02573             }
02574 
02575             public void caseRemExpr(RemExpr v)
02576             {
02577                 emitValue(v.getOp1());
02578                 emitValue(v.getOp2());
02579 
02580                 v.getType().apply(new TypeSwitch()
02581                 {
02582                     private void handleIntCase()
02583                     {
02584                         emit("irem", -1);
02585                     }
02586 
02587                     public void caseIntType(IntType t) { handleIntCase(); }
02588             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02589             public void caseShortType(ShortType t) { handleIntCase(); }
02590             public void caseCharType(CharType t) { handleIntCase(); }
02591             public void caseByteType(ByteType t) { handleIntCase(); }
02592 
02593                     public void caseLongType(LongType t)
02594                     {
02595                         emit("lrem", -2);
02596                     }
02597 
02598                     public void caseDoubleType(DoubleType t)
02599                     {
02600                         emit("drem", -2);
02601                     }
02602 
02603                     public void caseFloatType(FloatType t)
02604                     {
02605                         emit("frem", -1);
02606                     }
02607 
02608                     public void defaultCase(Type t)
02609                     {
02610                         throw new RuntimeException("Invalid argument type for rem");
02611                     }
02612                 });
02613             }
02614 
02615             public void caseShlExpr(ShlExpr v)
02616             {
02617                 emitValue(v.getOp1());
02618                 emitValue(v.getOp2());
02619 
02620                 v.getType().apply(new TypeSwitch()
02621                 {
02622                     private void handleIntCase()
02623                     {
02624                         emit("ishl", -1);
02625                     }
02626 
02627                     public void caseIntType(IntType t) { handleIntCase(); }
02628             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02629             public void caseShortType(ShortType t) { handleIntCase(); }
02630             public void caseCharType(CharType t) { handleIntCase(); }
02631             public void caseByteType(ByteType t) { handleIntCase(); }
02632 
02633                     public void caseLongType(LongType t)
02634                     {
02635                         emit("lshl", -1);
02636                     }
02637 
02638                     public void defaultCase(Type t)
02639                     {
02640                         throw new RuntimeException("Invalid argument type for shl");
02641                     }
02642                 });
02643             }
02644 
02645             public void caseShrExpr(ShrExpr v)
02646             {
02647                 emitValue(v.getOp1());
02648                 emitValue(v.getOp2());
02649 
02650                 v.getType().apply(new TypeSwitch()
02651                 {
02652                     private void handleIntCase()
02653                     {
02654                         emit("ishr", -1);
02655                     }
02656 
02657                     public void caseIntType(IntType t) { handleIntCase(); }
02658             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02659             public void caseShortType(ShortType t) { handleIntCase(); }
02660             public void caseCharType(CharType t) { handleIntCase(); }
02661             public void caseByteType(ByteType t) { handleIntCase(); }
02662 
02663                     public void caseLongType(LongType t)
02664                     {
02665                         emit("lshr", -1);
02666                     }
02667 
02668                     public void defaultCase(Type t)
02669                     {
02670                         throw new RuntimeException("Invalid argument type for shr");
02671                     }
02672                 });
02673             }
02674 
02675             public void caseSpecialInvokeExpr(SpecialInvokeExpr v)
02676             {
02677                 SootMethod m = v.getMethod();
02678 
02679                 emitValue(v.getBase());
02680 
02681                 for(int i = 0; i < m.getParameterCount(); i++)
02682                     emitValue(v.getArg(i));
02683 
02684                 emit("invokespecial " + slashify(m.getDeclaringClass().getName()) + "/" +
02685                     m.getName() + jasminDescriptorOf(m),
02686                     -(argCountOf(m) + 1) + sizeOfType(m.getReturnType()));
02687             }
02688 
02689             public void caseStaticInvokeExpr(StaticInvokeExpr v)
02690             {
02691                 SootMethod m = v.getMethod();
02692 
02693                 for(int i = 0; i < m.getParameterCount(); i++)
02694                     emitValue(v.getArg(i));
02695 
02696                 emit("invokestatic " + slashify(m.getDeclaringClass().getName()) + "/" +
02697                     m.getName() + jasminDescriptorOf(m),
02698                     -(argCountOf(m)) + sizeOfType(m.getReturnType()));
02699             }
02700 
02701             public void caseStaticFieldRef(StaticFieldRef v)
02702             {
02703                 emit("getstatic " + slashify(v.getField().getDeclaringClass().getName()) + "/" +
02704                     v.getField().getName() + " " + jasminDescriptorOf(v.getField().getType()),
02705                     sizeOfType(v.getField().getType()));
02706             }
02707 
02708             public void caseStringConstant(StringConstant v)
02709             {
02710                 StringBuffer src = new StringBuffer(v.value);
02711                 StringBuffer dest = new StringBuffer();
02712 
02713                 for(int i = 0; i < src.length(); i++)
02714                 {
02715                     if(src.charAt(i) == '\"')
02716                         dest.append("\\\"");
02717                     else if(src.charAt(i) == '\'')
02718                         dest.append("\\\'");
02719                     else if(src.charAt(i) == '\\')
02720                         dest.append("\\\\");
02721                     else
02722                         dest.append(src.charAt(i));
02723                 }
02724 
02725                 emit("ldc " + '"' + dest.toString() + '"', 1);
02726             }
02727 
02728             public void caseSubExpr(SubExpr v)
02729             {
02730                 emitValue(v.getOp1());
02731                 emitValue(v.getOp2());
02732 
02733                 v.getType().apply(new TypeSwitch()
02734                 {
02735                     private void handleIntCase()
02736                     {
02737                         emit("isub", -1);
02738                     }
02739 
02740                     public void caseIntType(IntType t) { handleIntCase(); }
02741             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02742             public void caseShortType(ShortType t) { handleIntCase(); }
02743             public void caseCharType(CharType t) { handleIntCase(); }
02744             public void caseByteType(ByteType t) { handleIntCase(); }
02745 
02746                     public void caseLongType(LongType t)
02747                     {
02748                         emit("lsub", -2);
02749                     }
02750 
02751                     public void caseDoubleType(DoubleType t)
02752                     {
02753                         emit("dsub", -2);
02754                     }
02755 
02756                     public void caseFloatType(FloatType t)
02757                     {
02758                         emit("fsub", -1);
02759                     }
02760 
02761                     public void defaultCase(Type t)
02762                     {
02763                         throw new RuntimeException("Invalid argument type for sub");
02764                     }
02765                 });
02766 
02767             }
02768 
02769             public void caseUshrExpr(UshrExpr v)
02770             {
02771                 emitValue(v.getOp1());
02772                 emitValue(v.getOp2());
02773 
02774                 v.getType().apply(new TypeSwitch()
02775                 {
02776                     private void handleIntCase()
02777                     {
02778                         emit("iushr", -1);
02779                     }
02780 
02781                     public void caseIntType(IntType t) { handleIntCase(); }
02782             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02783             public void caseShortType(ShortType t) { handleIntCase(); }
02784             public void caseCharType(CharType t) { handleIntCase(); }
02785             public void caseByteType(ByteType t) { handleIntCase(); }
02786 
02787                     public void caseLongType(LongType t)
02788                     {
02789                         emit("lushr", -1);
02790                     }
02791 
02792                     public void defaultCase(Type t)
02793                     {
02794                         throw new RuntimeException("Invalid argument type for ushr");
02795                     }
02796                 });
02797             }
02798 
02799             public void caseVirtualInvokeExpr(VirtualInvokeExpr v)
02800             {
02801                 SootMethod m = v.getMethod();
02802 
02803                 emitValue(v.getBase());
02804 
02805                 for(int i = 0; i < m.getParameterCount(); i++)
02806                     emitValue(v.getArg(i));
02807 
02808                 emit("invokevirtual " + slashify(m.getDeclaringClass().getName()) + "/" +
02809                     m.getName() + jasminDescriptorOf(m),
02810                     -(argCountOf(m) + 1) + sizeOfType(m.getReturnType()));
02811             }
02812 
02813             public void caseXorExpr(XorExpr v)
02814             {
02815                 emitValue(v.getOp1());
02816                 emitValue(v.getOp2());
02817 
02818                 v.getType().apply(new TypeSwitch()
02819                 {
02820             private void handleIntCase() 
02821                     { 
02822                 emit ("ixor", -1); 
02823                     }
02824 
02825                     public void caseIntType(IntType t) { handleIntCase(); }
02826             public void caseBooleanType(BooleanType t) { handleIntCase(); }
02827             public void caseShortType(ShortType t) { handleIntCase(); }
02828             public void caseCharType(CharType t) { handleIntCase(); }
02829             public void caseByteType(ByteType t) { handleIntCase(); }
02830 
02831                     public void caseLongType(LongType t)
02832                     {
02833                         emit("lxor", -2);
02834                     }
02835 
02836                     public void defaultCase(Type t)
02837                     {
02838                         throw new RuntimeException("Invalid argument type for xor");
02839                     }
02840                 });
02841             }
02842         });
02843     }
02844     String jasminDescriptorOf(SootMethod m)
02845     {
02846         StringBuffer buffer = new StringBuffer();
02847 
02848         buffer.append("(");
02849 
02850         // Add methods parameters
02851         {
02852             Iterator typeIt = m.getParameterTypes().iterator();
02853 
02854             while(typeIt.hasNext())
02855             {
02856                 Type t = (Type) typeIt.next();
02857 
02858                 buffer.append(jasminDescriptorOf(t));
02859             }
02860         }
02861 
02862         buffer.append(")");
02863 
02864         buffer.append(jasminDescriptorOf(m.getReturnType()));
02865 
02866         return buffer.toString();
02867     }
02868     String jasminDescriptorOf(Type type)
02869     {
02870         TypeSwitch sw;
02871 
02872         type.apply(sw = new TypeSwitch()
02873         {
02874             public void caseBooleanType(BooleanType t)
02875             {
02876                 setResult("Z");
02877             }
02878 
02879             public void caseByteType(ByteType t)
02880             {
02881                 setResult("B");
02882             }
02883 
02884             public void caseCharType(CharType t)
02885             {
02886                 setResult("C");
02887             }
02888 
02889             public void caseDoubleType(DoubleType t)
02890             {
02891                 setResult("D");
02892             }
02893 
02894             public void caseFloatType(FloatType t)
02895             {
02896                 setResult("F");
02897             }
02898 
02899             public void caseIntType(IntType t)
02900             {
02901                 setResult("I");
02902             }
02903 
02904             public void caseLongType(LongType t)
02905             {
02906                 setResult("J");
02907             }
02908 
02909             public void caseShortType(ShortType t)
02910             {
02911                 setResult("S");
02912             }
02913 
02914             public void defaultCase(Type t)
02915             {
02916                 throw new RuntimeException("Invalid type: " + t);
02917             }
02918 
02919             public void caseArrayType(ArrayType t)
02920             {
02921                 StringBuffer buffer = new StringBuffer();
02922 
02923                 for(int i = 0; i < t.numDimensions; i++)
02924                     buffer.append("[");
02925 
02926                 setResult(buffer.toString() + jasminDescriptorOf(t.baseType));
02927             }
02928 
02929             public void caseRefType(RefType t)
02930             {
02931                 setResult("L" + t.className.replace('.', '/') + ";");
02932             }
02933 
02934             public void caseVoidType(VoidType t)
02935             {
02936                 setResult("V");
02937             }
02938         });
02939 
02940         return (String) sw.getResult();
02941 
02942     }
02943     void modifyStackHeight(int stackChange)
02944     {
02945         currentStackHeight += stackChange;
02946         
02947         if(currentStackHeight < 0)
02948             throw new RuntimeException("Stack height is negative!");
02949             
02950         if(currentStackHeight > maxStackHeight)
02951             maxStackHeight = currentStackHeight;
02952     }
02953     void okayEmit(String s)
02954     {
02955         if(isEmittingMethodCode && !s.endsWith(":"))
02956             code.add("    " + s);
02957         else
02958             code.add(s);
02959 
02960 //        System.out.println(s);
02961     }
02962     public void print(PrintWriter out)
02963     {
02964         Iterator it = code.iterator();
02965 
02966         while(it.hasNext())
02967             out.println(it.next());
02968     }
02969     int sizeOfType(Type t)
02970     {
02971         if(t instanceof DoubleType || t instanceof LongType)
02972             return 2;
02973         else if(t instanceof VoidType)
02974             return 0;
02975         else
02976             return 1;
02977     }
02978     String slashify(String s)
02979     {
02980         return s.replace('.', '/');
02981     }
02982 }

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