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