Home » javassist-sources » javassist » bytecode » [javadoc | source]

    1   /*
    2    * Javassist, a Java-bytecode translator toolkit.
    3    * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved.
    4    *
    5    * The contents of this file are subject to the Mozilla Public License Version
    6    * 1.1 (the "License"); you may not use this file except in compliance with
    7    * the License.  Alternatively, the contents of this file may be used under
    8    * the terms of the GNU Lesser General Public License Version 2.1 or later.
    9    *
   10    * Software distributed under the License is distributed on an "AS IS" basis,
   11    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   12    * for the specific language governing rights and limitations under the
   13    * License.
   14    */
   15   package javassist.bytecode;
   16   
   17   import java.io.PrintStream;
   18   
   19   import javassist.CtMethod;
   20   
   21   /**
   22    * Simple utility class for printing the instructions of a method.
   23    *
   24    * @author Jason T. Greene
   25    */
   26   public class InstructionPrinter implements Opcode {
   27   
   28       private final static String opcodes[] = Mnemonic.OPCODE;
   29       private final PrintStream stream;
   30   
   31       public InstructionPrinter(PrintStream stream) {
   32           this.stream = stream;
   33       }
   34   
   35       public static void print(CtMethod method, PrintStream stream) {
   36           (new InstructionPrinter(stream)).print(method);
   37       }
   38   
   39       public void print(CtMethod method) {
   40           MethodInfo info = method.getMethodInfo2();
   41           ConstPool pool = info.getConstPool();
   42           CodeAttribute code = info.getCodeAttribute();
   43           if (code == null)
   44               return;
   45   
   46           CodeIterator iterator = code.iterator();
   47           while (iterator.hasNext()) {
   48               int pos;
   49               try {
   50                   pos = iterator.next();
   51               } catch (BadBytecode e) {
   52                   throw new RuntimeException(e);
   53               }
   54   
   55               stream.println(pos + ": " + instructionString(iterator, pos, pool));
   56           }
   57       }
   58   
   59       public static String instructionString(CodeIterator iter, int pos, ConstPool pool) {
   60           int opcode = iter.byteAt(pos);
   61   
   62           if (opcode > opcodes.length || opcode < 0)
   63               throw new IllegalArgumentException("Invalid opcode, opcode: " + opcode + " pos: "+ pos);
   64   
   65           String opstring = opcodes[opcode];
   66           switch (opcode) {
   67               case BIPUSH:
   68                   return opstring + " " + iter.byteAt(pos + 1);
   69               case SIPUSH:
   70                   return opstring + " " + iter.s16bitAt(pos + 1);
   71               case LDC:
   72                   return opstring + " " + ldc(pool, iter.byteAt(pos + 1));
   73               case LDC_W :
   74               case LDC2_W :
   75                   return opstring + " " + ldc(pool, iter.u16bitAt(pos + 1));
   76               case ILOAD:
   77               case LLOAD:
   78               case FLOAD:
   79               case DLOAD:
   80               case ALOAD:
   81               case ISTORE:
   82               case LSTORE:
   83               case FSTORE:
   84               case DSTORE:
   85               case ASTORE:
   86                   return opstring + " " + iter.byteAt(pos + 1);
   87               case IFEQ:
   88               case IFGE:
   89               case IFGT:
   90               case IFLE:
   91               case IFLT:
   92               case IFNE:
   93               case IFNONNULL:
   94               case IFNULL:
   95               case IF_ACMPEQ:
   96               case IF_ACMPNE:
   97               case IF_ICMPEQ:
   98               case IF_ICMPGE:
   99               case IF_ICMPGT:
  100               case IF_ICMPLE:
  101               case IF_ICMPLT:
  102               case IF_ICMPNE:
  103                   return opstring + " " + (iter.s16bitAt(pos + 1) + pos);
  104               case IINC:
  105                   return opstring + " " + iter.byteAt(pos + 1);
  106               case GOTO:
  107               case JSR:
  108                   return opstring + " " + (iter.s16bitAt(pos + 1) + pos);
  109               case RET:
  110                   return opstring + " " + iter.byteAt(pos + 1);
  111               case TABLESWITCH:
  112                   return tableSwitch(iter, pos);
  113               case LOOKUPSWITCH:
  114                   return lookupSwitch(iter, pos);
  115               case GETSTATIC:
  116               case PUTSTATIC:
  117               case GETFIELD:
  118               case PUTFIELD:
  119                   return opstring + " " + fieldInfo(pool, iter.u16bitAt(pos + 1));
  120               case INVOKEVIRTUAL:
  121               case INVOKESPECIAL:
  122               case INVOKESTATIC:
  123                   return opstring + " " + methodInfo(pool, iter.u16bitAt(pos + 1));
  124               case INVOKEINTERFACE:
  125                   return opstring + " " + interfaceMethodInfo(pool, iter.u16bitAt(pos + 1));
  126               case 186:
  127                   throw new RuntimeException("Bad opcode 186");
  128               case NEW:
  129                   return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
  130               case NEWARRAY:
  131                   return opstring + " " + arrayInfo(iter.byteAt(pos + 1));
  132               case ANEWARRAY:
  133                   return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
  134               case WIDE:
  135                   return wide(iter, pos);
  136               case MULTIANEWARRAY:
  137                   return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
  138               case GOTO_W:
  139               case JSR_W:
  140                   return opstring + " " + (iter.s32bitAt(pos + 1)+ pos);
  141               default:
  142                   return opstring;
  143           }
  144       }
  145   
  146   
  147       private static String wide(CodeIterator iter, int pos) {
  148           int opcode = iter.byteAt(pos + 1);
  149           int index = iter.u16bitAt(pos + 2);
  150           switch (opcode) {
  151               case ILOAD:
  152               case LLOAD:
  153               case FLOAD:
  154               case DLOAD:
  155               case ALOAD:
  156               case ISTORE:
  157               case LSTORE:
  158               case FSTORE:
  159               case DSTORE:
  160               case ASTORE:
  161               case IINC:
  162               case RET:
  163                   return opcodes[opcode] + " " + index;
  164               default:
  165                   throw new RuntimeException("Invalid WIDE operand");
  166           }
  167       }
  168   
  169   
  170       private static String arrayInfo(int type) {
  171           switch (type) {
  172               case T_BOOLEAN:
  173                   return "boolean";
  174               case T_CHAR:
  175                   return "char";
  176               case T_BYTE:
  177                   return "byte";
  178               case T_SHORT:
  179                   return "short";
  180               case T_INT:
  181                   return "int";
  182               case T_LONG:
  183                   return "long";
  184               case T_FLOAT:
  185                   return "float";
  186               case T_DOUBLE:
  187                   return "double";
  188               default:
  189                   throw new RuntimeException("Invalid array type");
  190           }
  191       }
  192   
  193   
  194       private static String classInfo(ConstPool pool, int index) {
  195           return "#" + index + " = Class " + pool.getClassInfo(index);
  196       }
  197   
  198   
  199       private static String interfaceMethodInfo(ConstPool pool, int index) {
  200           return "#" + index + " = Method "
  201                   + pool.getInterfaceMethodrefClassName(index) + "."
  202                   + pool.getInterfaceMethodrefName(index) + "("
  203                   + pool.getInterfaceMethodrefType(index) + ")";
  204       }
  205   
  206       private static String methodInfo(ConstPool pool, int index) {
  207           return "#" + index + " = Method "
  208                   + pool.getMethodrefClassName(index) + "."
  209                   + pool.getMethodrefName(index) + "("
  210                   + pool.getMethodrefType(index) + ")";
  211       }
  212   
  213   
  214       private static String fieldInfo(ConstPool pool, int index) {
  215           return "#" + index + " = Field "
  216               + pool.getFieldrefClassName(index) + "."
  217               + pool.getFieldrefName(index) + "("
  218               + pool.getFieldrefType(index) + ")";
  219       }
  220   
  221   
  222       private static String lookupSwitch(CodeIterator iter, int pos) {
  223           StringBuffer buffer = new StringBuffer("lookupswitch {\n");
  224           int index = (pos & ~3) + 4;
  225           // default
  226           buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n");
  227           int npairs = iter.s32bitAt(index += 4);
  228           int end = npairs * 8 + (index += 4);
  229   
  230           for (; index < end; index += 8) {
  231               int match = iter.s32bitAt(index);
  232               int target = iter.s32bitAt(index + 4) + pos;
  233               buffer.append("\t\t").append(match).append(": ").append(target).append("\n");
  234           }
  235   
  236           buffer.setCharAt(buffer.length() - 1, '}');
  237           return buffer.toString();
  238       }
  239   
  240   
  241       private static String tableSwitch(CodeIterator iter, int pos) {
  242           StringBuffer buffer = new StringBuffer("tableswitch {\n");
  243           int index = (pos & ~3) + 4;
  244           // default
  245           buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n");
  246           int low = iter.s32bitAt(index += 4);
  247           int high = iter.s32bitAt(index += 4);
  248           int end = (high - low + 1) * 4 + (index += 4);
  249   
  250           // Offset table
  251           for (int key = low; index < end; index += 4, key++) {
  252               int target = iter.s32bitAt(index) + pos;
  253               buffer.append("\t\t").append(key).append(": ").append(target).append("\n");
  254           }
  255   
  256           buffer.setCharAt(buffer.length() - 1, '}');
  257           return buffer.toString();
  258       }
  259   
  260   
  261       private static String ldc(ConstPool pool, int index) {
  262           int tag = pool.getTag(index);
  263           switch (tag) {
  264               case ConstPool.CONST_String:
  265                   return "#" + index + " = \"" + pool.getStringInfo(index) + "\"";
  266               case ConstPool.CONST_Integer:
  267                   return "#" + index + " = int " + pool.getIntegerInfo(index);
  268               case ConstPool.CONST_Float:
  269                   return "#" + index + " = float " + pool.getFloatInfo(index);
  270               case ConstPool.CONST_Long:
  271                   return "#" + index + " = long " + pool.getLongInfo(index);
  272               case ConstPool.CONST_Double:
  273                   return "#" + index + " = int " + pool.getDoubleInfo(index);
  274               case ConstPool.CONST_Class:
  275                   return classInfo(pool, index);
  276               default:
  277                   throw new RuntimeException("bad LDC: " + tag);
  278           }
  279       }
  280   }

Home » javassist-sources » javassist » bytecode » [javadoc | source]