• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InstructionPrinter(PrintStream stream)31     public InstructionPrinter(PrintStream stream) {
32         this.stream = stream;
33     }
34 
print(CtMethod method, PrintStream stream)35     public static void print(CtMethod method, PrintStream stream) {
36         (new InstructionPrinter(stream)).print(method);
37     }
38 
print(CtMethod method)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 
instructionString(CodeIterator iter, int pos, ConstPool pool)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             case CHECKCAST:
134                 return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
135             case WIDE:
136                 return wide(iter, pos);
137             case MULTIANEWARRAY:
138                 return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
139             case GOTO_W:
140             case JSR_W:
141                 return opstring + " " + (iter.s32bitAt(pos + 1)+ pos);
142             default:
143                 return opstring;
144         }
145     }
146 
147 
wide(CodeIterator iter, int pos)148     private static String wide(CodeIterator iter, int pos) {
149         int opcode = iter.byteAt(pos + 1);
150         int index = iter.u16bitAt(pos + 2);
151         switch (opcode) {
152             case ILOAD:
153             case LLOAD:
154             case FLOAD:
155             case DLOAD:
156             case ALOAD:
157             case ISTORE:
158             case LSTORE:
159             case FSTORE:
160             case DSTORE:
161             case ASTORE:
162             case IINC:
163             case RET:
164                 return opcodes[opcode] + " " + index;
165             default:
166                 throw new RuntimeException("Invalid WIDE operand");
167         }
168     }
169 
170 
arrayInfo(int type)171     private static String arrayInfo(int type) {
172         switch (type) {
173             case T_BOOLEAN:
174                 return "boolean";
175             case T_CHAR:
176                 return "char";
177             case T_BYTE:
178                 return "byte";
179             case T_SHORT:
180                 return "short";
181             case T_INT:
182                 return "int";
183             case T_LONG:
184                 return "long";
185             case T_FLOAT:
186                 return "float";
187             case T_DOUBLE:
188                 return "double";
189             default:
190                 throw new RuntimeException("Invalid array type");
191         }
192     }
193 
194 
classInfo(ConstPool pool, int index)195     private static String classInfo(ConstPool pool, int index) {
196         return "#" + index + " = Class " + pool.getClassInfo(index);
197     }
198 
199 
interfaceMethodInfo(ConstPool pool, int index)200     private static String interfaceMethodInfo(ConstPool pool, int index) {
201         return "#" + index + " = Method "
202                 + pool.getInterfaceMethodrefClassName(index) + "."
203                 + pool.getInterfaceMethodrefName(index) + "("
204                 + pool.getInterfaceMethodrefType(index) + ")";
205     }
206 
methodInfo(ConstPool pool, int index)207     private static String methodInfo(ConstPool pool, int index) {
208         return "#" + index + " = Method "
209                 + pool.getMethodrefClassName(index) + "."
210                 + pool.getMethodrefName(index) + "("
211                 + pool.getMethodrefType(index) + ")";
212     }
213 
214 
fieldInfo(ConstPool pool, int index)215     private static String fieldInfo(ConstPool pool, int index) {
216         return "#" + index + " = Field "
217             + pool.getFieldrefClassName(index) + "."
218             + pool.getFieldrefName(index) + "("
219             + pool.getFieldrefType(index) + ")";
220     }
221 
222 
lookupSwitch(CodeIterator iter, int pos)223     private static String lookupSwitch(CodeIterator iter, int pos) {
224         StringBuffer buffer = new StringBuffer("lookupswitch {\n");
225         int index = (pos & ~3) + 4;
226         // default
227         buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n");
228         int npairs = iter.s32bitAt(index += 4);
229         int end = npairs * 8 + (index += 4);
230 
231         for (; index < end; index += 8) {
232             int match = iter.s32bitAt(index);
233             int target = iter.s32bitAt(index + 4) + pos;
234             buffer.append("\t\t").append(match).append(": ").append(target).append("\n");
235         }
236 
237         buffer.setCharAt(buffer.length() - 1, '}');
238         return buffer.toString();
239     }
240 
241 
tableSwitch(CodeIterator iter, int pos)242     private static String tableSwitch(CodeIterator iter, int pos) {
243         StringBuffer buffer = new StringBuffer("tableswitch {\n");
244         int index = (pos & ~3) + 4;
245         // default
246         buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n");
247         int low = iter.s32bitAt(index += 4);
248         int high = iter.s32bitAt(index += 4);
249         int end = (high - low + 1) * 4 + (index += 4);
250 
251         // Offset table
252         for (int key = low; index < end; index += 4, key++) {
253             int target = iter.s32bitAt(index) + pos;
254             buffer.append("\t\t").append(key).append(": ").append(target).append("\n");
255         }
256 
257         buffer.setCharAt(buffer.length() - 1, '}');
258         return buffer.toString();
259     }
260 
261 
ldc(ConstPool pool, int index)262     private static String ldc(ConstPool pool, int index) {
263         int tag = pool.getTag(index);
264         switch (tag) {
265             case ConstPool.CONST_String:
266                 return "#" + index + " = \"" + pool.getStringInfo(index) + "\"";
267             case ConstPool.CONST_Integer:
268                 return "#" + index + " = int " + pool.getIntegerInfo(index);
269             case ConstPool.CONST_Float:
270                 return "#" + index + " = float " + pool.getFloatInfo(index);
271             case ConstPool.CONST_Long:
272                 return "#" + index + " = long " + pool.getLongInfo(index);
273             case ConstPool.CONST_Double:
274                 return "#" + index + " = int " + pool.getDoubleInfo(index);
275             case ConstPool.CONST_Class:
276                 return classInfo(pool, index);
277             default:
278                 throw new RuntimeException("bad LDC: " + tag);
279         }
280     }
281 }
282