1 /* |
|
2 * Copyright (c) 2007, 2013, Oracle and/or its affiliates. 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. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package com.sun.tools.javap; |
|
27 |
|
28 import java.util.ArrayList; |
|
29 import java.util.List; |
|
30 |
|
31 import com.sun.tools.classfile.AccessFlags; |
|
32 import com.sun.tools.classfile.Code_attribute; |
|
33 import com.sun.tools.classfile.ConstantPool; |
|
34 import com.sun.tools.classfile.ConstantPoolException; |
|
35 import com.sun.tools.classfile.DescriptorException; |
|
36 import com.sun.tools.classfile.Instruction; |
|
37 import com.sun.tools.classfile.Instruction.TypeKind; |
|
38 import com.sun.tools.classfile.Method; |
|
39 |
|
40 /* |
|
41 * Write the contents of a Code attribute. |
|
42 * |
|
43 * <p><b>This is NOT part of any supported API. |
|
44 * If you write code that depends on this, you do so at your own risk. |
|
45 * This code and its internal interfaces are subject to change or |
|
46 * deletion without notice.</b> |
|
47 */ |
|
48 public class CodeWriter extends BasicWriter { |
|
49 public static CodeWriter instance(Context context) { |
|
50 CodeWriter instance = context.get(CodeWriter.class); |
|
51 if (instance == null) |
|
52 instance = new CodeWriter(context); |
|
53 return instance; |
|
54 } |
|
55 |
|
56 protected CodeWriter(Context context) { |
|
57 super(context); |
|
58 context.put(CodeWriter.class, this); |
|
59 attrWriter = AttributeWriter.instance(context); |
|
60 classWriter = ClassWriter.instance(context); |
|
61 constantWriter = ConstantWriter.instance(context); |
|
62 sourceWriter = SourceWriter.instance(context); |
|
63 tryBlockWriter = TryBlockWriter.instance(context); |
|
64 stackMapWriter = StackMapWriter.instance(context); |
|
65 localVariableTableWriter = LocalVariableTableWriter.instance(context); |
|
66 localVariableTypeTableWriter = LocalVariableTypeTableWriter.instance(context); |
|
67 typeAnnotationWriter = TypeAnnotationWriter.instance(context); |
|
68 options = Options.instance(context); |
|
69 } |
|
70 |
|
71 void write(Code_attribute attr, ConstantPool constant_pool) { |
|
72 println("Code:"); |
|
73 indent(+1); |
|
74 writeVerboseHeader(attr, constant_pool); |
|
75 writeInstrs(attr); |
|
76 writeExceptionTable(attr); |
|
77 attrWriter.write(attr, attr.attributes, constant_pool); |
|
78 indent(-1); |
|
79 } |
|
80 |
|
81 public void writeVerboseHeader(Code_attribute attr, ConstantPool constant_pool) { |
|
82 Method method = classWriter.getMethod(); |
|
83 String argCount; |
|
84 try { |
|
85 int n = method.descriptor.getParameterCount(constant_pool); |
|
86 if (!method.access_flags.is(AccessFlags.ACC_STATIC)) |
|
87 ++n; // for 'this' |
|
88 argCount = Integer.toString(n); |
|
89 } catch (ConstantPoolException e) { |
|
90 argCount = report(e); |
|
91 } catch (DescriptorException e) { |
|
92 argCount = report(e); |
|
93 } |
|
94 |
|
95 println("stack=" + attr.max_stack + |
|
96 ", locals=" + attr.max_locals + |
|
97 ", args_size=" + argCount); |
|
98 |
|
99 } |
|
100 |
|
101 public void writeInstrs(Code_attribute attr) { |
|
102 List<InstructionDetailWriter> detailWriters = getDetailWriters(attr); |
|
103 |
|
104 for (Instruction instr: attr.getInstructions()) { |
|
105 try { |
|
106 for (InstructionDetailWriter w: detailWriters) |
|
107 w.writeDetails(instr); |
|
108 writeInstr(instr); |
|
109 } catch (ArrayIndexOutOfBoundsException e) { |
|
110 println(report("error at or after byte " + instr.getPC())); |
|
111 break; |
|
112 } |
|
113 } |
|
114 |
|
115 for (InstructionDetailWriter w: detailWriters) |
|
116 w.flush(); |
|
117 } |
|
118 |
|
119 public void writeInstr(Instruction instr) { |
|
120 print(String.format("%4d: %-13s ", instr.getPC(), instr.getMnemonic())); |
|
121 // compute the number of indentations for the body of multi-line instructions |
|
122 // This is 6 (the width of "%4d: "), divided by the width of each indentation level, |
|
123 // and rounded up to the next integer. |
|
124 int indentWidth = options.indentWidth; |
|
125 int indent = (6 + indentWidth - 1) / indentWidth; |
|
126 instr.accept(instructionPrinter, indent); |
|
127 println(); |
|
128 } |
|
129 // where |
|
130 Instruction.KindVisitor<Void,Integer> instructionPrinter = |
|
131 new Instruction.KindVisitor<Void,Integer>() { |
|
132 |
|
133 public Void visitNoOperands(Instruction instr, Integer indent) { |
|
134 return null; |
|
135 } |
|
136 |
|
137 public Void visitArrayType(Instruction instr, TypeKind kind, Integer indent) { |
|
138 print(" " + kind.name); |
|
139 return null; |
|
140 } |
|
141 |
|
142 public Void visitBranch(Instruction instr, int offset, Integer indent) { |
|
143 print((instr.getPC() + offset)); |
|
144 return null; |
|
145 } |
|
146 |
|
147 public Void visitConstantPoolRef(Instruction instr, int index, Integer indent) { |
|
148 print("#" + index); |
|
149 tab(); |
|
150 print("// "); |
|
151 printConstant(index); |
|
152 return null; |
|
153 } |
|
154 |
|
155 public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Integer indent) { |
|
156 print("#" + index + ", " + value); |
|
157 tab(); |
|
158 print("// "); |
|
159 printConstant(index); |
|
160 return null; |
|
161 } |
|
162 |
|
163 public Void visitLocal(Instruction instr, int index, Integer indent) { |
|
164 print(index); |
|
165 return null; |
|
166 } |
|
167 |
|
168 public Void visitLocalAndValue(Instruction instr, int index, int value, Integer indent) { |
|
169 print(index + ", " + value); |
|
170 return null; |
|
171 } |
|
172 |
|
173 public Void visitLookupSwitch(Instruction instr, |
|
174 int default_, int npairs, int[] matches, int[] offsets, Integer indent) { |
|
175 int pc = instr.getPC(); |
|
176 print("{ // " + npairs); |
|
177 indent(indent); |
|
178 for (int i = 0; i < npairs; i++) { |
|
179 print(String.format("%n%12d: %d", matches[i], (pc + offsets[i]))); |
|
180 } |
|
181 print("\n default: " + (pc + default_) + "\n}"); |
|
182 indent(-indent); |
|
183 return null; |
|
184 } |
|
185 |
|
186 public Void visitTableSwitch(Instruction instr, |
|
187 int default_, int low, int high, int[] offsets, Integer indent) { |
|
188 int pc = instr.getPC(); |
|
189 print("{ // " + low + " to " + high); |
|
190 indent(indent); |
|
191 for (int i = 0; i < offsets.length; i++) { |
|
192 print(String.format("%n%12d: %d", (low + i), (pc + offsets[i]))); |
|
193 } |
|
194 print("\n default: " + (pc + default_) + "\n}"); |
|
195 indent(-indent); |
|
196 return null; |
|
197 } |
|
198 |
|
199 public Void visitValue(Instruction instr, int value, Integer indent) { |
|
200 print(value); |
|
201 return null; |
|
202 } |
|
203 |
|
204 public Void visitUnknown(Instruction instr, Integer indent) { |
|
205 return null; |
|
206 } |
|
207 }; |
|
208 |
|
209 |
|
210 public void writeExceptionTable(Code_attribute attr) { |
|
211 if (attr.exception_table_length > 0) { |
|
212 println("Exception table:"); |
|
213 indent(+1); |
|
214 println(" from to target type"); |
|
215 for (int i = 0; i < attr.exception_table.length; i++) { |
|
216 Code_attribute.Exception_data handler = attr.exception_table[i]; |
|
217 print(String.format(" %5d %5d %5d", |
|
218 handler.start_pc, handler.end_pc, handler.handler_pc)); |
|
219 print(" "); |
|
220 int catch_type = handler.catch_type; |
|
221 if (catch_type == 0) { |
|
222 println("any"); |
|
223 } else { |
|
224 print("Class "); |
|
225 println(constantWriter.stringValue(catch_type)); |
|
226 } |
|
227 } |
|
228 indent(-1); |
|
229 } |
|
230 |
|
231 } |
|
232 |
|
233 private void printConstant(int index) { |
|
234 constantWriter.write(index); |
|
235 } |
|
236 |
|
237 private List<InstructionDetailWriter> getDetailWriters(Code_attribute attr) { |
|
238 List<InstructionDetailWriter> detailWriters = new ArrayList<>(); |
|
239 if (options.details.contains(InstructionDetailWriter.Kind.SOURCE)) { |
|
240 sourceWriter.reset(classWriter.getClassFile(), attr); |
|
241 if (sourceWriter.hasSource()) |
|
242 detailWriters.add(sourceWriter); |
|
243 else |
|
244 println("(Source code not available)"); |
|
245 } |
|
246 |
|
247 if (options.details.contains(InstructionDetailWriter.Kind.LOCAL_VARS)) { |
|
248 localVariableTableWriter.reset(attr); |
|
249 detailWriters.add(localVariableTableWriter); |
|
250 } |
|
251 |
|
252 if (options.details.contains(InstructionDetailWriter.Kind.LOCAL_VAR_TYPES)) { |
|
253 localVariableTypeTableWriter.reset(attr); |
|
254 detailWriters.add(localVariableTypeTableWriter); |
|
255 } |
|
256 |
|
257 if (options.details.contains(InstructionDetailWriter.Kind.STACKMAPS)) { |
|
258 stackMapWriter.reset(attr); |
|
259 stackMapWriter.writeInitialDetails(); |
|
260 detailWriters.add(stackMapWriter); |
|
261 } |
|
262 |
|
263 if (options.details.contains(InstructionDetailWriter.Kind.TRY_BLOCKS)) { |
|
264 tryBlockWriter.reset(attr); |
|
265 detailWriters.add(tryBlockWriter); |
|
266 } |
|
267 |
|
268 if (options.details.contains(InstructionDetailWriter.Kind.TYPE_ANNOS)) { |
|
269 typeAnnotationWriter.reset(attr); |
|
270 detailWriters.add(typeAnnotationWriter); |
|
271 } |
|
272 |
|
273 return detailWriters; |
|
274 } |
|
275 |
|
276 private AttributeWriter attrWriter; |
|
277 private ClassWriter classWriter; |
|
278 private ConstantWriter constantWriter; |
|
279 private LocalVariableTableWriter localVariableTableWriter; |
|
280 private LocalVariableTypeTableWriter localVariableTypeTableWriter; |
|
281 private TypeAnnotationWriter typeAnnotationWriter; |
|
282 private SourceWriter sourceWriter; |
|
283 private StackMapWriter stackMapWriter; |
|
284 private TryBlockWriter tryBlockWriter; |
|
285 private Options options; |
|
286 } |
|