|
1 /* |
|
2 * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package com.sun.tools.javap; |
|
27 |
|
28 import com.sun.tools.classfile.AccessFlags; |
|
29 import com.sun.tools.classfile.Code_attribute; |
|
30 import com.sun.tools.classfile.ConstantPool; |
|
31 import com.sun.tools.classfile.ConstantPoolException; |
|
32 import com.sun.tools.classfile.DescriptorException; |
|
33 import com.sun.tools.classfile.Method; |
|
34 |
|
35 import static com.sun.tools.classfile.OpCodes.*; |
|
36 |
|
37 /* |
|
38 * Write the contents of a Code attribute. |
|
39 * |
|
40 * <p><b>This is NOT part of any API supported by Sun Microsystems. If |
|
41 * you write code that depends on this, you do so at your own risk. |
|
42 * This code and its internal interfaces are subject to change or |
|
43 * deletion without notice.</b> |
|
44 */ |
|
45 class CodeWriter extends BasicWriter { |
|
46 static CodeWriter instance(Context context) { |
|
47 CodeWriter instance = context.get(CodeWriter.class); |
|
48 if (instance == null) |
|
49 instance = new CodeWriter(context); |
|
50 return instance; |
|
51 } |
|
52 |
|
53 protected CodeWriter(Context context) { |
|
54 super(context); |
|
55 context.put(CodeWriter.class, this); |
|
56 attrWriter = AttributeWriter.instance(context); |
|
57 classWriter = ClassWriter.instance(context); |
|
58 constantWriter = ConstantWriter.instance(context); |
|
59 } |
|
60 |
|
61 void write(Code_attribute attr, ConstantPool constant_pool) { |
|
62 println(" Code:"); |
|
63 writeVerboseHeader(attr, constant_pool); |
|
64 writeInstrs(attr); |
|
65 writeExceptionTable(attr); |
|
66 attrWriter.write(attr, attr.attributes, constant_pool); |
|
67 } |
|
68 |
|
69 public void writeVerboseHeader(Code_attribute attr, ConstantPool constant_pool) { |
|
70 Method method = classWriter.getMethod(); |
|
71 String argCount; |
|
72 try { |
|
73 int n = method.descriptor.getParameterCount(constant_pool); |
|
74 if (!method.access_flags.is(AccessFlags.ACC_STATIC)) |
|
75 ++n; // for 'this' |
|
76 argCount = Integer.toString(n); |
|
77 } catch (ConstantPoolException e) { |
|
78 argCount = report(e); |
|
79 } catch (DescriptorException e) { |
|
80 argCount = report(e); |
|
81 } |
|
82 |
|
83 println(" Stack=" + attr.max_stack + |
|
84 ", Locals=" + attr.max_locals + |
|
85 ", Args_size=" + argCount); |
|
86 |
|
87 } |
|
88 |
|
89 public void writeInstrs(Code_attribute attr) { |
|
90 try { |
|
91 for (int pc = 0; pc < attr.code_length;) { |
|
92 print(" " + pc + ":\t"); |
|
93 pc += writeInstr(attr, pc); |
|
94 println(); |
|
95 } |
|
96 } catch (Code_attribute.InvalidIndex e) { |
|
97 println(report(e)); |
|
98 } |
|
99 } |
|
100 |
|
101 public int writeInstr(Code_attribute attr, int pc) |
|
102 throws Code_attribute.InvalidIndex { |
|
103 String lP = ""; |
|
104 int opcode = attr.getUnsignedByte(pc); |
|
105 int opcode2; |
|
106 String mnem; |
|
107 switch (opcode) { |
|
108 case opc_nonpriv: |
|
109 case opc_priv: { |
|
110 opcode2 = attr.getUnsignedByte(pc + 1); |
|
111 mnem = opcName((opcode << 8) + opcode2); |
|
112 if (mnem == null) { |
|
113 mnem = opcName(opcode) + " " + opcode2; |
|
114 } |
|
115 print(mnem); |
|
116 return 2; |
|
117 } |
|
118 case opc_wide: { |
|
119 opcode2 = attr.getUnsignedByte(pc + 1); |
|
120 mnem = opcName((opcode << 8) + opcode2); |
|
121 if (mnem == null) { |
|
122 print("bytecode " + opcode); |
|
123 return 1; |
|
124 } |
|
125 print(mnem + " " + attr.getUnsignedShort(pc + 2)); |
|
126 if (opcode2 == opc_iinc) { |
|
127 print(", " + attr.getShort(pc + 4)); |
|
128 return 6; |
|
129 } |
|
130 return 4; |
|
131 } |
|
132 } |
|
133 mnem = opcName(opcode); |
|
134 if (mnem == null) { |
|
135 print("bytecode " + opcode); |
|
136 return 1; |
|
137 } |
|
138 if (opcode > opc_jsr_w) { |
|
139 print("bytecode " + opcode); |
|
140 return 1; |
|
141 } |
|
142 print(opcName(opcode)); |
|
143 switch (opcode) { |
|
144 case opc_aload: |
|
145 case opc_astore: |
|
146 case opc_fload: |
|
147 case opc_fstore: |
|
148 case opc_iload: |
|
149 case opc_istore: |
|
150 case opc_lload: |
|
151 case opc_lstore: |
|
152 case opc_dload: |
|
153 case opc_dstore: |
|
154 case opc_ret: |
|
155 print("\t" + attr.getUnsignedByte(pc + 1)); |
|
156 return 2; |
|
157 case opc_iinc: |
|
158 print("\t" + attr.getUnsignedByte(pc + 1) + ", " + attr.getByte(pc + 2)); |
|
159 return 3; |
|
160 case opc_tableswitch: |
|
161 { |
|
162 int tb = align(pc + 1); |
|
163 int default_skip = attr.getInt(tb); |
|
164 int low = attr.getInt(tb + 4); |
|
165 int high = attr.getInt(tb + 8); |
|
166 int count = high - low; |
|
167 print("{ //" + low + " to " + high); |
|
168 for (int i = 0; i <= count; i++) { |
|
169 print("\n\t\t" + (i + low) + ": " + lP + (pc + attr.getInt(tb + 12 + 4 * i)) + ";"); |
|
170 } |
|
171 print("\n\t\tdefault: " + lP + (default_skip + pc) + " }"); |
|
172 return tb - pc + 16 + count * 4; |
|
173 } |
|
174 case opc_lookupswitch: |
|
175 { |
|
176 int tb = align(pc + 1); |
|
177 int default_skip = attr.getInt(tb); |
|
178 int npairs = attr.getInt(tb + 4); |
|
179 print("{ //" + npairs); |
|
180 for (int i = 1; i <= npairs; i++) { |
|
181 print("\n\t\t" + attr.getInt(tb + i * 8) + ": " + lP + (pc + attr.getInt(tb + 4 + i * 8)) + ";"); |
|
182 } |
|
183 print("\n\t\tdefault: " + lP + (default_skip + pc) + " }"); |
|
184 return tb - pc + (npairs + 1) * 8; |
|
185 } |
|
186 case opc_newarray: |
|
187 int type = attr.getUnsignedByte(pc + 1); |
|
188 switch (type) { |
|
189 case T_BOOLEAN: |
|
190 print(" boolean"); |
|
191 break; |
|
192 case T_BYTE: |
|
193 print(" byte"); |
|
194 break; |
|
195 case T_CHAR: |
|
196 print(" char"); |
|
197 break; |
|
198 case T_SHORT: |
|
199 print(" short"); |
|
200 break; |
|
201 case T_INT: |
|
202 print(" int"); |
|
203 break; |
|
204 case T_LONG: |
|
205 print(" long"); |
|
206 break; |
|
207 case T_FLOAT: |
|
208 print(" float"); |
|
209 break; |
|
210 case T_DOUBLE: |
|
211 print(" double"); |
|
212 break; |
|
213 case T_CLASS: |
|
214 print(" class"); |
|
215 break; |
|
216 default: |
|
217 print(" BOGUS TYPE:" + type); |
|
218 } |
|
219 return 2; |
|
220 case opc_anewarray: |
|
221 { |
|
222 int index = attr.getUnsignedShort(pc + 1); |
|
223 print("\t#" + index + "; //"); |
|
224 printConstant(index); |
|
225 return 3; |
|
226 } |
|
227 case opc_sipush: |
|
228 print("\t" + attr.getShort(pc + 1)); |
|
229 return 3; |
|
230 case opc_bipush: |
|
231 print("\t" + attr.getByte(pc + 1)); |
|
232 return 2; |
|
233 case opc_ldc: |
|
234 { |
|
235 int index = attr.getUnsignedByte(pc + 1); |
|
236 print("\t#" + index + "; //"); |
|
237 printConstant(index); |
|
238 return 2; |
|
239 } |
|
240 case opc_ldc_w: |
|
241 case opc_ldc2_w: |
|
242 case opc_instanceof: |
|
243 case opc_checkcast: |
|
244 case opc_new: |
|
245 case opc_putstatic: |
|
246 case opc_getstatic: |
|
247 case opc_putfield: |
|
248 case opc_getfield: |
|
249 case opc_invokevirtual: |
|
250 case opc_invokespecial: |
|
251 case opc_invokestatic: |
|
252 { |
|
253 int index = attr.getUnsignedShort(pc + 1); |
|
254 print("\t#" + index + "; //"); |
|
255 printConstant(index); |
|
256 return 3; |
|
257 } |
|
258 case opc_invokeinterface: |
|
259 { |
|
260 int index = attr.getUnsignedShort(pc + 1); |
|
261 int nargs = attr.getUnsignedByte(pc + 3); |
|
262 print("\t#" + index + ", " + nargs + "; //"); |
|
263 printConstant(index); |
|
264 return 5; |
|
265 } |
|
266 case opc_multianewarray: |
|
267 { |
|
268 int index = attr.getUnsignedShort(pc + 1); |
|
269 int dimensions = attr.getUnsignedByte(pc + 3); |
|
270 print("\t#" + index + ", " + dimensions + "; //"); |
|
271 printConstant(index); |
|
272 return 4; |
|
273 } |
|
274 case opc_jsr: |
|
275 case opc_goto: |
|
276 case opc_ifeq: |
|
277 case opc_ifge: |
|
278 case opc_ifgt: |
|
279 case opc_ifle: |
|
280 case opc_iflt: |
|
281 case opc_ifne: |
|
282 case opc_if_icmpeq: |
|
283 case opc_if_icmpne: |
|
284 case opc_if_icmpge: |
|
285 case opc_if_icmpgt: |
|
286 case opc_if_icmple: |
|
287 case opc_if_icmplt: |
|
288 case opc_if_acmpeq: |
|
289 case opc_if_acmpne: |
|
290 case opc_ifnull: |
|
291 case opc_ifnonnull: |
|
292 print("\t" + lP + (pc + attr.getShort(pc + 1))); |
|
293 return 3; |
|
294 case opc_jsr_w: |
|
295 case opc_goto_w: |
|
296 print("\t" + lP + (pc + attr.getInt(pc + 1))); |
|
297 return 5; |
|
298 default: |
|
299 return 1; |
|
300 } |
|
301 } |
|
302 |
|
303 public void writeExceptionTable(Code_attribute attr) { |
|
304 if (attr.exception_table_langth > 0) { |
|
305 println(" Exception table:"); |
|
306 println(" from to target type"); |
|
307 for (int i = 0; i < attr.exception_table.length; i++) { |
|
308 Code_attribute.Exception_data handler = attr.exception_table[i]; |
|
309 printFixedWidthInt(handler.start_pc, 6); |
|
310 printFixedWidthInt(handler.end_pc, 6); |
|
311 printFixedWidthInt(handler.handler_pc, 6); |
|
312 print(" "); |
|
313 int catch_type = handler.catch_type; |
|
314 if (catch_type == 0) { |
|
315 println("any"); |
|
316 } else { |
|
317 print("Class "); |
|
318 println(constantWriter.stringValue(catch_type)); |
|
319 println(""); |
|
320 } |
|
321 } |
|
322 } |
|
323 |
|
324 } |
|
325 |
|
326 private void printConstant(int index) { |
|
327 constantWriter.write(index); |
|
328 } |
|
329 |
|
330 private void printFixedWidthInt(int n, int width) { |
|
331 String s = String.valueOf(n); |
|
332 for (int i = s.length(); i < width; i++) |
|
333 print(" "); |
|
334 print(s); |
|
335 } |
|
336 |
|
337 private static int align(int n) { |
|
338 return (n + 3) & ~3; |
|
339 } |
|
340 |
|
341 private AttributeWriter attrWriter; |
|
342 private ClassWriter classWriter; |
|
343 private ConstantWriter constantWriter; |
|
344 } |