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

Tue, 28 Dec 2010 15:54:52 -0800

author
ohair
date
Tue, 28 Dec 2010 15:54:52 -0800
changeset 798
4868a36f6fd8
parent 581
f2fdd52e4e87
child 953
c55928005af4
permissions
-rw-r--r--

6962318: Update copyright year
Reviewed-by: xdono

     1 /*
     2  * Copyright (c) 2007, 2010, 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.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 supported API.
    58  *  If 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     protected ClassFile getClassFile() {
    97         return classFile;
    98     }
   100     protected void setClassFile(ClassFile cf) {
   101         classFile = cf;
   102         constant_pool = classFile.constant_pool;
   103     }
   105     protected Method getMethod() {
   106         return method;
   107     }
   109     protected void setMethod(Method m) {
   110         method = m;
   111     }
   113     public void write(ClassFile cf) {
   114         setClassFile(cf);
   116         if ((options.sysInfo || options.verbose) && !options.compat) {
   117             if (uri != null) {
   118                 if (uri.getScheme().equals("file"))
   119                     println("Classfile " + uri.getPath());
   120                 else
   121                     println("Classfile " + uri);
   122             }
   123             indent(+1);
   124             if (lastModified != -1) {
   125                 Date lm = new Date(lastModified);
   126                 DateFormat df = DateFormat.getDateInstance();
   127                 if (size > 0) {
   128                     println("Last modified " + df.format(lm) + "; size " + size + " bytes");
   129                 } else {
   130                     println("Last modified " + df.format(lm));
   131                 }
   132             } else if (size > 0) {
   133                 println("Size " + size + " bytes");
   134             }
   135             if (digestName != null && digest != null) {
   136                 StringBuilder sb = new StringBuilder();
   137                 for (byte b: digest)
   138                     sb.append(String.format("%02x", b));
   139                 println(digestName + " checksum " + sb);
   140             }
   141         }
   143         Attribute sfa = cf.getAttribute(Attribute.SourceFile);
   144         if (sfa instanceof SourceFile_attribute) {
   145             println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
   146         }
   148         if ((options.sysInfo || options.verbose) && !options.compat) {
   149             indent(-1);
   150         }
   152         String name = getJavaName(classFile);
   153         AccessFlags flags = cf.access_flags;
   155         writeModifiers(flags.getClassModifiers());
   157         if (classFile.isClass())
   158             print("class ");
   159         else if (classFile.isInterface())
   160             print("interface ");
   162         print(name);
   164         Signature_attribute sigAttr = getSignature(cf.attributes);
   165         if (sigAttr == null) {
   166             // use info from class file header
   167             if (classFile.isClass() && classFile.super_class != 0 ) {
   168                 String sn = getJavaSuperclassName(cf);
   169                 print(" extends ");
   170                 print(sn);
   171             }
   172             for (int i = 0; i < classFile.interfaces.length; i++) {
   173                 print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");
   174                 print(getJavaInterfaceName(classFile, i));
   175             }
   176         } else {
   177             try {
   178                 Type t = sigAttr.getParsedSignature().getType(constant_pool);
   179                 // The signature parser cannot disambiguate between a
   180                 // FieldType and a ClassSignatureType that only contains a superclass type.
   181                 if (t instanceof Type.ClassSigType)
   182                     print(getJavaName(t.toString()));
   183                 else {
   184                     print(" extends ");
   185                     print(getJavaName(t.toString()));
   186                 }
   187             } catch (ConstantPoolException e) {
   188                 print(report(e));
   189             }
   190         }
   192         if (options.verbose) {
   193             println();
   194             indent(+1);
   195             attrWriter.write(cf, cf.attributes, constant_pool);
   196             println("minor version: " + cf.minor_version);
   197             println("major version: " + cf.major_version);
   198             if (!options.compat)
   199               writeList("flags: ", flags.getClassFlags(), NEWLINE);
   200             indent(-1);
   201             constantWriter.writeConstantPool();
   202         } else {
   203             print(" ");
   204         }
   206         println("{");
   207         indent(+1);
   208         writeFields();
   209         writeMethods();
   210         indent(-1);
   211         println("}");
   212     }
   214     protected void writeFields() {
   215         for (Field f: classFile.fields) {
   216             writeField(f);
   217         }
   218     }
   220     protected void writeField(Field f) {
   221         if (!options.checkAccess(f.access_flags))
   222             return;
   224         AccessFlags flags = f.access_flags;
   225         writeModifiers(flags.getFieldModifiers());
   226         Signature_attribute sigAttr = getSignature(f.attributes);
   227         if (sigAttr == null)
   228             print(getJavaFieldType(f.descriptor));
   229         else {
   230             try {
   231                 Type t = sigAttr.getParsedSignature().getType(constant_pool);
   232                 print(getJavaName(t.toString()));
   233             } catch (ConstantPoolException e) {
   234                 // report error?
   235                 // fall back on non-generic descriptor
   236                 print(getJavaFieldType(f.descriptor));
   237             }
   238         }
   239         print(" ");
   240         print(getFieldName(f));
   241         if (options.showConstants && !options.compat) { // BUG 4111861 print static final field contents
   242             Attribute a = f.attributes.get(Attribute.ConstantValue);
   243             if (a instanceof ConstantValue_attribute) {
   244                 print(" = ");
   245                 ConstantValue_attribute cv = (ConstantValue_attribute) a;
   246                 print(getConstantValue(f.descriptor, cv.constantvalue_index));
   247             }
   248         }
   249         print(";");
   250         println();
   252         indent(+1);
   254         if (options.showInternalSignatures)
   255             println("Signature: " + getValue(f.descriptor));
   257         if (options.verbose && !options.compat)
   258             writeList("flags: ", flags.getFieldFlags(), NEWLINE);
   260         if (options.showAllAttrs) {
   261             for (Attribute attr: f.attributes)
   262                 attrWriter.write(f, attr, constant_pool);
   263             println();
   264         }
   266         indent(-1);
   268         if (options.showDisassembled || options.showLineAndLocalVariableTables)
   269             println();
   270     }
   272     protected void writeMethods() {
   273         for (Method m: classFile.methods)
   274             writeMethod(m);
   275         setPendingNewline(false);
   276     }
   278     protected void writeMethod(Method m) {
   279         if (!options.checkAccess(m.access_flags))
   280             return;
   282         method = m;
   284         AccessFlags flags = m.access_flags;
   286         Descriptor d;
   287         Type.MethodType methodType;
   288         List<? extends Type> methodExceptions;
   290         Signature_attribute sigAttr = getSignature(m.attributes);
   291         if (sigAttr == null) {
   292             d = m.descriptor;
   293             methodType = null;
   294             methodExceptions = null;
   295         } else {
   296             Signature methodSig = sigAttr.getParsedSignature();
   297             d = methodSig;
   298             try {
   299                 methodType = (Type.MethodType) methodSig.getType(constant_pool);
   300                 methodExceptions = methodType.throwsTypes;
   301                 if (methodExceptions != null && methodExceptions.size() == 0)
   302                     methodExceptions = null;
   303             } catch (ConstantPoolException e) {
   304                 // report error?
   305                 // fall back on standard descriptor
   306                 methodType = null;
   307                 methodExceptions = null;
   308             }
   309         }
   311         writeModifiers(flags.getMethodModifiers());
   312         if (methodType != null) {
   313             writeListIfNotEmpty("<", methodType.typeParamTypes, "> ");
   314         }
   315         if (getName(m).equals("<init>")) {
   316             print(getJavaName(classFile));
   317             print(getJavaParameterTypes(d, flags));
   318         } else if (getName(m).equals("<clinit>")) {
   319             print("{}");
   320         } else {
   321             print(getJavaReturnType(d));
   322             print(" ");
   323             print(getName(m));
   324             print(getJavaParameterTypes(d, flags));
   325         }
   327         Attribute e_attr = m.attributes.get(Attribute.Exceptions);
   328         if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions
   329             if (e_attr instanceof Exceptions_attribute) {
   330                 Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;
   331                 print(" throws ");
   332                 if (methodExceptions != null) { // use generic list if available
   333                     writeList("", methodExceptions, "");
   334                 } else {
   335                     for (int i = 0; i < exceptions.number_of_exceptions; i++) {
   336                         if (i > 0)
   337                             print(", ");
   338                         print(getJavaException(exceptions, i));
   339                     }
   340                 }
   341             } else {
   342                 report("Unexpected or invalid value for Exceptions attribute");
   343             }
   344         }
   346         println(";");
   348         indent(+1);
   350         if (options.showInternalSignatures) {
   351             println("Signature: " + getValue(m.descriptor));
   352         }
   354         if (options.verbose && !options.compat) {
   355             writeList("flags: ", flags.getMethodFlags(), NEWLINE);
   356         }
   358         Code_attribute code = null;
   359         Attribute c_attr = m.attributes.get(Attribute.Code);
   360         if (c_attr != null) {
   361             if (c_attr instanceof Code_attribute)
   362                 code = (Code_attribute) c_attr;
   363             else
   364                 report("Unexpected or invalid value for Code attribute");
   365         }
   367         if (options.showDisassembled && !options.showAllAttrs) {
   368             if (code != null) {
   369                 println("Code:");
   370                 codeWriter.writeInstrs(code);
   371                 codeWriter.writeExceptionTable(code);
   372             }
   373         }
   375         if (options.showLineAndLocalVariableTables) {
   376             if (code != null) {
   377                 attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);
   378                 attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);
   379             }
   380         }
   382         if (options.showAllAttrs) {
   383             Attribute[] attrs = m.attributes.attrs;
   384             for (Attribute attr: attrs)
   385                 attrWriter.write(m, attr, constant_pool);
   386         }
   388         indent(-1);
   390         // set pendingNewline to write a newline before the next method (if any)
   391         // if a separator is desired
   392         setPendingNewline(
   393                 options.showDisassembled ||
   394                 options.showAllAttrs ||
   395                 options.showInternalSignatures ||
   396                 options.showLineAndLocalVariableTables ||
   397                 options.verbose);
   398     }
   400     void writeModifiers(Collection<String> items) {
   401         for (Object item: items) {
   402             print(item);
   403             print(" ");
   404         }
   405     }
   407     void writeList(String prefix, Collection<?> items, String suffix) {
   408         print(prefix);
   409         String sep = "";
   410         for (Object item: items) {
   411             print(sep);
   412             print(item);
   413             sep = ", ";
   414         }
   415         print(suffix);
   416     }
   418     void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {
   419         if (items != null && items.size() > 0)
   420             writeList(prefix, items, suffix);
   421     }
   423     Signature_attribute getSignature(Attributes attributes) {
   424         if (options.compat) // javap does not recognize recent attributes
   425             return null;
   426         return (Signature_attribute) attributes.get(Attribute.Signature);
   427     }
   429     String adjustVarargs(AccessFlags flags, String params) {
   430         if (flags.is(ACC_VARARGS) && !options.compat) {
   431             int i = params.lastIndexOf("[]");
   432             if (i > 0)
   433                 return params.substring(0, i) + "..." + params.substring(i+2);
   434         }
   436         return params;
   437     }
   439     String getJavaName(ClassFile cf) {
   440         try {
   441             return getJavaName(cf.getName());
   442         } catch (ConstantPoolException e) {
   443             return report(e);
   444         }
   445     }
   447     String getJavaSuperclassName(ClassFile cf) {
   448         try {
   449             return getJavaName(cf.getSuperclassName());
   450         } catch (ConstantPoolException e) {
   451             return report(e);
   452         }
   453     }
   455     String getJavaInterfaceName(ClassFile cf, int index) {
   456         try {
   457             return getJavaName(cf.getInterfaceName(index));
   458         } catch (ConstantPoolException e) {
   459             return report(e);
   460         }
   461     }
   463     String getJavaFieldType(Descriptor d) {
   464         try {
   465             return getJavaName(d.getFieldType(constant_pool));
   466         } catch (ConstantPoolException e) {
   467             return report(e);
   468         } catch (DescriptorException e) {
   469             return report(e);
   470         }
   471     }
   473     String getJavaReturnType(Descriptor d) {
   474         try {
   475             return getJavaName(d.getReturnType(constant_pool));
   476         } catch (ConstantPoolException e) {
   477             return report(e);
   478         } catch (DescriptorException e) {
   479             return report(e);
   480         }
   481     }
   483     String getJavaParameterTypes(Descriptor d, AccessFlags flags) {
   484         try {
   485             return getJavaName(adjustVarargs(flags, d.getParameterTypes(constant_pool)));
   486         } catch (ConstantPoolException e) {
   487             return report(e);
   488         } catch (DescriptorException e) {
   489             return report(e);
   490         }
   491     }
   493     String getJavaException(Exceptions_attribute attr, int index) {
   494         try {
   495             return getJavaName(attr.getException(index, constant_pool));
   496         } catch (ConstantPoolException e) {
   497             return report(e);
   498         }
   499     }
   501     String getValue(Descriptor d) {
   502         try {
   503             return d.getValue(constant_pool);
   504         } catch (ConstantPoolException e) {
   505             return report(e);
   506         }
   507     }
   509     String getFieldName(Field f) {
   510         try {
   511             return f.getName(constant_pool);
   512         } catch (ConstantPoolException e) {
   513             return report(e);
   514         }
   515     }
   517     String getName(Method m) {
   518         try {
   519             return m.getName(constant_pool);
   520         } catch (ConstantPoolException e) {
   521             return report(e);
   522         }
   523     }
   525     static String getJavaName(String name) {
   526         return name.replace('/', '.');
   527     }
   529     String getSourceFile(SourceFile_attribute attr) {
   530         try {
   531             return attr.getSourceFile(constant_pool);
   532         } catch (ConstantPoolException e) {
   533             return report(e);
   534         }
   535     }
   537     /**
   538      * Get the value of an entry in the constant pool as a Java constant.
   539      * Characters and booleans are represented by CONSTANT_Intgere entries.
   540      * Character and string values are processed to escape characters outside
   541      * the basic printable ASCII set.
   542      * @param d the descriptor, giving the expected type of the constant
   543      * @param index the index of the value in the constant pool
   544      * @return a printable string containing the value of the constant.
   545      */
   546     String getConstantValue(Descriptor d, int index) {
   547         try {
   548             ConstantPool.CPInfo cpInfo = constant_pool.get(index);
   550             switch (cpInfo.getTag()) {
   551                 case ConstantPool.CONSTANT_Integer: {
   552                     ConstantPool.CONSTANT_Integer_info info =
   553                             (ConstantPool.CONSTANT_Integer_info) cpInfo;
   554                     String t = d.getValue(constant_pool);
   555                     if (t.equals("C")) { // character
   556                         return getConstantCharValue((char) info.value);
   557                     } else if (t.equals("Z")) { // boolean
   558                         return String.valueOf(info.value == 1);
   559                     } else { // other: assume integer
   560                         return String.valueOf(info.value);
   561                     }
   562                 }
   564                 case ConstantPool.CONSTANT_String: {
   565                     ConstantPool.CONSTANT_String_info info =
   566                             (ConstantPool.CONSTANT_String_info) cpInfo;
   567                     return getConstantStringValue(info.getString());
   568                 }
   570                 default:
   571                     return constantWriter.stringValue(cpInfo);
   572             }
   573         } catch (ConstantPoolException e) {
   574             return "#" + index;
   575         }
   576     }
   578     private String getConstantCharValue(char c) {
   579         StringBuilder sb = new StringBuilder();
   580         sb.append('\'');
   581         sb.append(esc(c, '\''));
   582         sb.append('\'');
   583         return sb.toString();
   584     }
   586     private String getConstantStringValue(String s) {
   587         StringBuilder sb = new StringBuilder();
   588         sb.append("\"");
   589         for (int i = 0; i < s.length(); i++) {
   590             sb.append(esc(s.charAt(i), '"'));
   591         }
   592         sb.append("\"");
   593         return sb.toString();
   594     }
   596     private String esc(char c, char quote) {
   597         if (32 <= c && c <= 126 && c != quote)
   598             return String.valueOf(c);
   599         else switch (c) {
   600             case '\b': return "\\b";
   601             case '\n': return "\\n";
   602             case '\t': return "\\t";
   603             case '\f': return "\\f";
   604             case '\r': return "\\r";
   605             case '\\': return "\\\\";
   606             case '\'': return "\\'";
   607             case '\"': return "\\\"";
   608             default:   return String.format("\\u%04x", (int) c);
   609         }
   610     }
   612     private Options options;
   613     private AttributeWriter attrWriter;
   614     private CodeWriter codeWriter;
   615     private ConstantWriter constantWriter;
   616     private ClassFile classFile;
   617     private URI uri;
   618     private long lastModified;
   619     private String digestName;
   620     private byte[] digest;
   621     private int size;
   622     private ConstantPool constant_pool;
   623     private Method method;
   624     private static final String NEWLINE = System.getProperty("line.separator", "\n");
   625 }

mercurial