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 { instance(Context context)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 CodeWriter(Context context)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 write(Code_attribute attr, ConstantPool constant_pool)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 writeVerboseHeader(Code_attribute attr, ConstantPool constant_pool)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 writeInstrs(Code_attribute attr)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 writeInstr(Instruction instr)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 writeExceptionTable(Code_attribute attr)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 printConstant(int index)233 private void printConstant(int index) { 234 constantWriter.write(index); 235 } 236 getDetailWriters(Code_attribute attr)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 } 287