javap/src/main/java/sun/tools/javap/ClassData.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 10 Nov 2012 19:01:28 +0100
branchjavap
changeset 149 32653a09f0db
parent 144 b06660b614db
child 151 40f95fe90cdc
permissions -rw-r--r--
Compiling javap against the emul package. Still need impl for our copy of Hashtable and Vector
     1 /*
     2  * Copyright (c) 2002, 2004, 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 
    27 package sun.tools.javap;
    28 
    29 import java.util.*;
    30 import java.io.*;
    31 
    32 /**
    33  * Central data repository of the Java Disassembler.
    34  * Stores all the information in java class file.
    35  *
    36  * @author  Sucheta Dambalkar (Adopted code from jdis)
    37  */
    38 public class ClassData implements RuntimeConstants {
    39 
    40     private int magic;
    41     private int minor_version;
    42     private int major_version;
    43     private int cpool_count;
    44     private Object cpool[];
    45     private int access;
    46     private int this_class = 0;;
    47     private int super_class;
    48     private int interfaces_count;
    49     private int[] interfaces = new int[0];;
    50     private int fields_count;
    51     private FieldData[] fields;
    52     private int methods_count;
    53     private MethodData[] methods;
    54     private InnerClassData[] innerClasses;
    55     private int attributes_count;
    56     private AttrData[] attrs;
    57     private String classname;
    58     private String superclassname;
    59     private int source_cpx=0;
    60     private byte tags[];
    61     private Hashtable indexHashAscii = new Hashtable();
    62     private String pkgPrefix="";
    63     private int pkgPrefixLen=0;
    64 
    65     /**
    66      * Read classfile to disassemble.
    67      */
    68     public ClassData(InputStream infile) throws IOException {
    69         this.read(new DataInputStream(infile));
    70     }
    71 
    72     /**
    73      * Reads and stores class file information.
    74      */
    75     public void read(DataInputStream in) throws IOException {
    76         // Read the header
    77         magic = in.readInt();
    78         if (magic != JAVA_MAGIC) {
    79             throw new ClassFormatError("wrong magic: " +
    80                                        toHex(magic) + ", expected " +
    81                                        toHex(JAVA_MAGIC));
    82         }
    83         minor_version = in.readShort();
    84         major_version = in.readShort();
    85         if (major_version != JAVA_VERSION) {
    86         }
    87 
    88         // Read the constant pool
    89         readCP(in);
    90         access = in.readUnsignedShort();
    91         this_class = in.readUnsignedShort();
    92         super_class = in.readUnsignedShort();
    93 
    94         //Read interfaces.
    95         interfaces_count = in.readUnsignedShort();
    96         if(interfaces_count > 0){
    97             interfaces = new int[interfaces_count];
    98         }
    99         for (int i = 0; i < interfaces_count; i++) {
   100             interfaces[i]=in.readShort();
   101         }
   102 
   103         // Read the fields
   104         readFields(in);
   105 
   106         // Read the methods
   107         readMethods(in);
   108 
   109         // Read the attributes
   110         attributes_count = in.readUnsignedShort();
   111         attrs=new AttrData[attributes_count];
   112         for (int k = 0; k < attributes_count; k++) {
   113             int name_cpx=in.readUnsignedShort();
   114             if (getTag(name_cpx)==CONSTANT_UTF8
   115                 && getString(name_cpx).equals("SourceFile")
   116                 ){      if (in.readInt()!=2)
   117                     throw new ClassFormatError("invalid attr length");
   118                 source_cpx=in.readUnsignedShort();
   119                 AttrData attr=new AttrData(this);
   120                 attr.read(name_cpx);
   121                 attrs[k]=attr;
   122 
   123             } else if (getTag(name_cpx)==CONSTANT_UTF8
   124                        && getString(name_cpx).equals("InnerClasses")
   125                        ){       int length=in.readInt();
   126                        int num=in.readUnsignedShort();
   127                        if (2+num*8 != length)
   128                            throw new ClassFormatError("invalid attr length");
   129                        innerClasses=new InnerClassData[num];
   130                        for (int j = 0; j < num; j++) {
   131                            InnerClassData innerClass=new InnerClassData(this);
   132                            innerClass.read(in);
   133                            innerClasses[j]=innerClass;
   134                        }
   135                        AttrData attr=new AttrData(this);
   136                        attr.read(name_cpx);
   137                        attrs[k]=attr;
   138             } else {
   139                 AttrData attr=new AttrData(this);
   140                 attr.read(name_cpx, in);
   141                 attrs[k]=attr;
   142             }
   143         }
   144         in.close();
   145     } // end ClassData.read()
   146 
   147     /**
   148      * Reads and stores constant pool info.
   149      */
   150     void readCP(DataInputStream in) throws IOException {
   151         cpool_count = in.readUnsignedShort();
   152         tags = new byte[cpool_count];
   153         cpool = new Object[cpool_count];
   154         for (int i = 1; i < cpool_count; i++) {
   155             byte tag = in.readByte();
   156 
   157             switch(tags[i] = tag) {
   158             case CONSTANT_UTF8:
   159                 String str=in.readUTF();
   160                 indexHashAscii.put(cpool[i] = str, new Integer(i));
   161                 break;
   162             case CONSTANT_INTEGER:
   163                 cpool[i] = new Integer(in.readInt());
   164                 break;
   165             case CONSTANT_FLOAT:
   166                 cpool[i] = new Float(in.readFloat());
   167                 break;
   168             case CONSTANT_LONG:
   169                 cpool[i++] = new Long(in.readLong());
   170                 break;
   171             case CONSTANT_DOUBLE:
   172                 cpool[i++] = new Double(in.readDouble());
   173                 break;
   174             case CONSTANT_CLASS:
   175             case CONSTANT_STRING:
   176                 cpool[i] = new CPX(in.readUnsignedShort());
   177                 break;
   178 
   179             case CONSTANT_FIELD:
   180             case CONSTANT_METHOD:
   181             case CONSTANT_INTERFACEMETHOD:
   182             case CONSTANT_NAMEANDTYPE:
   183                 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
   184                 break;
   185 
   186             case 0:
   187             default:
   188                 throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
   189             }
   190         }
   191     }
   192 
   193     /**
   194      * Reads and strores field info.
   195      */
   196     protected void readFields(DataInputStream in) throws IOException {
   197         int fields_count = in.readUnsignedShort();
   198         fields=new FieldData[fields_count];
   199         for (int k = 0; k < fields_count; k++) {
   200             FieldData field=new FieldData(this);
   201             field.read(in);
   202             fields[k]=field;
   203         }
   204     }
   205 
   206     /**
   207      * Reads and strores Method info.
   208      */
   209     protected void readMethods(DataInputStream in) throws IOException {
   210         int methods_count = in.readUnsignedShort();
   211         methods=new MethodData[methods_count];
   212         for (int k = 0; k < methods_count ; k++) {
   213             MethodData method=new MethodData(this);
   214             method.read(in);
   215             methods[k]=method;
   216         }
   217     }
   218 
   219     /**
   220      * get a string
   221      */
   222     public String getString(int n) {
   223         return (n == 0) ? null : (String)cpool[n];
   224     }
   225 
   226     /**
   227      * get the type of constant given an index
   228      */
   229     public byte getTag(int n) {
   230         try{
   231             return tags[n];
   232         } catch (ArrayIndexOutOfBoundsException e) {
   233             return (byte)100;
   234         }
   235     }
   236 
   237     static final String hexString="0123456789ABCDEF";
   238 
   239     public static char hexTable[]=hexString.toCharArray();
   240 
   241     static String toHex(long val, int width) {
   242         StringBuffer s = new StringBuffer();
   243         for (int i=width-1; i>=0; i--)
   244             s.append(hexTable[((int)(val>>(4*i)))&0xF]);
   245         return "0x"+s.toString();
   246     }
   247 
   248     static String toHex(long val) {
   249         int width;
   250         for (width=16; width>0; width--) {
   251             if ((val>>(width-1)*4)!=0) break;
   252         }
   253         return toHex(val, width);
   254     }
   255 
   256     static String toHex(int val) {
   257         int width;
   258         for (width=8; width>0; width--) {
   259             if ((val>>(width-1)*4)!=0) break;
   260         }
   261         return toHex(val, width);
   262     }
   263 
   264     /**
   265      * Returns the name of this class.
   266      */
   267     public String getClassName() {
   268         String res=null;
   269         if (this_class==0) {
   270             return res;
   271         }
   272         int tcpx;
   273         try {
   274             if (tags[this_class]!=CONSTANT_CLASS) {
   275                 return res; //"<CP["+cpx+"] is not a Class> ";
   276             }
   277             tcpx=((CPX)cpool[this_class]).cpx;
   278         } catch (ArrayIndexOutOfBoundsException e) {
   279             return res; // "#"+cpx+"// invalid constant pool index";
   280         } catch (Throwable e) {
   281             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   282         }
   283 
   284         try {
   285             return (String)(cpool[tcpx]);
   286         } catch (ArrayIndexOutOfBoundsException e) {
   287             return  res; // "class #"+scpx+"// invalid constant pool index";
   288         } catch (ClassCastException e) {
   289             return  res; // "class #"+scpx+"// invalid constant pool reference";
   290         } catch (Throwable e) {
   291             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   292         }
   293 
   294     }
   295 
   296     /**
   297      * Returns the name of class at perticular index.
   298      */
   299     public String getClassName(int cpx) {
   300         String res="#"+cpx;
   301         if (cpx==0) {
   302             return res;
   303         }
   304         int scpx;
   305         try {
   306             if (tags[cpx]!=CONSTANT_CLASS) {
   307                 return res; //"<CP["+cpx+"] is not a Class> ";
   308             }
   309             scpx=((CPX)cpool[cpx]).cpx;
   310         } catch (ArrayIndexOutOfBoundsException e) {
   311             return res; // "#"+cpx+"// invalid constant pool index";
   312         } catch (Throwable e) {
   313             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   314         }
   315         res="#"+scpx;
   316         try {
   317             return (String)(cpool[scpx]);
   318         } catch (ArrayIndexOutOfBoundsException e) {
   319             return  res; // "class #"+scpx+"// invalid constant pool index";
   320         } catch (ClassCastException e) {
   321             return  res; // "class #"+scpx+"// invalid constant pool reference";
   322         } catch (Throwable e) {
   323             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   324         }
   325     }
   326 
   327     /**
   328      * Returns true if it is a class
   329      */
   330     public boolean isClass() {
   331         if((access & ACC_INTERFACE) == 0) return true;
   332         return false;
   333     }
   334 
   335     /**
   336      * Returns true if it is a interface.
   337      */
   338     public boolean isInterface(){
   339         if((access & ACC_INTERFACE) != 0) return true;
   340         return false;
   341     }
   342 
   343     /**
   344      * Returns true if this member is public, false otherwise.
   345      */
   346     public boolean isPublic(){
   347         return (access & ACC_PUBLIC) != 0;
   348     }
   349 
   350     /**
   351      * Returns the access of this class or interface.
   352      */
   353     public String[] getAccess(){
   354         Vector v = new Vector();
   355         if ((access & ACC_PUBLIC)   !=0) v.addElement("public");
   356         if ((access & ACC_FINAL)    !=0) v.addElement("final");
   357         if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract");
   358         String[] accflags = new String[v.size()];
   359         v.copyInto(accflags);
   360         return accflags;
   361     }
   362 
   363     /**
   364      * Returns list of innerclasses.
   365      */
   366     public InnerClassData[] getInnerClasses(){
   367         return innerClasses;
   368     }
   369 
   370     /**
   371      * Returns list of attributes.
   372      */
   373     public AttrData[] getAttributes(){
   374         return attrs;
   375     }
   376 
   377     /**
   378      * Returns true if superbit is set.
   379      */
   380     public boolean isSuperSet(){
   381         if ((access & ACC_SUPER)   !=0) return true;
   382         return false;
   383     }
   384 
   385     /**
   386      * Returns super class name.
   387      */
   388     public String getSuperClassName(){
   389         String res=null;
   390         if (super_class==0) {
   391             return res;
   392         }
   393         int scpx;
   394         try {
   395             if (tags[super_class]!=CONSTANT_CLASS) {
   396                 return res; //"<CP["+cpx+"] is not a Class> ";
   397             }
   398             scpx=((CPX)cpool[super_class]).cpx;
   399         } catch (ArrayIndexOutOfBoundsException e) {
   400             return res; // "#"+cpx+"// invalid constant pool index";
   401         } catch (Throwable e) {
   402             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   403         }
   404 
   405         try {
   406             return (String)(cpool[scpx]);
   407         } catch (ArrayIndexOutOfBoundsException e) {
   408             return  res; // "class #"+scpx+"// invalid constant pool index";
   409         } catch (ClassCastException e) {
   410             return  res; // "class #"+scpx+"// invalid constant pool reference";
   411         } catch (Throwable e) {
   412             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   413         }
   414     }
   415 
   416     /**
   417      * Returns list of super interfaces.
   418      */
   419     public String[] getSuperInterfaces(){
   420         String interfacenames[] = new String[interfaces.length];
   421         int interfacecpx = -1;
   422         for(int i = 0; i < interfaces.length; i++){
   423             interfacecpx=((CPX)cpool[interfaces[i]]).cpx;
   424             interfacenames[i] = (String)(cpool[interfacecpx]);
   425         }
   426         return interfacenames;
   427     }
   428 
   429     /**
   430      * Returns string at prticular constant pool index.
   431      */
   432     public String getStringValue(int cpoolx) {
   433         try {
   434             return ((String)cpool[cpoolx]);
   435         } catch (ArrayIndexOutOfBoundsException e) {
   436             return "//invalid constant pool index:"+cpoolx;
   437         } catch (ClassCastException e) {
   438             return "//invalid constant pool ref:"+cpoolx;
   439         }
   440     }
   441 
   442     /**
   443      * Returns list of field info.
   444      */
   445     public  FieldData[] getFields(){
   446         return fields;
   447     }
   448 
   449     /**
   450      * Returns list of method info.
   451      */
   452     public  MethodData[] getMethods(){
   453         return methods;
   454     }
   455 
   456     /**
   457      * Returns constant pool entry at that index.
   458      */
   459     public CPX2 getCpoolEntry(int cpx){
   460         return ((CPX2)(cpool[cpx]));
   461     }
   462 
   463     public Object getCpoolEntryobj(int cpx){
   464         return (cpool[cpx]);
   465     }
   466 
   467     /**
   468      * Returns index of this class.
   469      */
   470     public int getthis_cpx(){
   471         return this_class;
   472     }
   473 
   474     public String TagString (int tag) {
   475         String res=Tables.tagName(tag);
   476         if (res==null)  return "BOGUS_TAG:"+tag;
   477         return res;
   478     }
   479 
   480     /**
   481      * Returns string at that index.
   482      */
   483     public String StringValue(int cpx) {
   484         if (cpx==0) return "#0";
   485         int tag;
   486         Object x;
   487         String suffix="";
   488         try {
   489             tag=tags[cpx];
   490             x=cpool[cpx];
   491         } catch (IndexOutOfBoundsException e) {
   492             return "<Incorrect CP index:"+cpx+">";
   493         }
   494 
   495         if (x==null) return "<NULL>";
   496         switch (tag) {
   497         case CONSTANT_UTF8: {
   498             StringBuffer sb=new StringBuffer();
   499             String s=(String)x;
   500             for (int k=0; k<s.length(); k++) {
   501                 char c=s.charAt(k);
   502                 switch (c) {
   503                 case '\t': sb.append('\\').append('t'); break;
   504                 case '\n': sb.append('\\').append('n'); break;
   505                 case '\r': sb.append('\\').append('r'); break;
   506                 case '\"': sb.append('\\').append('\"'); break;
   507                 default: sb.append(c);
   508                 }
   509             }
   510             return sb.toString();
   511         }
   512         case CONSTANT_DOUBLE: {
   513             Double d=(Double)x;
   514             String sd=d.toString();
   515             return sd+"d";
   516         }
   517         case CONSTANT_FLOAT: {
   518             Float f=(Float)x;
   519             String sf=(f).toString();
   520             return sf+"f";
   521         }
   522         case CONSTANT_LONG: {
   523             Long ln = (Long)x;
   524             return ln.toString()+'l';
   525         }
   526         case CONSTANT_INTEGER: {
   527             Integer in = (Integer)x;
   528             return in.toString();
   529         }
   530         case CONSTANT_CLASS:
   531             return javaName(getClassName(cpx));
   532         case CONSTANT_STRING:
   533             return StringValue(((CPX)x).cpx);
   534         case CONSTANT_FIELD:
   535         case CONSTANT_METHOD:
   536         case CONSTANT_INTERFACEMETHOD:
   537             //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
   538              return javaName(getClassName(((CPX2)x).cpx1))+"."+StringValue(((CPX2)x).cpx2);
   539 
   540         case CONSTANT_NAMEANDTYPE:
   541             return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
   542         default:
   543             return "UnknownTag"; //TBD
   544         }
   545     }
   546 
   547     /**
   548      * Returns resolved java type name.
   549      */
   550     public String javaName(String name) {
   551         if( name==null) return "null";
   552         int len=name.length();
   553         if (len==0) return "\"\"";
   554         int cc='/';
   555     fullname: { // xxx/yyy/zzz
   556             int cp;
   557             for (int k=0; k<len; k += Character.charCount(cp)) {
   558                 cp=name.codePointAt(k);
   559                 if (cc=='/') {
   560                     if (!isJavaIdentifierStart(cp)) break fullname;
   561                 } else if (cp!='/') {
   562                     if (!isJavaIdentifierPart(cp)) break fullname;
   563                 }
   564                 cc=cp;
   565             }
   566             return name;
   567         }
   568         return "\""+name+"\"";
   569     }
   570 
   571     public String getName(int cpx) {
   572         String res;
   573         try {
   574             return javaName((String)cpool[cpx]); //.replace('/','.');
   575         } catch (ArrayIndexOutOfBoundsException e) {
   576             return "<invalid constant pool index:"+cpx+">";
   577         } catch (ClassCastException e) {
   578             return "<invalid constant pool ref:"+cpx+">";
   579         }
   580     }
   581 
   582     /**
   583      * Returns unqualified class name.
   584      */
   585     public String getShortClassName(int cpx) {
   586         String classname=javaName(getClassName(cpx));
   587         pkgPrefixLen=classname.lastIndexOf("/")+1;
   588         if (pkgPrefixLen!=0) {
   589             pkgPrefix=classname.substring(0,pkgPrefixLen);
   590             if (classname.startsWith(pkgPrefix)) {
   591                 return classname.substring(pkgPrefixLen);
   592             }
   593         }
   594         return classname;
   595     }
   596 
   597     /**
   598      * Returns source file name.
   599      */
   600     public String getSourceName(){
   601         return getName(source_cpx);
   602     }
   603 
   604     /**
   605      * Returns package name.
   606      */
   607     public String getPkgName(){
   608         String classname=getClassName(this_class);
   609         pkgPrefixLen=classname.lastIndexOf("/")+1;
   610         if (pkgPrefixLen!=0) {
   611             pkgPrefix=classname.substring(0,pkgPrefixLen);
   612             return("package  "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n");
   613         }else return null;
   614     }
   615 
   616     /**
   617      * Returns total constant pool entry count.
   618      */
   619     public int getCpoolCount(){
   620         return cpool_count;
   621     }
   622 
   623     public String StringTag(int cpx) {
   624         byte tag=0;
   625         String str=null;
   626         try {
   627             if (cpx==0) throw new IndexOutOfBoundsException();
   628             tag=tags[cpx];
   629             return      TagString(tag);
   630         } catch (IndexOutOfBoundsException e) {
   631             str="Incorrect CP index:"+cpx;
   632         }
   633         return str;
   634     }
   635 
   636     /**
   637      * Returns minor version of class file.
   638      */
   639     public int getMinor_version(){
   640         return minor_version;
   641     }
   642 
   643     /**
   644      * Returns major version of class file.
   645      */
   646     public int getMajor_version(){
   647         return major_version;
   648     }
   649 
   650     private boolean isJavaIdentifierStart(int cp) {
   651         return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
   652     }
   653 
   654     private boolean isJavaIdentifierPart(int cp) {
   655         return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
   656     }
   657 }