Tue, 08 Jan 2013 10:17:29 +0100
8005184: Restructure DeferredAttr to allow pluggable deferred type completers
Summary: Add hooks to generalize deferred type completion via custom helper objects
Reviewed-by: jjg
1 /*
2 * Copyright (c) 2007, 2012, 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 */
26 package com.sun.tools.javap;
28 import java.util.ArrayList;
29 import java.util.List;
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;
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 }
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 options = Options.instance(context);
68 }
70 void write(Code_attribute attr, ConstantPool constant_pool) {
71 println("Code:");
72 indent(+1);
73 writeVerboseHeader(attr, constant_pool);
74 writeInstrs(attr);
75 writeExceptionTable(attr);
76 attrWriter.write(attr, attr.attributes, constant_pool);
77 indent(-1);
78 }
80 public void writeVerboseHeader(Code_attribute attr, ConstantPool constant_pool) {
81 Method method = classWriter.getMethod();
82 String argCount;
83 try {
84 int n = method.descriptor.getParameterCount(constant_pool);
85 if (!method.access_flags.is(AccessFlags.ACC_STATIC))
86 ++n; // for 'this'
87 argCount = Integer.toString(n);
88 } catch (ConstantPoolException e) {
89 argCount = report(e);
90 } catch (DescriptorException e) {
91 argCount = report(e);
92 }
94 println("stack=" + attr.max_stack +
95 ", locals=" + attr.max_locals +
96 ", args_size=" + argCount);
98 }
100 public void writeInstrs(Code_attribute attr) {
101 List<InstructionDetailWriter> detailWriters = getDetailWriters(attr);
103 for (Instruction instr: attr.getInstructions()) {
104 try {
105 for (InstructionDetailWriter w: detailWriters)
106 w.writeDetails(instr);
107 writeInstr(instr);
108 } catch (ArrayIndexOutOfBoundsException e) {
109 println(report("error at or after byte " + instr.getPC()));
110 break;
111 }
112 }
114 for (InstructionDetailWriter w: detailWriters)
115 w.flush();
116 }
118 public void writeInstr(Instruction instr) {
119 print(String.format("%4d: %-13s ", instr.getPC(), instr.getMnemonic()));
120 // compute the number of indentations for the body of multi-line instructions
121 // This is 6 (the width of "%4d: "), divided by the width of each indentation level,
122 // and rounded up to the next integer.
123 int indentWidth = options.indentWidth;
124 int indent = (6 + indentWidth - 1) / indentWidth;
125 instr.accept(instructionPrinter, indent);
126 println();
127 }
128 // where
129 Instruction.KindVisitor<Void,Integer> instructionPrinter =
130 new Instruction.KindVisitor<Void,Integer>() {
132 public Void visitNoOperands(Instruction instr, Integer indent) {
133 return null;
134 }
136 public Void visitArrayType(Instruction instr, TypeKind kind, Integer indent) {
137 print(" " + kind.name);
138 return null;
139 }
141 public Void visitBranch(Instruction instr, int offset, Integer indent) {
142 print((instr.getPC() + offset));
143 return null;
144 }
146 public Void visitConstantPoolRef(Instruction instr, int index, Integer indent) {
147 print("#" + index);
148 tab();
149 print("// ");
150 printConstant(index);
151 return null;
152 }
154 public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Integer indent) {
155 print("#" + index + ", " + value);
156 tab();
157 print("// ");
158 printConstant(index);
159 return null;
160 }
162 public Void visitLocal(Instruction instr, int index, Integer indent) {
163 print(index);
164 return null;
165 }
167 public Void visitLocalAndValue(Instruction instr, int index, int value, Integer indent) {
168 print(index + ", " + value);
169 return null;
170 }
172 public Void visitLookupSwitch(Instruction instr,
173 int default_, int npairs, int[] matches, int[] offsets, Integer indent) {
174 int pc = instr.getPC();
175 print("{ // " + npairs);
176 indent(indent);
177 for (int i = 0; i < npairs; i++) {
178 print(String.format("%n%12d: %d", matches[i], (pc + offsets[i])));
179 }
180 print("\n default: " + (pc + default_) + "\n}");
181 indent(-indent);
182 return null;
183 }
185 public Void visitTableSwitch(Instruction instr,
186 int default_, int low, int high, int[] offsets, Integer indent) {
187 int pc = instr.getPC();
188 print("{ // " + low + " to " + high);
189 indent(indent);
190 for (int i = 0; i < offsets.length; i++) {
191 print(String.format("%n%12d: %d", (low + i), (pc + offsets[i])));
192 }
193 print("\n default: " + (pc + default_) + "\n}");
194 indent(-indent);
195 return null;
196 }
198 public Void visitValue(Instruction instr, int value, Integer indent) {
199 print(value);
200 return null;
201 }
203 public Void visitUnknown(Instruction instr, Integer indent) {
204 return null;
205 }
206 };
209 public void writeExceptionTable(Code_attribute attr) {
210 if (attr.exception_table_langth > 0) {
211 println("Exception table:");
212 indent(+1);
213 println(" from to target type");
214 for (int i = 0; i < attr.exception_table.length; i++) {
215 Code_attribute.Exception_data handler = attr.exception_table[i];
216 print(String.format(" %5d %5d %5d",
217 handler.start_pc, handler.end_pc, handler.handler_pc));
218 print(" ");
219 int catch_type = handler.catch_type;
220 if (catch_type == 0) {
221 println("any");
222 } else {
223 print("Class ");
224 println(constantWriter.stringValue(catch_type));
225 }
226 }
227 indent(-1);
228 }
230 }
232 private void printConstant(int index) {
233 constantWriter.write(index);
234 }
236 private List<InstructionDetailWriter> getDetailWriters(Code_attribute attr) {
237 List<InstructionDetailWriter> detailWriters =
238 new ArrayList<InstructionDetailWriter>();
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 }
247 if (options.details.contains(InstructionDetailWriter.Kind.LOCAL_VARS)) {
248 localVariableTableWriter.reset(attr);
249 detailWriters.add(localVariableTableWriter);
250 }
252 if (options.details.contains(InstructionDetailWriter.Kind.LOCAL_VAR_TYPES)) {
253 localVariableTypeTableWriter.reset(attr);
254 detailWriters.add(localVariableTypeTableWriter);
255 }
257 if (options.details.contains(InstructionDetailWriter.Kind.STACKMAPS)) {
258 stackMapWriter.reset(attr);
259 stackMapWriter.writeInitialDetails();
260 detailWriters.add(stackMapWriter);
261 }
263 if (options.details.contains(InstructionDetailWriter.Kind.TRY_BLOCKS)) {
264 tryBlockWriter.reset(attr);
265 detailWriters.add(tryBlockWriter);
266 }
268 return detailWriters;
269 }
271 private AttributeWriter attrWriter;
272 private ClassWriter classWriter;
273 private ConstantWriter constantWriter;
274 private LocalVariableTableWriter localVariableTableWriter;
275 private LocalVariableTypeTableWriter localVariableTypeTableWriter;
276 private SourceWriter sourceWriter;
277 private StackMapWriter stackMapWriter;
278 private TryBlockWriter tryBlockWriter;
279 private Options options;
280 }