diff -r 000000000000 -r b06660b614db javap/src/main/java/sun/tools/javap/JavapPrinter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/sun/tools/javap/JavapPrinter.java Fri Nov 09 21:33:22 2012 +0100 @@ -0,0 +1,910 @@ +/* + * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package sun.tools.javap; + +import java.util.*; +import java.io.*; + +import static sun.tools.javap.RuntimeConstants.*; + +/** + * Program to print information about class files + * + * @author Sucheta Dambalkar + */ +public class JavapPrinter { + JavapEnvironment env; + ClassData cls; + byte[] code; + String lP= ""; + PrintWriter out; + + public JavapPrinter(InputStream cname, PrintWriter out, JavapEnvironment env){ + this.out = out; + this.cls = new ClassData(cname); + this.env = env; + } + + /** + * Entry point to print class file information. + */ + public void print(){ + printclassHeader(); + printfields(); + printMethods(); + printend(); + } + + /** + * Print a description of the class (not members). + */ + public void printclassHeader(){ + String srcName=""; + if ((srcName = cls.getSourceName()) != "null") // requires debug info + out.println("Compiled from " + javaclassname(srcName)); + + if(cls.isInterface()) { + // The only useful access modifier of an interface is + // public; interfaces are always marked as abstract and + // cannot be final. + out.print((cls.isPublic()?"public ":"") + + "interface "+ javaclassname(cls.getClassName())); + } + else if(cls.isClass()) { + String []accflags = cls.getAccess(); + printAccess(accflags); + out.print("class "+ javaclassname(cls.getClassName())); + + if(cls.getSuperClassName() != null){ + out.print(" extends " + javaclassname(cls.getSuperClassName())); + } + } + + String []interfacelist = cls.getSuperInterfaces(); + if(interfacelist.length > 0){ + if(cls.isClass()) { + out.print(" implements "); + } + else if(cls.isInterface()){ + out.print(" extends "); + } + + for(int j = 0; j < interfacelist.length; j++){ + out.print(javaclassname(interfacelist[j])); + + if((j+1) < interfacelist.length) { + out.print(","); + } + } + } + + // Print class attribute information. + if((env.showallAttr) || (env.showVerbose)){ + printClassAttributes(); + } + // Print verbose output. + if(env.showVerbose){ + printverbosecls(); + } + out.println("{"); + } + + /** + * Print verbose output. + */ + public void printverbosecls(){ + out.println(" minor version: "+cls.getMinor_version()); + out.println(" major version: "+cls.getMajor_version()); + out.println(" Constant pool:"); + printcp(); + env.showallAttr = true; + } + + /** + * Print class attribute information. + */ + public void printClassAttributes(){ + out.println(); + AttrData[] clsattrs = cls.getAttributes(); + for(int i = 0; i < clsattrs.length; i++){ + String clsattrname = clsattrs[i].getAttrName(); + if(clsattrname.equals("SourceFile")){ + out.println(" SourceFile: "+ cls.getSourceName()); + }else if(clsattrname.equals("InnerClasses")){ + printInnerClasses(); + }else { + printAttrData(clsattrs[i]); + } + } + } + + /** + * Print the fields + */ + public void printfields(){ + FieldData[] fields = cls.getFields(); + for(int f = 0; f < fields.length; f++){ + String[] accflags = fields[f].getAccess(); + if(checkAccess(accflags)){ + if(!(env. showLineAndLocal || env.showDisassembled || env.showVerbose + || env.showInternalSigs || env.showallAttr)){ + out.print(" "); + } + printAccess(accflags); + out.println(fields[f].getType()+" " +fields[f].getName()+";"); + if (env.showInternalSigs) { + out.println(" Signature: " + (fields[f].getInternalSig())); + } + + // print field attribute information. + if (env.showallAttr){ + printFieldAttributes(fields[f]); + + } + if((env.showDisassembled) || (env.showLineAndLocal)){ + out.println(); + } + } + } + } + + + /* print field attribute information. */ + public void printFieldAttributes(FieldData field){ + Vector fieldattrs = field.getAttributes(); + for(int j = 0; j < fieldattrs.size(); j++){ + String fieldattrname = ((AttrData)fieldattrs.elementAt(j)).getAttrName(); + if(fieldattrname.equals("ConstantValue")){ + printConstantValue(field); + }else if (fieldattrname.equals("Deprecated")){ + out.println("Deprecated: "+ field.isDeprecated()); + }else if (fieldattrname.equals("Synthetic")){ + out.println(" Synthetic: "+ field.isSynthetic()); + }else { + printAttrData((AttrData)fieldattrs.elementAt(j)); + } + } + out.println(); + } + + /** + * Print the methods + */ + public void printMethods(){ + MethodData[] methods = cls.getMethods(); + for(int m = 0; m < methods.length; m++){ + String[] accflags = methods[m].getAccess(); + if(checkAccess(accflags)){ + if(!(env. showLineAndLocal || env.showDisassembled || env.showVerbose + || env.showInternalSigs || env.showallAttr)){ + out.print(" "); + } + printMethodSignature(methods[m], accflags); + printExceptions(methods[m]); + out.println(";"); + + // Print internal signature of method. + if (env.showInternalSigs){ + out.println(" Signature: " + (methods[m].getInternalSig())); + } + + //Print disassembled code. + if(env.showDisassembled && ! env.showallAttr) { + printcodeSequence(methods[m]); + printExceptionTable(methods[m]); + out.println(); + } + + // Print line and local variable attribute information. + if (env.showLineAndLocal) { + printLineNumTable(methods[m]); + printLocVarTable(methods[m]); + out.println(); + } + + // Print method attribute information. + if (env.showallAttr){ + printMethodAttributes(methods[m]); + } + } + } + } + + /** + * Print method signature. + */ + public void printMethodSignature(MethodData method, String[] accflags){ + printAccess(accflags); + + if((method.getName()).equals("")){ + out.print(javaclassname(cls.getClassName())); + out.print(method.getParameters()); + }else if((method.getName()).equals("")){ + out.print("{}"); + }else{ + out.print(method.getReturnType()+" "); + out.print(method.getName()); + out.print(method.getParameters()); + } + } + + /** + * print method attribute information. + */ + public void printMethodAttributes(MethodData method){ + Vector methodattrs = method.getAttributes(); + Vector codeattrs = method.getCodeAttributes(); + for(int k = 0; k < methodattrs.size(); k++){ + String methodattrname = ((AttrData)methodattrs.elementAt(k)).getAttrName(); + if(methodattrname.equals("Code")){ + printcodeSequence(method); + printExceptionTable(method); + for(int c = 0; c < codeattrs.size(); c++){ + String codeattrname = ((AttrData)codeattrs.elementAt(c)).getAttrName(); + if(codeattrname.equals("LineNumberTable")){ + printLineNumTable(method); + }else if(codeattrname.equals("LocalVariableTable")){ + printLocVarTable(method); + }else if(codeattrname.equals("StackMapTable")) { + // Java SE JSR 202 stack map tables + printStackMapTable(method); + }else if(codeattrname.equals("StackMap")) { + // Java ME CLDC stack maps + printStackMap(method); + } else { + printAttrData((AttrData)codeattrs.elementAt(c)); + } + } + }else if(methodattrname.equals("Exceptions")){ + out.println(" Exceptions: "); + printExceptions(method); + }else if (methodattrname.equals("Deprecated")){ + out.println(" Deprecated: "+ method.isDeprecated()); + }else if (methodattrname.equals("Synthetic")){ + out.println(" Synthetic: "+ method.isSynthetic()); + }else { + printAttrData((AttrData)methodattrs.elementAt(k)); + } + } + out.println(); + } + + /** + * Print exceptions. + */ + public void printExceptions(MethodData method){ + int []exc_index_table = method.get_exc_index_table(); + if (exc_index_table != null) { + if(!(env. showLineAndLocal || env.showDisassembled || env.showVerbose + || env.showInternalSigs || env.showallAttr)){ + out.print(" "); + } + out.print(" throws "); + int k; + int l = exc_index_table.length; + + for (k=0; kopc_jsr_w) { + // pseudo opcodes should be printed as bytecodes + out.print("bytecode "+opcode); + return 1; + } + out.print(Tables.opcName(opcode)); + switch (opcode) { + case opc_aload: case opc_astore: + case opc_fload: case opc_fstore: + case opc_iload: case opc_istore: + case opc_lload: case opc_lstore: + case opc_dload: case opc_dstore: + case opc_ret: + out.print("\t"+getUbyte(pc+1)); + return 2; + case opc_iinc: + out.print("\t"+getUbyte(pc+1)+", "+getbyte(pc+2)); + return 3; + case opc_tableswitch:{ + int tb=align(pc+1); + int default_skip = getInt(tb); /* default skip pamount */ + int low = getInt(tb+4); + int high = getInt(tb+8); + int count = high - low; + out.print("{ //"+low+" to "+high); + for (int i = 0; i <= count; i++) + out.print( "\n\t\t" + (i+low) + ": "+lP+(pc+getInt(tb+12+4*i))+";"); + out.print("\n\t\tdefault: "+lP+(default_skip + pc) + " }"); + return tb-pc+16+count*4; + } + + case opc_lookupswitch:{ + int tb=align(pc+1); + int default_skip = getInt(tb); + int npairs = getInt(tb+4); + out.print("{ //"+npairs); + for (int i = 1; i <= npairs; i++) + out.print("\n\t\t"+getInt(tb+i*8) + +": "+lP+(pc+getInt(tb+4+i*8))+";" + ); + out.print("\n\t\tdefault: "+lP+(default_skip + pc) + " }"); + return tb-pc+(npairs+1)*8; + } + case opc_newarray: + int type=getUbyte(pc+1); + switch (type) { + case T_BOOLEAN:out.print(" boolean");break; + case T_BYTE: out.print(" byte"); break; + case T_CHAR: out.print(" char"); break; + case T_SHORT: out.print(" short"); break; + case T_INT: out.print(" int"); break; + case T_LONG: out.print(" long"); break; + case T_FLOAT: out.print(" float"); break; + case T_DOUBLE: out.print(" double"); break; + case T_CLASS: out.print(" class"); break; + default: out.print(" BOGUS TYPE:"+type); + } + return 2; + + case opc_anewarray: { + int index = getUShort(pc+1); + out.print("\t#"+index+"; //"); + PrintConstant(index); + return 3; + } + + case opc_sipush: + out.print("\t"+getShort(pc+1)); + return 3; + + case opc_bipush: + out.print("\t"+getbyte(pc+1)); + return 2; + + case opc_ldc: { + int index = getUbyte(pc+1); + out.print("\t#"+index+"; //"); + PrintConstant(index); + return 2; + } + + case opc_ldc_w: case opc_ldc2_w: + case opc_instanceof: case opc_checkcast: + case opc_new: + case opc_putstatic: case opc_getstatic: + case opc_putfield: case opc_getfield: + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: { + int index = getUShort(pc+1); + out.print("\t#"+index+"; //"); + PrintConstant(index); + return 3; + } + + case opc_invokeinterface: { + int index = getUShort(pc+1), nargs=getUbyte(pc+3); + out.print("\t#"+index+", "+nargs+"; //"); + PrintConstant(index); + return 5; + } + + case opc_multianewarray: { + int index = getUShort(pc+1), dimensions=getUbyte(pc+3); + out.print("\t#"+index+", "+dimensions+"; //"); + PrintConstant(index); + return 4; + } + case opc_jsr: case opc_goto: + case opc_ifeq: case opc_ifge: case opc_ifgt: + case opc_ifle: case opc_iflt: case opc_ifne: + case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge: + case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt: + case opc_if_acmpeq: case opc_if_acmpne: + case opc_ifnull: case opc_ifnonnull: + out.print("\t"+lP+(pc + getShort(pc+1)) ); + return 3; + + case opc_jsr_w: + case opc_goto_w: + out.print("\t"+lP+(pc + getInt(pc+1))); + return 5; + + default: + return 1; + } + } + /** + * Print code attribute details. + */ + public void printVerboseHeader(MethodData method) { + int argCount = method.getArgumentlength(); + if (!method.isStatic()) + ++argCount; // for 'this' + + out.println(" Stack=" + method.getMaxStack() + + ", Locals=" + method.getMaxLocals() + + ", Args_size=" + argCount); + + } + + + /** + * Print the exception table for this method code + */ + void printExceptionTable(MethodData method){//throws IOException + Vector exception_table = method.getexception_table(); + if (exception_table.size() > 0) { + out.println(" Exception table:"); + out.println(" from to target type"); + for (int idx = 0; idx < exception_table.size(); ++idx) { + TrapData handler = (TrapData)exception_table.elementAt(idx); + printFixedWidthInt(handler.start_pc, 6); + printFixedWidthInt(handler.end_pc, 6); + printFixedWidthInt(handler.handler_pc, 6); + out.print(" "); + int catch_cpx = handler.catch_cpx; + if (catch_cpx == 0) { + out.println("any"); + }else { + out.print("Class "); + out.println(cls.getClassName(catch_cpx)); + out.println(""); + } + } + } + } + + /** + * Print LineNumberTable attribute information. + */ + public void printLineNumTable(MethodData method) { + int numlines = method.getnumlines(); + Vector lin_num_tb = method.getlin_num_tb(); + if( lin_num_tb.size() > 0){ + out.println(" LineNumberTable: "); + for (int i=0; i 0){ + out.println(" LocalVariableTable: "); + out.print(" "); + out.println("Start Length Slot Name Signature"); + } + Vector loc_var_tb = method.getloc_var_tb(); + + for (int i=0; i 0) { + out.println(" StackMap: number_of_entries = " + number_of_entries); + + for (StackMapData frame : stack_map_tb) { + frame.print(this); + } + } + out.println(); + } + + /** + * Print StackMapTable attribute information. + */ + public void printStackMapTable(MethodData method) { + StackMapTableData[] stack_map_tb = method.getStackMapTable(); + int number_of_entries = stack_map_tb.length; + if (number_of_entries > 0) { + out.println(" StackMapTable: number_of_entries = " + number_of_entries); + + for (StackMapTableData frame : stack_map_tb) { + frame.print(this); + } + } + out.println(); + } + + void printMap(String name, int[] map) { + out.print(name); + for (int i=0; i> 8; + switch (type) { + case ITEM_Object: + out.print(" "); + PrintConstant(argument); + break; + case ITEM_NewObject: + out.print(" " + Tables.mapTypeName(type)); + out.print(" " + argument); + break; + default: + out.print(" " + Tables.mapTypeName(type)); + } + out.print( (i==(map.length-1)? ' ' : ',')); + } + out.println("]"); + } + + /** + * Print ConstantValue attribute information. + */ + public void printConstantValue(FieldData field){ + out.print(" Constant value: "); + int cpx = (field.getConstantValueIndex()); + byte tag=0; + try { + tag=cls.getTag(cpx); + + } catch (IndexOutOfBoundsException e) { + out.print("Error:"); + return; + } + switch (tag) { + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + case CONSTANT_FIELD: { + CPX2 x = (CPX2)(cls.getCpoolEntry(cpx)); + if (x.cpx1 == cls.getthis_cpx()) { + // don't print class part for local references + cpx=x.cpx2; + } + } + } + out.print(cls.TagString(tag)+" "+ cls.StringValue(cpx)); + } + + /** + * Print InnerClass attribute information. + */ + public void printInnerClasses(){//throws ioexception + + InnerClassData[] innerClasses = cls.getInnerClasses(); + if(innerClasses != null){ + if(innerClasses.length > 0){ + out.print(" "); + out.println("InnerClass: "); + for(int i = 0 ; i < innerClasses.length; i++){ + out.print(" "); + //access + String[] accflags = innerClasses[i].getAccess(); + if(checkAccess(accflags)){ + printAccess(accflags); + if (innerClasses[i].inner_name_index!=0) { + out.print("#"+innerClasses[i].inner_name_index+"= "); + } + out.print("#"+innerClasses[i].inner_class_info_index); + if (innerClasses[i].outer_class_info_index!=0) { + out.print(" of #"+innerClasses[i].outer_class_info_index); + } + out.print("; //"); + if (innerClasses[i].inner_name_index!=0) { + out.print(cls.getName(innerClasses[i].inner_name_index)+"="); + } + PrintConstant(innerClasses[i].inner_class_info_index); + if (innerClasses[i].outer_class_info_index!=0) { + out.print(" of "); + PrintConstant(innerClasses[i].outer_class_info_index); + } + out.println(); + } + } + + } + } + } + + /** + * Print constant pool information. + */ + public void printcp(){ + int cpx = 1 ; + + while (cpx < cls.getCpoolCount()) { + out.print("const #"+cpx+" = "); + cpx+=PrintlnConstantEntry(cpx); + } + out.println(); + } + + /** + * Print constant pool entry information. + */ + public int PrintlnConstantEntry(int cpx) { + int size=1; + byte tag=0; + try { + tag=cls.getTag(cpx); + } catch (IndexOutOfBoundsException e) { + out.println(" "); + return 1; + } + out.print(cls.StringTag(cpx)+"\t"); + Object x=cls.getCpoolEntryobj(cpx); + if (x==null) { + switch (tag) { + case CONSTANT_LONG: + case CONSTANT_DOUBLE: + size=2; + } + out.println("null;"); + return size; + } + String str=cls.StringValue(cpx); + + switch (tag) { + case CONSTANT_CLASS: + case CONSTANT_STRING: + out.println("#"+(((CPX)x).cpx)+";\t// "+str); + break; + case CONSTANT_FIELD: + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + out.println("#"+((CPX2)x).cpx1+".#"+((CPX2)x).cpx2+";\t// "+str); + break; + case CONSTANT_NAMEANDTYPE: + out.println("#"+((CPX2)x).cpx1+":#"+((CPX2)x).cpx2+";// "+str); + break; + case CONSTANT_LONG: + case CONSTANT_DOUBLE: + size=2; + default: + out.println(str+";"); + } + return size; + } + + /** + * Checks access of class, field or method. + */ + public boolean checkAccess(String accflags[]){ + + boolean ispublic = false; + boolean isprotected = false; + boolean isprivate = false; + boolean ispackage = false; + + for(int i= 0; i < accflags.length; i++){ + if(accflags[i].equals("public")) ispublic = true; + else if (accflags[i].equals("protected")) isprotected = true; + else if (accflags[i].equals("private")) isprivate = true; + } + + if(!(ispublic || isprotected || isprivate)) ispackage = true; + + if((env.showAccess == env.PUBLIC) && (isprotected || isprivate || ispackage)) return false; + else if((env.showAccess == env.PROTECTED) && (isprivate || ispackage)) return false; + else if((env.showAccess == env.PACKAGE) && (isprivate)) return false; + else return true; + } + + /** + * Prints access of class, field or method. + */ + public void printAccess(String []accflags){ + for(int j = 0; j < accflags.length; j++){ + out.print(accflags[j]+" "); + } + } + + /** + * Print an integer so that it takes 'length' characters in + * the output. Temporary until formatting code is stable. + */ + public void printFixedWidthInt(long x, int length) { + CharArrayWriter baStream = new CharArrayWriter(); + PrintWriter pStream = new PrintWriter(baStream); + pStream.print(x); + String str = baStream.toString(); + for (int cnt = length - str.length(); cnt > 0; --cnt) + out.print(' '); + out.print(str); + } + + protected int getbyte (int pc) { + return code[pc]; + } + + protected int getUbyte (int pc) { + return code[pc]&0xFF; + } + + int getShort (int pc) { + return (code[pc]<<8) | (code[pc+1]&0xFF); + } + + int getUShort (int pc) { + return ((code[pc]<<8) | (code[pc+1]&0xFF))&0xFFFF; + } + + protected int getInt (int pc) { + return (getShort(pc)<<16) | (getShort(pc+2)&0xFFFF); + } + + /** + * Print constant value at that index. + */ + void PrintConstant(int cpx) { + if (cpx==0) { + out.print("#0"); + return; + } + byte tag=0; + try { + tag=cls.getTag(cpx); + + } catch (IndexOutOfBoundsException e) { + out.print("#"+cpx); + return; + } + switch (tag) { + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + case CONSTANT_FIELD: { + // CPX2 x=(CPX2)(cpool[cpx]); + CPX2 x = (CPX2)(cls.getCpoolEntry(cpx)); + if (x.cpx1 == cls.getthis_cpx()) { + // don't print class part for local references + cpx=x.cpx2; + } + } + } + out.print(cls.TagString(tag)+" "+ cls.StringValue(cpx)); + } + + protected static int align (int n) { + return (n+3) & ~3 ; + } + + public void printend(){ + out.println("}"); + out.println(); + } + + public String javaclassname(String name){ + return name.replace('/','.'); + } + + /** + * Print attribute data in hex. + */ + public void printAttrData(AttrData attr){ + byte []data = attr.getData(); + int i = 0; + int j = 0; + out.print(" "+attr.getAttrName()+": "); + out.println("length = " + cls.toHex(attr.datalen)); + + out.print(" "); + + + while (i < data.length){ + String databytestring = cls.toHex(data[i]); + if(databytestring.equals("0x")) out.print("00"); + else if(databytestring.substring(2).length() == 1){ + out.print("0"+databytestring.substring(2)); + } else{ + out.print(databytestring.substring(2)); + } + + j++; + if(j == 16) { + out.println(); + out.print(" "); + j = 0; + } + else out.print(" "); + i++; + } + out.println(); + } +}