Compiling javap against the emul package. Still need impl for our copy of Hashtable and Vector
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.
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.
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).
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.
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
27 package sun.tools.javap;
33 * Central data repository of the Java Disassembler.
34 * Stores all the information in java class file.
36 * @author Sucheta Dambalkar (Adopted code from jdis)
38 public class ClassData implements RuntimeConstants {
41 private int minor_version;
42 private int major_version;
43 private int cpool_count;
44 private Object cpool[];
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;
61 private Hashtable indexHashAscii = new Hashtable();
62 private String pkgPrefix="";
63 private int pkgPrefixLen=0;
66 * Read classfile to disassemble.
68 public ClassData(InputStream infile) throws IOException {
69 this.read(new DataInputStream(infile));
73 * Reads and stores class file information.
75 public void read(DataInputStream in) throws IOException {
78 if (magic != JAVA_MAGIC) {
79 throw new ClassFormatError("wrong magic: " +
80 toHex(magic) + ", expected " +
83 minor_version = in.readShort();
84 major_version = in.readShort();
85 if (major_version != JAVA_VERSION) {
88 // Read the constant pool
90 access = in.readUnsignedShort();
91 this_class = in.readUnsignedShort();
92 super_class = in.readUnsignedShort();
95 interfaces_count = in.readUnsignedShort();
96 if(interfaces_count > 0){
97 interfaces = new int[interfaces_count];
99 for (int i = 0; i < interfaces_count; i++) {
100 interfaces[i]=in.readShort();
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);
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);
133 innerClasses[j]=innerClass;
135 AttrData attr=new AttrData(this);
139 AttrData attr=new AttrData(this);
140 attr.read(name_cpx, in);
145 } // end ClassData.read()
148 * Reads and stores constant pool info.
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();
157 switch(tags[i] = tag) {
159 String str=in.readUTF();
160 indexHashAscii.put(cpool[i] = str, new Integer(i));
162 case CONSTANT_INTEGER:
163 cpool[i] = new Integer(in.readInt());
166 cpool[i] = new Float(in.readFloat());
169 cpool[i++] = new Long(in.readLong());
171 case CONSTANT_DOUBLE:
172 cpool[i++] = new Double(in.readDouble());
175 case CONSTANT_STRING:
176 cpool[i] = new CPX(in.readUnsignedShort());
180 case CONSTANT_METHOD:
181 case CONSTANT_INTERFACEMETHOD:
182 case CONSTANT_NAMEANDTYPE:
183 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
188 throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
194 * Reads and strores field info.
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);
207 * Reads and strores Method info.
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);
222 public String getString(int n) {
223 return (n == 0) ? null : (String)cpool[n];
227 * get the type of constant given an index
229 public byte getTag(int n) {
232 } catch (ArrayIndexOutOfBoundsException e) {
237 static final String hexString="0123456789ABCDEF";
239 public static char hexTable[]=hexString.toCharArray();
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();
248 static String toHex(long val) {
250 for (width=16; width>0; width--) {
251 if ((val>>(width-1)*4)!=0) break;
253 return toHex(val, width);
256 static String toHex(int val) {
258 for (width=8; width>0; width--) {
259 if ((val>>(width-1)*4)!=0) break;
261 return toHex(val, width);
265 * Returns the name of this class.
267 public String getClassName() {
274 if (tags[this_class]!=CONSTANT_CLASS) {
275 return res; //"<CP["+cpx+"] is not a Class> ";
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";
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";
297 * Returns the name of class at perticular index.
299 public String getClassName(int cpx) {
306 if (tags[cpx]!=CONSTANT_CLASS) {
307 return res; //"<CP["+cpx+"] is not a Class> ";
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";
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";
328 * Returns true if it is a class
330 public boolean isClass() {
331 if((access & ACC_INTERFACE) == 0) return true;
336 * Returns true if it is a interface.
338 public boolean isInterface(){
339 if((access & ACC_INTERFACE) != 0) return true;
344 * Returns true if this member is public, false otherwise.
346 public boolean isPublic(){
347 return (access & ACC_PUBLIC) != 0;
351 * Returns the access of this class or interface.
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);
364 * Returns list of innerclasses.
366 public InnerClassData[] getInnerClasses(){
371 * Returns list of attributes.
373 public AttrData[] getAttributes(){
378 * Returns true if superbit is set.
380 public boolean isSuperSet(){
381 if ((access & ACC_SUPER) !=0) return true;
386 * Returns super class name.
388 public String getSuperClassName(){
390 if (super_class==0) {
395 if (tags[super_class]!=CONSTANT_CLASS) {
396 return res; //"<CP["+cpx+"] is not a Class> ";
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";
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";
417 * Returns list of super interfaces.
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]);
426 return interfacenames;
430 * Returns string at prticular constant pool index.
432 public String getStringValue(int cpoolx) {
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;
443 * Returns list of field info.
445 public FieldData[] getFields(){
450 * Returns list of method info.
452 public MethodData[] getMethods(){
457 * Returns constant pool entry at that index.
459 public CPX2 getCpoolEntry(int cpx){
460 return ((CPX2)(cpool[cpx]));
463 public Object getCpoolEntryobj(int cpx){
468 * Returns index of this class.
470 public int getthis_cpx(){
474 public String TagString (int tag) {
475 String res=Tables.tagName(tag);
476 if (res==null) return "BOGUS_TAG:"+tag;
481 * Returns string at that index.
483 public String StringValue(int cpx) {
484 if (cpx==0) return "#0";
491 } catch (IndexOutOfBoundsException e) {
492 return "<Incorrect CP index:"+cpx+">";
495 if (x==null) return "<NULL>";
497 case CONSTANT_UTF8: {
498 StringBuffer sb=new StringBuffer();
500 for (int k=0; k<s.length(); k++) {
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);
510 return sb.toString();
512 case CONSTANT_DOUBLE: {
514 String sd=d.toString();
517 case CONSTANT_FLOAT: {
519 String sf=(f).toString();
522 case CONSTANT_LONG: {
524 return ln.toString()+'l';
526 case CONSTANT_INTEGER: {
527 Integer in = (Integer)x;
528 return in.toString();
531 return javaName(getClassName(cpx));
532 case CONSTANT_STRING:
533 return StringValue(((CPX)x).cpx);
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);
540 case CONSTANT_NAMEANDTYPE:
541 return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
543 return "UnknownTag"; //TBD
548 * Returns resolved java type name.
550 public String javaName(String name) {
551 if( name==null) return "null";
552 int len=name.length();
553 if (len==0) return "\"\"";
555 fullname: { // xxx/yyy/zzz
557 for (int k=0; k<len; k += Character.charCount(cp)) {
558 cp=name.codePointAt(k);
560 if (!isJavaIdentifierStart(cp)) break fullname;
561 } else if (cp!='/') {
562 if (!isJavaIdentifierPart(cp)) break fullname;
568 return "\""+name+"\"";
571 public String getName(int cpx) {
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+">";
583 * Returns unqualified class name.
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);
598 * Returns source file name.
600 public String getSourceName(){
601 return getName(source_cpx);
605 * Returns package name.
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");
617 * Returns total constant pool entry count.
619 public int getCpoolCount(){
623 public String StringTag(int cpx) {
627 if (cpx==0) throw new IndexOutOfBoundsException();
629 return TagString(tag);
630 } catch (IndexOutOfBoundsException e) {
631 str="Incorrect CP index:"+cpx;
637 * Returns minor version of class file.
639 public int getMinor_version(){
640 return minor_version;
644 * Returns major version of class file.
646 public int getMajor_version(){
647 return major_version;
650 private boolean isJavaIdentifierStart(int cp) {
651 return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
654 private boolean isJavaIdentifierPart(int cp) {
655 return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');