src/share/classes/com/sun/tools/javap/ClassWriter.java

Wed, 18 Jun 2008 16:53:08 -0700

author
jjg
date
Wed, 18 Jun 2008 16:53:08 -0700
changeset 52
3cb4fb6e0720
parent 46
7708bd6d800d
child 54
eaf608c64fec
permissions
-rw-r--r--

6715767: javap on java.lang.ClassLoader crashes
Reviewed-by: ksrini

jjg@46 1 /*
jjg@46 2 * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
jjg@46 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@46 4 *
jjg@46 5 * This code is free software; you can redistribute it and/or modify it
jjg@46 6 * under the terms of the GNU General Public License version 2 only, as
jjg@46 7 * published by the Free Software Foundation. Sun designates this
jjg@46 8 * particular file as subject to the "Classpath" exception as provided
jjg@46 9 * by Sun in the LICENSE file that accompanied this code.
jjg@46 10 *
jjg@46 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@46 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@46 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@46 14 * version 2 for more details (a copy is included in the LICENSE file that
jjg@46 15 * accompanied this code).
jjg@46 16 *
jjg@46 17 * You should have received a copy of the GNU General Public License version
jjg@46 18 * 2 along with this work; if not, write to the Free Software Foundation,
jjg@46 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@46 20 *
jjg@46 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
jjg@46 22 * CA 95054 USA or visit www.sun.com if you need additional information or
jjg@46 23 * have any questions.
jjg@46 24 */
jjg@46 25
jjg@46 26 package com.sun.tools.javap;
jjg@46 27
jjg@46 28 import java.util.Collection;
jjg@46 29 import java.util.List;
jjg@46 30
jjg@46 31 import com.sun.tools.classfile.AccessFlags;
jjg@46 32 import com.sun.tools.classfile.Attribute;
jjg@46 33 import com.sun.tools.classfile.Attributes;
jjg@46 34 import com.sun.tools.classfile.ClassFile;
jjg@46 35 import com.sun.tools.classfile.Code_attribute;
jjg@46 36 import com.sun.tools.classfile.ConstantPool;
jjg@46 37 import com.sun.tools.classfile.ConstantPoolException;
jjg@46 38 import com.sun.tools.classfile.Descriptor;
jjg@46 39 import com.sun.tools.classfile.DescriptorException;
jjg@46 40 import com.sun.tools.classfile.Exceptions_attribute;
jjg@46 41 import com.sun.tools.classfile.Field;
jjg@46 42 import com.sun.tools.classfile.Method;
jjg@46 43 import com.sun.tools.classfile.Signature;
jjg@46 44 import com.sun.tools.classfile.Signature_attribute;
jjg@46 45 import com.sun.tools.classfile.SourceFile_attribute;
jjg@46 46 import com.sun.tools.classfile.Type;
jjg@46 47
jjg@46 48 import static com.sun.tools.classfile.AccessFlags.*;
jjg@46 49
jjg@46 50 /*
jjg@46 51 * The main javap class to write the contents of a class file as text.
jjg@46 52 *
jjg@46 53 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
jjg@46 54 * you write code that depends on this, you do so at your own risk.
jjg@46 55 * This code and its internal interfaces are subject to change or
jjg@46 56 * deletion without notice.</b>
jjg@46 57 */
jjg@46 58 public class ClassWriter extends BasicWriter {
jjg@46 59 static ClassWriter instance(Context context) {
jjg@46 60 ClassWriter instance = context.get(ClassWriter.class);
jjg@46 61 if (instance == null)
jjg@46 62 instance = new ClassWriter(context);
jjg@46 63 return instance;
jjg@46 64 }
jjg@46 65
jjg@46 66 protected ClassWriter(Context context) {
jjg@46 67 super(context);
jjg@46 68 context.put(ClassWriter.class, this);
jjg@46 69 options = Options.instance(context);
jjg@46 70 attrWriter = AttributeWriter.instance(context);
jjg@46 71 codeWriter = CodeWriter.instance(context);
jjg@46 72 constantWriter = ConstantWriter.instance(context);
jjg@46 73 }
jjg@46 74
jjg@46 75 ClassFile getClassFile() {
jjg@46 76 return classFile;
jjg@46 77 }
jjg@46 78
jjg@46 79 Method getMethod() {
jjg@46 80 return method;
jjg@46 81 }
jjg@46 82
jjg@46 83 public void write(ClassFile cf) {
jjg@46 84 classFile = cf;
jjg@46 85 constant_pool = classFile.constant_pool;
jjg@46 86
jjg@46 87 Attribute sfa = cf.getAttribute(Attribute.SourceFile);
jjg@46 88 if (sfa instanceof SourceFile_attribute) {
jjg@46 89 println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
jjg@46 90 }
jjg@46 91
jjg@46 92 String name = getJavaName(classFile);
jjg@46 93 AccessFlags flags = cf.access_flags;
jjg@46 94
jjg@46 95 writeModifiers(flags.getClassModifiers());
jjg@46 96
jjg@46 97 if (classFile.isClass())
jjg@46 98 print("class ");
jjg@46 99 else if (classFile.isInterface())
jjg@46 100 print("interface ");
jjg@46 101
jjg@46 102 print(name);
jjg@46 103
jjg@46 104 Signature_attribute sigAttr = getSignature(cf.attributes);
jjg@46 105 if (sigAttr == null) {
jjg@46 106 // use info from class file header
jjg@46 107 if (classFile.isClass()) {
jjg@46 108 if (classFile.super_class != 0 ) {
jjg@46 109 String sn = getJavaSuperclassName(cf);
jjg@46 110 if (!sn.equals("java.lang.Object") || options.compat) { // BUG XXXXXXXX
jjg@46 111 print(" extends ");
jjg@46 112 print(sn);
jjg@46 113 }
jjg@46 114 }
jjg@46 115 }
jjg@46 116 for (int i = 0; i < classFile.interfaces.length; i++) {
jjg@46 117 print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");
jjg@46 118 print(getJavaInterfaceName(classFile, i));
jjg@46 119 }
jjg@46 120 } else {
jjg@46 121 try {
jjg@46 122 Type t = sigAttr.getParsedSignature().getType(constant_pool);
jjg@46 123 // The signature parser cannot disambiguate between a
jjg@46 124 // FieldType and a ClassSignatureType that only contains a superclass type.
jjg@46 125 if (t instanceof Type.ClassSigType)
jjg@46 126 print(t);
jjg@46 127 else if (!t.isObject()) {
jjg@46 128 print(" extends ");
jjg@46 129 print(t);
jjg@46 130 }
jjg@46 131 } catch (ConstantPoolException e) {
jjg@46 132 print(report(e));
jjg@46 133 }
jjg@46 134 }
jjg@46 135
jjg@46 136 if (options.verbose) {
jjg@46 137 println();
jjg@46 138 attrWriter.write(cf, cf.attributes, constant_pool);
jjg@46 139 println(" minor version: " + cf.minor_version);
jjg@46 140 println(" major version: " + cf.major_version);
jjg@46 141 if (!options.compat)
jjg@46 142 writeList(" flags: ", flags.getClassFlags(), NEWLINE);
jjg@46 143 constantWriter.writeConstantPool();
jjg@46 144 println();
jjg@46 145 } else {
jjg@46 146 if (!options.compat)
jjg@46 147 print(" ");
jjg@46 148 }
jjg@46 149
jjg@46 150 println("{");
jjg@46 151 writeFields();
jjg@46 152 writeMethods();
jjg@46 153 println("}");
jjg@46 154 println();
jjg@46 155 }
jjg@46 156
jjg@46 157 void writeFields() {
jjg@46 158 for (Field f: classFile.fields) {
jjg@46 159 writeField(f);
jjg@46 160 }
jjg@46 161 }
jjg@46 162
jjg@46 163 void writeField(Field f) {
jjg@46 164 if (!options.checkAccess(f.access_flags))
jjg@46 165 return;
jjg@46 166
jjg@46 167 if (!(options.showLineAndLocalVariableTables
jjg@46 168 || options.showDisassembled
jjg@46 169 || options.verbose
jjg@46 170 || options.showInternalSignatures
jjg@46 171 || options.showAllAttrs)) {
jjg@46 172 print(" ");
jjg@46 173 }
jjg@46 174
jjg@46 175 AccessFlags flags = f.access_flags;
jjg@46 176 writeModifiers(flags.getFieldModifiers());
jjg@46 177 Signature_attribute sigAttr = getSignature(f.attributes);
jjg@46 178 if (sigAttr == null)
jjg@46 179 print(getFieldType(f.descriptor));
jjg@46 180 else {
jjg@46 181 try {
jjg@46 182 Type t = sigAttr.getParsedSignature().getType(constant_pool);
jjg@46 183 print(t);
jjg@46 184 } catch (ConstantPoolException e) {
jjg@46 185 // report error?
jjg@46 186 // fall back on non-generic descriptor
jjg@46 187 print(getFieldType(f.descriptor));
jjg@46 188 }
jjg@46 189 }
jjg@46 190 print(" ");
jjg@46 191 print(getFieldName(f));
jjg@46 192 print(";");
jjg@46 193 println();
jjg@46 194
jjg@46 195 if (options.showInternalSignatures)
jjg@46 196 println(" Signature: " + getValue(f.descriptor));
jjg@46 197
jjg@46 198 if (options.verbose && !options.compat)
jjg@46 199 writeList(" flags: ", flags.getFieldFlags(), NEWLINE);
jjg@46 200
jjg@46 201 if (options.showAllAttrs) {
jjg@46 202 for (Attribute attr: f.attributes)
jjg@46 203 attrWriter.write(f, attr, constant_pool);
jjg@46 204 println();
jjg@46 205 }
jjg@46 206
jjg@46 207 if (options.showDisassembled || options.showLineAndLocalVariableTables)
jjg@46 208 println();
jjg@46 209 }
jjg@46 210
jjg@46 211 void writeMethods() {
jjg@46 212 for (Method m: classFile.methods)
jjg@46 213 writeMethod(m);
jjg@46 214 }
jjg@46 215
jjg@46 216 void writeMethod(Method m) {
jjg@46 217 if (!options.checkAccess(m.access_flags))
jjg@46 218 return;
jjg@46 219
jjg@46 220 method = m;
jjg@46 221
jjg@46 222 if (!(options.showLineAndLocalVariableTables
jjg@46 223 || options.showDisassembled
jjg@46 224 || options.verbose
jjg@46 225 || options.showInternalSignatures
jjg@46 226 || options.showAllAttrs)) {
jjg@46 227 print(" ");
jjg@46 228 }
jjg@46 229
jjg@46 230 AccessFlags flags = m.access_flags;
jjg@46 231
jjg@46 232 Descriptor d;
jjg@46 233 Type.MethodType methodType;
jjg@46 234 List<? extends Type> methodExceptions;
jjg@46 235
jjg@46 236 Signature_attribute sigAttr = getSignature(m.attributes);
jjg@46 237 if (sigAttr == null) {
jjg@46 238 d = m.descriptor;
jjg@46 239 methodType = null;
jjg@46 240 methodExceptions = null;
jjg@46 241 } else {
jjg@46 242 Signature methodSig = sigAttr.getParsedSignature();
jjg@46 243 d = methodSig;
jjg@46 244 try {
jjg@46 245 methodType = (Type.MethodType) methodSig.getType(constant_pool);
jjg@46 246 methodExceptions = methodType.throwsTypes;
jjg@46 247 if (methodExceptions != null && methodExceptions.size() == 0)
jjg@46 248 methodExceptions = null;
jjg@46 249 } catch (ConstantPoolException e) {
jjg@46 250 // report error?
jjg@46 251 // fall back on standard descriptor
jjg@46 252 methodType = null;
jjg@46 253 methodExceptions = null;
jjg@46 254 }
jjg@46 255 }
jjg@46 256
jjg@46 257 writeModifiers(flags.getMethodModifiers());
jjg@46 258 if (methodType != null) {
jjg@46 259 writeListIfNotEmpty("<", methodType.typeArgTypes, "> ");
jjg@46 260 }
jjg@46 261 if (getName(m).equals("<init>")) {
jjg@46 262 print(getJavaName(classFile));
jjg@46 263 print(getParameterTypes(d, flags));
jjg@46 264 } else if (getName(m).equals("<clinit>")) {
jjg@46 265 print("{}");
jjg@46 266 } else {
jjg@46 267 print(getReturnType(d));
jjg@46 268 print(" ");
jjg@46 269 print(getName(m));
jjg@46 270 print(getParameterTypes(d, flags));
jjg@46 271 }
jjg@46 272
jjg@46 273 Attribute e_attr = m.attributes.get(Attribute.Exceptions);
jjg@46 274 if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions
jjg@46 275 if (e_attr instanceof Exceptions_attribute) {
jjg@46 276 Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;
jjg@46 277 if (options.compat) { // Bug XXXXXXX whitespace
jjg@46 278 if (!(options.showLineAndLocalVariableTables
jjg@46 279 || options.showDisassembled
jjg@46 280 || options.verbose
jjg@46 281 || options.showInternalSignatures
jjg@46 282 || options.showAllAttrs)) {
jjg@46 283 print(" ");
jjg@46 284 }
jjg@46 285 print(" ");
jjg@46 286 }
jjg@46 287 print(" throws ");
jjg@46 288 if (methodExceptions != null) { // use generic list if available
jjg@46 289 writeList("", methodExceptions, "");
jjg@46 290 } else {
jjg@46 291 for (int i = 0; i < exceptions.number_of_exceptions; i++) {
jjg@46 292 if (i > 0)
jjg@46 293 print(", ");
jjg@52 294 print(getJavaException(exceptions, i));
jjg@46 295 }
jjg@46 296 }
jjg@46 297 } else {
jjg@46 298 report("Unexpected or invalid value for Exceptions attribute");
jjg@46 299 }
jjg@46 300 }
jjg@46 301
jjg@46 302 print(";");
jjg@46 303 println();
jjg@46 304
jjg@46 305 if (options.showInternalSignatures)
jjg@46 306 println(" Signature: " + getValue(m.descriptor));
jjg@46 307
jjg@46 308 if (options.verbose && !options.compat)
jjg@46 309 writeList(" flags: ", flags.getMethodFlags(), NEWLINE);
jjg@46 310
jjg@46 311 Code_attribute code = null;
jjg@46 312 Attribute c_attr = m.attributes.get(Attribute.Code);
jjg@46 313 if (c_attr != null) {
jjg@46 314 if (c_attr instanceof Code_attribute)
jjg@46 315 code = (Code_attribute) c_attr;
jjg@46 316 else
jjg@46 317 report("Unexpected or invalid value for Code attribute");
jjg@46 318 }
jjg@46 319
jjg@46 320 if (options.showDisassembled && !options.showAllAttrs) {
jjg@46 321 if (code != null) {
jjg@46 322 println(" Code:");
jjg@46 323 codeWriter.writeInstrs(code);
jjg@46 324 codeWriter.writeExceptionTable(code);
jjg@46 325 }
jjg@46 326 println();
jjg@46 327 }
jjg@46 328
jjg@46 329 if (options.showLineAndLocalVariableTables) {
jjg@46 330 if (code != null)
jjg@46 331 attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);
jjg@46 332 println();
jjg@46 333 if (code != null)
jjg@46 334 attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);
jjg@46 335 println();
jjg@46 336 println();
jjg@46 337 }
jjg@46 338
jjg@46 339 if (options.showAllAttrs) {
jjg@46 340 Attribute[] attrs = m.attributes.attrs;
jjg@46 341 for (Attribute attr: attrs)
jjg@46 342 attrWriter.write(m, attr, constant_pool);
jjg@46 343
jjg@46 344 // // the following condition is to mimic old javap
jjg@46 345 // if (!(attrs.length > 0 &&
jjg@46 346 // attrs[attrs.length - 1] instanceof Exceptions_attribute))
jjg@46 347 println();
jjg@46 348 }
jjg@46 349 }
jjg@46 350
jjg@46 351 void writeModifiers(Collection<String> items) {
jjg@46 352 for (Object item: items) {
jjg@46 353 print(item);
jjg@46 354 print(" ");
jjg@46 355 }
jjg@46 356 }
jjg@46 357
jjg@46 358 void writeList(String prefix, Collection<?> items, String suffix) {
jjg@46 359 print(prefix);
jjg@46 360 String sep = "";
jjg@46 361 for (Object item: items) {
jjg@46 362 print(sep);
jjg@46 363 print(item);
jjg@46 364 sep = ", ";
jjg@46 365 }
jjg@46 366 print(suffix);
jjg@46 367 }
jjg@46 368
jjg@46 369 void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {
jjg@46 370 if (items != null && items.size() > 0)
jjg@46 371 writeList(prefix, items, suffix);
jjg@46 372 }
jjg@46 373
jjg@46 374 Signature_attribute getSignature(Attributes attributes) {
jjg@46 375 if (options.compat) // javap does not recognize recent attributes
jjg@46 376 return null;
jjg@46 377 return (Signature_attribute) attributes.get(Attribute.Signature);
jjg@46 378 }
jjg@46 379
jjg@46 380 String adjustVarargs(AccessFlags flags, String params) {
jjg@46 381 if (flags.is(ACC_VARARGS) && !options.compat) {
jjg@46 382 int i = params.lastIndexOf("[]");
jjg@46 383 if (i > 0)
jjg@46 384 return params.substring(0, i) + "..." + params.substring(i+2);
jjg@46 385 }
jjg@46 386
jjg@46 387 return params;
jjg@46 388 }
jjg@46 389
jjg@46 390 String getJavaName(ClassFile cf) {
jjg@46 391 try {
jjg@46 392 return getJavaName(cf.getName());
jjg@46 393 } catch (ConstantPoolException e) {
jjg@46 394 return report(e);
jjg@46 395 }
jjg@46 396 }
jjg@46 397
jjg@46 398 String getJavaSuperclassName(ClassFile cf) {
jjg@46 399 try {
jjg@46 400 return getJavaName(cf.getSuperclassName());
jjg@46 401 } catch (ConstantPoolException e) {
jjg@46 402 return report(e);
jjg@46 403 }
jjg@46 404 }
jjg@46 405
jjg@46 406 String getJavaInterfaceName(ClassFile cf, int index) {
jjg@46 407 try {
jjg@46 408 return getJavaName(cf.getInterfaceName(index));
jjg@46 409 } catch (ConstantPoolException e) {
jjg@46 410 return report(e);
jjg@46 411 }
jjg@46 412 }
jjg@46 413
jjg@46 414 String getFieldType(Descriptor d) {
jjg@46 415 try {
jjg@46 416 return d.getFieldType(constant_pool);
jjg@46 417 } catch (ConstantPoolException e) {
jjg@46 418 return report(e);
jjg@46 419 } catch (DescriptorException e) {
jjg@46 420 return report(e);
jjg@46 421 }
jjg@46 422 }
jjg@46 423
jjg@46 424 String getReturnType(Descriptor d) {
jjg@46 425 try {
jjg@46 426 return d.getReturnType(constant_pool);
jjg@46 427 } catch (ConstantPoolException e) {
jjg@46 428 return report(e);
jjg@46 429 } catch (DescriptorException e) {
jjg@46 430 return report(e);
jjg@46 431 }
jjg@46 432 }
jjg@46 433
jjg@46 434 String getParameterTypes(Descriptor d, AccessFlags flags) {
jjg@46 435 try {
jjg@46 436 return adjustVarargs(flags, d.getParameterTypes(constant_pool));
jjg@46 437 } catch (ConstantPoolException e) {
jjg@46 438 return report(e);
jjg@46 439 } catch (DescriptorException e) {
jjg@46 440 return report(e);
jjg@46 441 }
jjg@46 442 }
jjg@46 443
jjg@52 444 String getJavaException(Exceptions_attribute attr, int index) {
jjg@52 445 try {
jjg@52 446 return getJavaName(attr.getException(index, constant_pool));
jjg@52 447 } catch (ConstantPoolException e) {
jjg@52 448 return report(e);
jjg@52 449 }
jjg@52 450 }
jjg@52 451
jjg@46 452 String getValue(Descriptor d) {
jjg@46 453 try {
jjg@46 454 return d.getValue(constant_pool);
jjg@46 455 } catch (ConstantPoolException e) {
jjg@46 456 return report(e);
jjg@46 457 }
jjg@46 458 }
jjg@46 459
jjg@46 460 String getFieldName(Field f) {
jjg@46 461 try {
jjg@46 462 return f.getName(constant_pool);
jjg@46 463 } catch (ConstantPoolException e) {
jjg@46 464 return report(e);
jjg@46 465 }
jjg@46 466 }
jjg@46 467
jjg@46 468 String getName(Method m) {
jjg@46 469 try {
jjg@46 470 return m.getName(constant_pool);
jjg@46 471 } catch (ConstantPoolException e) {
jjg@46 472 return report(e);
jjg@46 473 }
jjg@46 474 }
jjg@46 475
jjg@46 476 static String getJavaName(String name) {
jjg@46 477 return name.replace('/', '.');
jjg@46 478 }
jjg@46 479
jjg@46 480 String getSourceFile(SourceFile_attribute attr) {
jjg@46 481 try {
jjg@46 482 return attr.getSourceFile(constant_pool);
jjg@46 483 } catch (ConstantPoolException e) {
jjg@46 484 return report(e);
jjg@46 485 }
jjg@46 486 }
jjg@46 487
jjg@46 488 private Options options;
jjg@46 489 private AttributeWriter attrWriter;
jjg@46 490 private CodeWriter codeWriter;
jjg@46 491 private ConstantWriter constantWriter;
jjg@46 492 private ClassFile classFile;
jjg@46 493 private ConstantPool constant_pool;
jjg@46 494 private Method method;
jjg@46 495 private static final String NEWLINE = System.getProperty("line.separator", "\n");
jjg@46 496 }

mercurial