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

Tue, 19 May 2009 11:50:54 -0700

author
jjg
date
Tue, 19 May 2009 11:50:54 -0700
changeset 283
cd0630109de5
parent 88
05684554f040
child 300
ed989c347b3c
permissions
-rw-r--r--

6824493: experimental support for additional info for instructions
Reviewed-by: mcimadamore

     1 /*
     2  * Copyright 2007-2008 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  */
    26 package com.sun.tools.javap;
    28 import java.net.URI;
    29 import java.text.DateFormat;
    30 import java.util.Collection;
    31 import java.util.Date;
    32 import java.util.List;
    34 import com.sun.tools.classfile.AccessFlags;
    35 import com.sun.tools.classfile.Attribute;
    36 import com.sun.tools.classfile.Attributes;
    37 import com.sun.tools.classfile.ClassFile;
    38 import com.sun.tools.classfile.Code_attribute;
    39 import com.sun.tools.classfile.ConstantPool;
    40 import com.sun.tools.classfile.ConstantPoolException;
    41 import com.sun.tools.classfile.ConstantValue_attribute;
    42 import com.sun.tools.classfile.Descriptor;
    43 import com.sun.tools.classfile.DescriptorException;
    44 import com.sun.tools.classfile.Exceptions_attribute;
    45 import com.sun.tools.classfile.Field;
    46 import com.sun.tools.classfile.Method;
    47 import com.sun.tools.classfile.Signature;
    48 import com.sun.tools.classfile.Signature_attribute;
    49 import com.sun.tools.classfile.SourceFile_attribute;
    50 import com.sun.tools.classfile.Type;
    52 import static com.sun.tools.classfile.AccessFlags.*;
    54 /*
    55  *  The main javap class to write the contents of a class file as text.
    56  *
    57  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    58  *  you write code that depends on this, you do so at your own risk.
    59  *  This code and its internal interfaces are subject to change or
    60  *  deletion without notice.</b>
    61  */
    62 public class ClassWriter extends BasicWriter {
    63     static ClassWriter instance(Context context) {
    64         ClassWriter instance = context.get(ClassWriter.class);
    65         if (instance == null)
    66             instance = new ClassWriter(context);
    67         return instance;
    68     }
    70     protected ClassWriter(Context context) {
    71         super(context);
    72         context.put(ClassWriter.class, this);
    73         options = Options.instance(context);
    74         attrWriter = AttributeWriter.instance(context);
    75         codeWriter = CodeWriter.instance(context);
    76         constantWriter = ConstantWriter.instance(context);
    77     }
    79     void setDigest(String name, byte[] digest) {
    80         this.digestName = name;
    81         this.digest = digest;
    82     }
    84     void setFile(URI uri) {
    85         this.uri = uri;
    86     }
    88     void setFileSize(int size) {
    89         this.size = size;
    90     }
    92     void setLastModified(long lastModified) {
    93         this.lastModified = lastModified;
    94     }
    96     ClassFile getClassFile() {
    97         return classFile;
    98     }
   100     Method getMethod() {
   101         return method;
   102     }
   104     public void write(ClassFile cf) {
   105         classFile = cf;
   106         constant_pool = classFile.constant_pool;
   108         if ((options.sysInfo || options.verbose) && !options.compat) {
   109             if (uri != null) {
   110                 if (uri.getScheme().equals("file"))
   111                     println("Classfile " + uri.getPath());
   112                 else
   113                     println("Classfile " + uri);
   114             }
   115             if (lastModified != -1) {
   116                 Date lm = new Date(lastModified);
   117                 DateFormat df = DateFormat.getDateInstance();
   118                 if (size > 0) {
   119                     println("Last modified " + df.format(lm) + "; size " + size + " bytes");
   120                 } else {
   121                     println("Last modified " + df.format(lm));
   122                 }
   123             } else if (size > 0) {
   124                 println("Size " + size + " bytes");
   125             }
   126             if (digestName != null && digest != null) {
   127                 StringBuilder sb = new StringBuilder();
   128                 for (byte b: digest)
   129                     sb.append(String.format("%02x", b));
   130                 println(digestName + " checksum " + sb);
   131             }
   132         }
   134         Attribute sfa = cf.getAttribute(Attribute.SourceFile);
   135         if (sfa instanceof SourceFile_attribute) {
   136             println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
   137         }
   139         String name = getJavaName(classFile);
   140         AccessFlags flags = cf.access_flags;
   142         writeModifiers(flags.getClassModifiers());
   144         if (classFile.isClass())
   145             print("class ");
   146         else if (classFile.isInterface())
   147             print("interface ");
   149         print(name);
   151         Signature_attribute sigAttr = getSignature(cf.attributes);
   152         if (sigAttr == null) {
   153             // use info from class file header
   154             if (classFile.isClass() && classFile.super_class != 0 ) {
   155                 String sn = getJavaSuperclassName(cf);
   156                 print(" extends ");
   157                 print(sn);
   158             }
   159             for (int i = 0; i < classFile.interfaces.length; i++) {
   160                 print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");
   161                 print(getJavaInterfaceName(classFile, i));
   162             }
   163         } else {
   164             try {
   165                 Type t = sigAttr.getParsedSignature().getType(constant_pool);
   166                 // The signature parser cannot disambiguate between a
   167                 // FieldType and a ClassSignatureType that only contains a superclass type.
   168                 if (t instanceof Type.ClassSigType)
   169                     print(t);
   170                 else {
   171                     print(" extends ");
   172                     print(t);
   173                 }
   174             } catch (ConstantPoolException e) {
   175                 print(report(e));
   176             }
   177         }
   179         if (options.verbose) {
   180             println();
   181             attrWriter.write(cf, cf.attributes, constant_pool);
   182             println("  minor version: " + cf.minor_version);
   183             println("  major version: " + cf.major_version);
   184             if (!options.compat)
   185               writeList("  flags: ", flags.getClassFlags(), NEWLINE);
   186             constantWriter.writeConstantPool();
   187             println();
   188         } else {
   189             if (!options.compat)
   190                 print(" ");
   191         }
   193         println("{");
   194         writeFields();
   195         writeMethods();
   196         println("}");
   197         println();
   198     }
   200     void writeFields() {
   201         for (Field f: classFile.fields) {
   202             writeField(f);
   203         }
   204     }
   206     void writeField(Field f) {
   207         if (!options.checkAccess(f.access_flags))
   208             return;
   210         if (!(options.showLineAndLocalVariableTables
   211                 || options.showDisassembled
   212                 || options.verbose
   213                 || options.showInternalSignatures
   214                 || options.showAllAttrs)) {
   215             print("    ");
   216         }
   218         AccessFlags flags = f.access_flags;
   219         writeModifiers(flags.getFieldModifiers());
   220         Signature_attribute sigAttr = getSignature(f.attributes);
   221         if (sigAttr == null)
   222             print(getFieldType(f.descriptor));
   223         else {
   224             try {
   225                 Type t = sigAttr.getParsedSignature().getType(constant_pool);
   226                 print(t);
   227             } catch (ConstantPoolException e) {
   228                 // report error?
   229                 // fall back on non-generic descriptor
   230                 print(getFieldType(f.descriptor));
   231             }
   232         }
   233         print(" ");
   234         print(getFieldName(f));
   235         if (options.showConstants && !options.compat) { // BUG 4111861 print static final field contents
   236             Attribute a = f.attributes.get(Attribute.ConstantValue);
   237             if (a instanceof ConstantValue_attribute) {
   238                 print(" = ");
   239                 ConstantValue_attribute cv = (ConstantValue_attribute) a;
   240                 print(getConstantValue(f.descriptor, cv.constantvalue_index));
   241             }
   242         }
   243         print(";");
   244         println();
   246         if (options.showInternalSignatures)
   247             println("  Signature: " + getValue(f.descriptor));
   249         if (options.verbose && !options.compat)
   250             writeList("  flags: ", flags.getFieldFlags(), NEWLINE);
   252         if (options.showAllAttrs) {
   253             for (Attribute attr: f.attributes)
   254                 attrWriter.write(f, attr, constant_pool);
   255             println();
   256         }
   258         if (options.showDisassembled || options.showLineAndLocalVariableTables)
   259             println();
   260     }
   262     void writeMethods() {
   263         for (Method m: classFile.methods)
   264             writeMethod(m);
   265     }
   267     void writeMethod(Method m) {
   268         if (!options.checkAccess(m.access_flags))
   269             return;
   271         method = m;
   273         if (!(options.showLineAndLocalVariableTables
   274                 || options.showDisassembled
   275                 || options.verbose
   276                 || options.showInternalSignatures
   277                 || options.showAllAttrs)) {
   278             print("    ");
   279         }
   281         AccessFlags flags = m.access_flags;
   283         Descriptor d;
   284         Type.MethodType methodType;
   285         List<? extends Type> methodExceptions;
   287         Signature_attribute sigAttr = getSignature(m.attributes);
   288         if (sigAttr == null) {
   289             d = m.descriptor;
   290             methodType = null;
   291             methodExceptions = null;
   292         } else {
   293             Signature methodSig = sigAttr.getParsedSignature();
   294             d = methodSig;
   295             try {
   296                 methodType = (Type.MethodType) methodSig.getType(constant_pool);
   297                 methodExceptions = methodType.throwsTypes;
   298                 if (methodExceptions != null && methodExceptions.size() == 0)
   299                     methodExceptions = null;
   300             } catch (ConstantPoolException e) {
   301                 // report error?
   302                 // fall back on standard descriptor
   303                 methodType = null;
   304                 methodExceptions = null;
   305             }
   306         }
   308         writeModifiers(flags.getMethodModifiers());
   309         if (methodType != null) {
   310             writeListIfNotEmpty("<", methodType.typeArgTypes, "> ");
   311         }
   312         if (getName(m).equals("<init>")) {
   313             print(getJavaName(classFile));
   314             print(getParameterTypes(d, flags));
   315         } else if (getName(m).equals("<clinit>")) {
   316             print("{}");
   317         } else {
   318             print(getReturnType(d));
   319             print(" ");
   320             print(getName(m));
   321             print(getParameterTypes(d, flags));
   322         }
   324         Attribute e_attr = m.attributes.get(Attribute.Exceptions);
   325         if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions
   326             if (e_attr instanceof Exceptions_attribute) {
   327                 Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;
   328                 if (options.compat) { // Bug XXXXXXX whitespace
   329                     if (!(options.showLineAndLocalVariableTables
   330                             || options.showDisassembled
   331                             || options.verbose
   332                             || options.showInternalSignatures
   333                             || options.showAllAttrs)) {
   334                         print("    ");
   335                     }
   336                     print("  ");
   337                 }
   338                 print(" throws ");
   339                 if (methodExceptions != null) { // use generic list if available
   340                     writeList("", methodExceptions, "");
   341                 } else {
   342                     for (int i = 0; i < exceptions.number_of_exceptions; i++) {
   343                         if (i > 0)
   344                             print(", ");
   345                         print(getJavaException(exceptions, i));
   346                     }
   347                 }
   348             } else {
   349                 report("Unexpected or invalid value for Exceptions attribute");
   350             }
   351         }
   353         print(";");
   354         println();
   356         if (options.showInternalSignatures)
   357             println("  Signature: " + getValue(m.descriptor));
   359         if (options.verbose && !options.compat)
   360             writeList("  flags: ", flags.getMethodFlags(), NEWLINE);
   362         Code_attribute code = null;
   363         Attribute c_attr = m.attributes.get(Attribute.Code);
   364         if (c_attr != null) {
   365             if (c_attr instanceof Code_attribute)
   366                 code = (Code_attribute) c_attr;
   367             else
   368                 report("Unexpected or invalid value for Code attribute");
   369         }
   371         if (options.showDisassembled && !options.showAllAttrs) {
   372             if (code != null) {
   373                 println("  Code:");
   374                 codeWriter.writeInstrs(code);
   375                 codeWriter.writeExceptionTable(code);
   376             }
   377             println();
   378         }
   380         if (options.showLineAndLocalVariableTables) {
   381             if (code != null)
   382                 attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);
   383             println();
   384             if (code != null)
   385                 attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);
   386             println();
   387             println();
   388         }
   390         if (options.showAllAttrs) {
   391             Attribute[] attrs = m.attributes.attrs;
   392             for (Attribute attr: attrs)
   393                 attrWriter.write(m, attr, constant_pool);
   395 //            // the following condition is to mimic old javap
   396 //            if (!(attrs.length > 0 &&
   397 //                    attrs[attrs.length - 1] instanceof Exceptions_attribute))
   398             println();
   399         }
   400     }
   402     void writeModifiers(Collection<String> items) {
   403         for (Object item: items) {
   404             print(item);
   405             print(" ");
   406         }
   407     }
   409     void writeList(String prefix, Collection<?> items, String suffix) {
   410         print(prefix);
   411         String sep = "";
   412         for (Object item: items) {
   413             print(sep);
   414             print(item);
   415             sep = ", ";
   416         }
   417         print(suffix);
   418     }
   420     void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {
   421         if (items != null && items.size() > 0)
   422             writeList(prefix, items, suffix);
   423     }
   425     Signature_attribute getSignature(Attributes attributes) {
   426         if (options.compat) // javap does not recognize recent attributes
   427             return null;
   428         return (Signature_attribute) attributes.get(Attribute.Signature);
   429     }
   431     String adjustVarargs(AccessFlags flags, String params) {
   432         if (flags.is(ACC_VARARGS) && !options.compat) {
   433             int i = params.lastIndexOf("[]");
   434             if (i > 0)
   435                 return params.substring(0, i) + "..." + params.substring(i+2);
   436         }
   438         return params;
   439     }
   441     String getJavaName(ClassFile cf) {
   442         try {
   443             return getJavaName(cf.getName());
   444         } catch (ConstantPoolException e) {
   445             return report(e);
   446         }
   447     }
   449     String getJavaSuperclassName(ClassFile cf) {
   450         try {
   451             return getJavaName(cf.getSuperclassName());
   452         } catch (ConstantPoolException e) {
   453             return report(e);
   454         }
   455     }
   457     String getJavaInterfaceName(ClassFile cf, int index) {
   458         try {
   459             return getJavaName(cf.getInterfaceName(index));
   460         } catch (ConstantPoolException e) {
   461             return report(e);
   462         }
   463     }
   465     String getFieldType(Descriptor d) {
   466         try {
   467             return d.getFieldType(constant_pool);
   468         } catch (ConstantPoolException e) {
   469             return report(e);
   470         } catch (DescriptorException e) {
   471             return report(e);
   472         }
   473     }
   475     String getReturnType(Descriptor d) {
   476         try {
   477             return d.getReturnType(constant_pool);
   478         } catch (ConstantPoolException e) {
   479             return report(e);
   480         } catch (DescriptorException e) {
   481             return report(e);
   482         }
   483     }
   485     String getParameterTypes(Descriptor d, AccessFlags flags) {
   486         try {
   487             return adjustVarargs(flags, d.getParameterTypes(constant_pool));
   488         } catch (ConstantPoolException e) {
   489             return report(e);
   490         } catch (DescriptorException e) {
   491             return report(e);
   492         }
   493     }
   495     String getJavaException(Exceptions_attribute attr, int index) {
   496         try {
   497             return getJavaName(attr.getException(index, constant_pool));
   498         } catch (ConstantPoolException e) {
   499             return report(e);
   500         }
   501     }
   503     String getValue(Descriptor d) {
   504         try {
   505             return d.getValue(constant_pool);
   506         } catch (ConstantPoolException e) {
   507             return report(e);
   508         }
   509     }
   511     String getFieldName(Field f) {
   512         try {
   513             return f.getName(constant_pool);
   514         } catch (ConstantPoolException e) {
   515             return report(e);
   516         }
   517     }
   519     String getName(Method m) {
   520         try {
   521             return m.getName(constant_pool);
   522         } catch (ConstantPoolException e) {
   523             return report(e);
   524         }
   525     }
   527     static String getJavaName(String name) {
   528         return name.replace('/', '.');
   529     }
   531     String getSourceFile(SourceFile_attribute attr) {
   532         try {
   533             return attr.getSourceFile(constant_pool);
   534         } catch (ConstantPoolException e) {
   535             return report(e);
   536         }
   537     }
   539     /**
   540      * Get the value of an entry in the constant pool as a Java constant.
   541      * Characters and booleans are represented by CONSTANT_Intgere entries.
   542      * Character and string values are processed to escape characters outside
   543      * the basic printable ASCII set.
   544      * @param d the descriptor, giving the expected type of the constant
   545      * @param index the index of the value in the constant pool
   546      * @return a printable string containing the value of the constant.
   547      */
   548     String getConstantValue(Descriptor d, int index) {
   549         try {
   550             ConstantPool.CPInfo cpInfo = constant_pool.get(index);
   552             switch (cpInfo.getTag()) {
   553                 case ConstantPool.CONSTANT_Integer: {
   554                     ConstantPool.CONSTANT_Integer_info info =
   555                             (ConstantPool.CONSTANT_Integer_info) cpInfo;
   556                     String t = d.getValue(constant_pool);
   557                     if (t.equals("C")) { // character
   558                         return getConstantCharValue((char) info.value);
   559                     } else if (t.equals("Z")) { // boolean
   560                         return String.valueOf(info.value == 1);
   561                     } else { // other: assume integer
   562                         return String.valueOf(info.value);
   563                     }
   564                 }
   566                 case ConstantPool.CONSTANT_String: {
   567                     ConstantPool.CONSTANT_String_info info =
   568                             (ConstantPool.CONSTANT_String_info) cpInfo;
   569                     return getConstantStringValue(info.getString());
   570                 }
   572                 default:
   573                     return constantWriter.stringValue(cpInfo);
   574             }
   575         } catch (ConstantPoolException e) {
   576             return "#" + index;
   577         }
   578     }
   580     private String getConstantCharValue(char c) {
   581         StringBuilder sb = new StringBuilder();
   582         sb.append('\'');
   583         sb.append(esc(c, '\''));
   584         sb.append('\'');
   585         return sb.toString();
   586     }
   588     private String getConstantStringValue(String s) {
   589         StringBuilder sb = new StringBuilder();
   590         sb.append("\"");
   591         for (int i = 0; i < s.length(); i++) {
   592             sb.append(esc(s.charAt(i), '"'));
   593         }
   594         sb.append("\"");
   595         return sb.toString();
   596     }
   598     private String esc(char c, char quote) {
   599         if (32 <= c && c <= 126 && c != quote)
   600             return String.valueOf(c);
   601         else switch (c) {
   602             case '\b': return "\\b";
   603             case '\n': return "\\n";
   604             case '\t': return "\\t";
   605             case '\f': return "\\f";
   606             case '\r': return "\\r";
   607             case '\\': return "\\\\";
   608             case '\'': return "\\'";
   609             case '\"': return "\\\"";
   610             default:   return String.format("\\u%04x", (int) c);
   611         }
   612     }
   614     private Options options;
   615     private AttributeWriter attrWriter;
   616     private CodeWriter codeWriter;
   617     private ConstantWriter constantWriter;
   618     private ClassFile classFile;
   619     private URI uri;
   620     private long lastModified;
   621     private String digestName;
   622     private byte[] digest;
   623     private int size;
   624     private ConstantPool constant_pool;
   625     private Method method;
   626     private static final String NEWLINE = System.getProperty("line.separator", "\n");
   627 }

mercurial