diff options
author | joehw <none@none> | 2012-04-12 08:38:26 -0700 |
---|---|---|
committer | joehw <none@none> | 2012-04-12 08:38:26 -0700 |
commit | 41b00ad77bc0c9fd8ecc91d0743ca6d029a69a3e (patch) | |
tree | 9b353d47ffac135a97e990d60f7437783fa0a1ed /src/com/sun/org/apache/bcel/internal/util/CodeHTML.java | |
parent | 32c27c27678881c5840239b38539cef087e8b62b (diff) | |
download | jdk8u_jaxp-41b00ad77bc0c9fd8ecc91d0743ca6d029a69a3e.tar.gz |
7160496: Rename JDK8 JAXP source directory
Summary: moving src/share/classes to src
Reviewed-by: ohair
Diffstat (limited to 'src/com/sun/org/apache/bcel/internal/util/CodeHTML.java')
-rw-r--r-- | src/com/sun/org/apache/bcel/internal/util/CodeHTML.java | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/src/com/sun/org/apache/bcel/internal/util/CodeHTML.java b/src/com/sun/org/apache/bcel/internal/util/CodeHTML.java new file mode 100644 index 0000000..cae2ea6 --- /dev/null +++ b/src/com/sun/org/apache/bcel/internal/util/CodeHTML.java @@ -0,0 +1,621 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +package com.sun.org.apache.bcel.internal.util; + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2001 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache BCEL" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache BCEL", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +import com.sun.org.apache.bcel.internal.classfile.*; +import java.io.*; +import java.util.BitSet; + +/** + * Convert code into HTML file. + * + * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> + * + */ +final class CodeHTML implements com.sun.org.apache.bcel.internal.Constants { + private String class_name; // name of current class + private Method[] methods; // Methods to print + private PrintWriter file; // file to write to + private BitSet goto_set; + private ConstantPool constant_pool; + private ConstantHTML constant_html; + private static boolean wide=false; + + CodeHTML(String dir, String class_name, + Method[] methods, ConstantPool constant_pool, + ConstantHTML constant_html) throws IOException + { + this.class_name = class_name; + this.methods = methods; + this.constant_pool = constant_pool; + this.constant_html = constant_html; + + file = new PrintWriter(new FileOutputStream(dir + class_name + "_code.html")); + file.println("<HTML><BODY BGCOLOR=\"#C0C0C0\">"); + + for(int i=0; i < methods.length; i++) + writeMethod(methods[i], i); + + file.println("</BODY></HTML>"); + file.close(); + } + + /** + * Disassemble a stream of byte codes and return the + * string representation. + * + * @param stream data input stream + * @return String representation of byte code + */ + private final String codeToHTML(ByteSequence bytes, int method_number) + throws IOException + { + short opcode = (short)bytes.readUnsignedByte(); + StringBuffer buf; + String name, signature; + int default_offset=0, low, high; + int index, class_index, vindex, constant; + int[] jump_table; + int no_pad_bytes=0, offset; + + buf = new StringBuffer("<TT>" + OPCODE_NAMES[opcode] + "</TT></TD><TD>"); + + /* Special case: Skip (0-3) padding bytes, i.e., the + * following bytes are 4-byte-aligned + */ + if((opcode == TABLESWITCH) || (opcode == LOOKUPSWITCH)) { + int remainder = bytes.getIndex() % 4; + no_pad_bytes = (remainder == 0)? 0 : 4 - remainder; + + for(int i=0; i < no_pad_bytes; i++) + bytes.readByte(); + + // Both cases have a field default_offset in common + default_offset = bytes.readInt(); + } + + switch(opcode) { + case TABLESWITCH: + low = bytes.readInt(); + high = bytes.readInt(); + + offset = bytes.getIndex() - 12 - no_pad_bytes - 1; + default_offset += offset; + + buf.append("<TABLE BORDER=1><TR>"); + + // Print switch indices in first row (and default) + jump_table = new int[high - low + 1]; + for(int i=0; i < jump_table.length; i++) { + jump_table[i] = offset + bytes.readInt(); + + buf.append("<TH>" + (low + i) + "</TH>"); + } + buf.append("<TH>default</TH></TR>\n<TR>"); + + // Print target and default indices in second row + for(int i=0; i < jump_table.length; i++) + buf.append("<TD><A HREF=\"#code" + method_number + "@" + + jump_table[i] + "\">" + jump_table[i] + "</A></TD>"); + buf.append("<TD><A HREF=\"#code" + method_number + "@" + + default_offset + "\">" + default_offset + "</A></TD></TR>\n</TABLE>\n"); + + break; + + /* Lookup switch has variable length arguments. + */ + case LOOKUPSWITCH: + int npairs = bytes.readInt(); + offset = bytes.getIndex() - 8 - no_pad_bytes - 1; + jump_table = new int[npairs]; + default_offset += offset; + + buf.append("<TABLE BORDER=1><TR>"); + + // Print switch indices in first row (and default) + for(int i=0; i < npairs; i++) { + int match = bytes.readInt(); + + jump_table[i] = offset + bytes.readInt(); + buf.append("<TH>" + match + "</TH>"); + } + buf.append("<TH>default</TH></TR>\n<TR>"); + + // Print target and default indices in second row + for(int i=0; i < npairs; i++) + buf.append("<TD><A HREF=\"#code" + method_number + "@" + + jump_table[i] + "\">" + jump_table[i] + "</A></TD>"); + buf.append("<TD><A HREF=\"#code" + method_number + "@" + + default_offset + "\">" + default_offset + "</A></TD></TR>\n</TABLE>\n"); + break; + + /* Two address bytes + offset from start of byte stream form the + * jump target. + */ + case GOTO: case IFEQ: case IFGE: case IFGT: + case IFLE: case IFLT: + case IFNE: case IFNONNULL: case IFNULL: case IF_ACMPEQ: + case IF_ACMPNE: case IF_ICMPEQ: case IF_ICMPGE: case IF_ICMPGT: + case IF_ICMPLE: case IF_ICMPLT: case IF_ICMPNE: case JSR: + + index = (int)(bytes.getIndex() + bytes.readShort() - 1); + + buf.append("<A HREF=\"#code" + method_number + "@" + index + "\">" + index + "</A>"); + break; + + /* Same for 32-bit wide jumps + */ + case GOTO_W: case JSR_W: + int windex = bytes.getIndex() + bytes.readInt() - 1; + buf.append("<A HREF=\"#code" + method_number + "@" + windex + "\">" + + windex + "</A>"); + break; + + /* Index byte references local variable (register) + */ + case ALOAD: case ASTORE: case DLOAD: case DSTORE: case FLOAD: + case FSTORE: case ILOAD: case ISTORE: case LLOAD: case LSTORE: + case RET: + if(wide) { + vindex = bytes.readShort(); + wide=false; // Clear flag + } + else + vindex = bytes.readUnsignedByte(); + + buf.append("%" + vindex); + break; + + /* + * Remember wide byte which is used to form a 16-bit address in the + * following instruction. Relies on that the method is called again with + * the following opcode. + */ + case WIDE: + wide = true; + buf.append("(wide)"); + break; + + /* Array of basic type. + */ + case NEWARRAY: + buf.append("<FONT COLOR=\"#00FF00\">" + TYPE_NAMES[bytes.readByte()] + "</FONT>"); + break; + + /* Access object/class fields. + */ + case GETFIELD: case GETSTATIC: case PUTFIELD: case PUTSTATIC: + index = bytes.readShort(); + ConstantFieldref c1 = (ConstantFieldref)constant_pool.getConstant(index, CONSTANT_Fieldref); + + class_index = c1.getClassIndex(); + name = constant_pool.getConstantString(class_index, CONSTANT_Class); + name = Utility.compactClassName(name, false); + + index = c1.getNameAndTypeIndex(); + String field_name = constant_pool.constantToString(index, CONSTANT_NameAndType); + + if(name.equals(class_name)) { // Local field + buf.append("<A HREF=\"" + class_name + "_methods.html#field" + field_name + + "\" TARGET=Methods>" + field_name + "</A>\n"); + } + else + buf.append(constant_html.referenceConstant(class_index) + "." + field_name); + + break; + + /* Operands are references to classes in constant pool + */ + case CHECKCAST: case INSTANCEOF: case NEW: + index = bytes.readShort(); + buf.append(constant_html.referenceConstant(index)); + break; + + /* Operands are references to methods in constant pool + */ + case INVOKESPECIAL: case INVOKESTATIC: case INVOKEVIRTUAL: case INVOKEINTERFACE: + int m_index = bytes.readShort(); + String str; + + if(opcode == INVOKEINTERFACE) { // Special treatment needed + int nargs = bytes.readUnsignedByte(); // Redundant + int reserved = bytes.readUnsignedByte(); // Reserved + + ConstantInterfaceMethodref c=(ConstantInterfaceMethodref)constant_pool.getConstant(m_index, CONSTANT_InterfaceMethodref); + + class_index = c.getClassIndex(); + str = constant_pool.constantToString(c); + index = c.getNameAndTypeIndex(); + } + else { + ConstantMethodref c = (ConstantMethodref)constant_pool.getConstant(m_index, CONSTANT_Methodref); + class_index = c.getClassIndex(); + + str = constant_pool.constantToString(c); + index = c.getNameAndTypeIndex(); + } + + name = Class2HTML.referenceClass(class_index); + str = Class2HTML.toHTML(constant_pool.constantToString(constant_pool.getConstant(index, CONSTANT_NameAndType))); + + // Get signature, i.e., types + ConstantNameAndType c2 = (ConstantNameAndType)constant_pool. + getConstant(index, CONSTANT_NameAndType); + signature = constant_pool.constantToString(c2.getSignatureIndex(), + CONSTANT_Utf8); + String[] args = Utility.methodSignatureArgumentTypes(signature, false); + String type = Utility.methodSignatureReturnType(signature, false); + + buf.append(name + ".<A HREF=\"" + class_name + "_cp.html#cp" + m_index + + "\" TARGET=ConstantPool>" + str + "</A>" + "("); + + // List arguments + for(int i=0; i < args.length; i++) { + buf.append(Class2HTML.referenceType(args[i])); + + if(i < args.length - 1) + buf.append(", "); + } + // Attach return type + buf.append("):" + Class2HTML.referenceType(type)); + + break; + + /* Operands are references to items in constant pool + */ + case LDC_W: case LDC2_W: + index = bytes.readShort(); + + buf.append("<A HREF=\"" + class_name + "_cp.html#cp" + index + + "\" TARGET=\"ConstantPool\">" + + Class2HTML.toHTML(constant_pool.constantToString(index, + constant_pool. + getConstant(index).getTag()))+ + "</a>"); + break; + + case LDC: + index = bytes.readUnsignedByte(); + buf.append("<A HREF=\"" + class_name + "_cp.html#cp" + index + + "\" TARGET=\"ConstantPool\">" + + Class2HTML.toHTML(constant_pool.constantToString(index, + constant_pool. + getConstant(index).getTag()))+ + "</a>"); + break; + + /* Array of references. + */ + case ANEWARRAY: + index = bytes.readShort(); + + buf.append(constant_html.referenceConstant(index)); + break; + + /* Multidimensional array of references. + */ + case MULTIANEWARRAY: + index = bytes.readShort(); + int dimensions = bytes.readByte(); + buf.append(constant_html.referenceConstant(index) + ":" + dimensions + "-dimensional"); + break; + + /* Increment local variable. + */ + case IINC: + if(wide) { + vindex = bytes.readShort(); + constant = bytes.readShort(); + wide = false; + } + else { + vindex = bytes.readUnsignedByte(); + constant = bytes.readByte(); + } + buf.append("%" + vindex + " " + constant); + break; + + default: + if(NO_OF_OPERANDS[opcode] > 0) { + for(int i=0; i < TYPE_OF_OPERANDS[opcode].length; i++) { + switch(TYPE_OF_OPERANDS[opcode][i]) { + case T_BYTE: + buf.append(bytes.readUnsignedByte()); + break; + + case T_SHORT: // Either branch or index + buf.append(bytes.readShort()); + break; + + case T_INT: + buf.append(bytes.readInt()); + break; + + default: // Never reached + System.err.println("Unreachable default case reached!"); + System.exit(-1); + } + buf.append(" "); + } + } + } + + buf.append("</TD>"); + return buf.toString(); + } + + /** + * Find all target addresses in code, so that they can be marked + * with <A NAME = ...>. Target addresses are kept in an BitSet object. + */ + private final void findGotos(ByteSequence bytes, Method method, Code code) + throws IOException + { + int index; + goto_set = new BitSet(bytes.available()); + int opcode; + + /* First get Code attribute from method and the exceptions handled + * (try .. catch) in this method. We only need the line number here. + */ + + if(code != null) { + CodeException[] ce = code.getExceptionTable(); + int len = ce.length; + + for(int i=0; i < len; i++) { + goto_set.set(ce[i].getStartPC()); + goto_set.set(ce[i].getEndPC()); + goto_set.set(ce[i].getHandlerPC()); + } + + // Look for local variables and their range + Attribute[] attributes = code.getAttributes(); + for(int i=0; i < attributes.length; i++) { + if(attributes[i].getTag() == ATTR_LOCAL_VARIABLE_TABLE) { + LocalVariable[] vars = ((LocalVariableTable)attributes[i]).getLocalVariableTable(); + + for(int j=0; j < vars.length; j++) { + int start = vars[j].getStartPC(); + int end = (int)(start + vars[j].getLength()); + goto_set.set(start); + goto_set.set(end); + } + break; + } + } + } + + // Get target addresses from GOTO, JSR, TABLESWITCH, etc. + for(int i=0; bytes.available() > 0; i++) { + opcode = bytes.readUnsignedByte(); + //System.out.println(OPCODE_NAMES[opcode]); + switch(opcode) { + case TABLESWITCH: case LOOKUPSWITCH: + //bytes.readByte(); // Skip already read byte + + int remainder = bytes.getIndex() % 4; + int no_pad_bytes = (remainder == 0)? 0 : 4 - remainder; + int default_offset, offset; + + for(int j=0; j < no_pad_bytes; j++) + bytes.readByte(); + + // Both cases have a field default_offset in common + default_offset = bytes.readInt(); + + if(opcode == TABLESWITCH) { + int low = bytes.readInt(); + int high = bytes.readInt(); + + offset = bytes.getIndex() - 12 - no_pad_bytes - 1; + default_offset += offset; + goto_set.set(default_offset); + + for(int j=0; j < (high - low + 1); j++) { + index = offset + bytes.readInt(); + goto_set.set(index); + } + } + else { // LOOKUPSWITCH + int npairs = bytes.readInt(); + + offset = bytes.getIndex() - 8 - no_pad_bytes - 1; + default_offset += offset; + goto_set.set(default_offset); + + for(int j=0; j < npairs; j++) { + int match = bytes.readInt(); + + index = offset + bytes.readInt(); + goto_set.set(index); + } + } + break; + + case GOTO: case IFEQ: case IFGE: case IFGT: + case IFLE: case IFLT: + case IFNE: case IFNONNULL: case IFNULL: case IF_ACMPEQ: + case IF_ACMPNE: case IF_ICMPEQ: case IF_ICMPGE: case IF_ICMPGT: + case IF_ICMPLE: case IF_ICMPLT: case IF_ICMPNE: case JSR: + //bytes.readByte(); // Skip already read byte + index = bytes.getIndex() + bytes.readShort() - 1; + + goto_set.set(index); + break; + + case GOTO_W: case JSR_W: + //bytes.readByte(); // Skip already read byte + index = bytes.getIndex() + bytes.readInt() - 1; + goto_set.set(index); + break; + + default: + bytes.unreadByte(); + codeToHTML(bytes, 0); // Ignore output + } + } + } + + /** + * Write a single method with the byte code associated with it. + */ + private void writeMethod(Method method, int method_number) + throws IOException + { + // Get raw signature + String signature = method.getSignature(); + // Get array of strings containing the argument types + String[] args = Utility.methodSignatureArgumentTypes(signature, false); + // Get return type string + String type = Utility.methodSignatureReturnType(signature, false); + // Get method name + String name = method.getName(); + String html_name = Class2HTML.toHTML(name); + // Get method's access flags + String access = Utility.accessToString(method.getAccessFlags()); + access = Utility.replace(access, " ", " "); + // Get the method's attributes, the Code Attribute in particular + Attribute[] attributes= method.getAttributes(); + + file.print("<P><B><FONT COLOR=\"#FF0000\">" + access + "</FONT> " + + "<A NAME=method" + method_number + ">" + Class2HTML.referenceType(type) + + "</A> <A HREF=\"" + class_name + "_methods.html#method" + method_number + + "\" TARGET=Methods>" + html_name + "</A>("); + + for(int i=0; i < args.length; i++) { + file.print(Class2HTML.referenceType(args[i])); + if(i < args.length - 1) + file.print(", "); + } + + file.println(")</B></P>"); + + Code c=null; + byte[] code=null; + + if(attributes.length > 0) { + file.print("<H4>Attributes</H4><UL>\n"); + for(int i=0; i < attributes.length; i++) { + byte tag = attributes[i].getTag(); + + if(tag != ATTR_UNKNOWN) + file.print("<LI><A HREF=\"" + class_name + "_attributes.html#method" + method_number + "@" + i + + "\" TARGET=Attributes>" + ATTRIBUTE_NAMES[tag] + "</A></LI>\n"); + else + file.print("<LI>" + attributes[i] + "</LI>"); + + if(tag == ATTR_CODE) { + c = (Code)attributes[i]; + Attribute[] attributes2 = c.getAttributes(); + code = c.getCode(); + + file.print("<UL>"); + for(int j=0; j < attributes2.length; j++) { + tag = attributes2[j].getTag(); + file.print("<LI><A HREF=\"" + class_name + "_attributes.html#" + + "method" + method_number + "@" + i + "@" + j + "\" TARGET=Attributes>" + + ATTRIBUTE_NAMES[tag] + "</A></LI>\n"); + + } + file.print("</UL>"); + } + } + file.println("</UL>"); + } + + if(code != null) { // No code, an abstract method, e.g. + //System.out.println(name + "\n" + Utility.codeToString(code, constant_pool, 0, -1)); + + // Print the byte code + ByteSequence stream = new ByteSequence(code); + stream.mark(stream.available()); + findGotos(stream, method, c); + stream.reset(); + + file.println("<TABLE BORDER=0><TR><TH ALIGN=LEFT>Byte<BR>offset</TH>" + + "<TH ALIGN=LEFT>Instruction</TH><TH ALIGN=LEFT>Argument</TH>"); + + for(int i=0; stream.available() > 0; i++) { + int offset = stream.getIndex(); + String str = codeToHTML(stream, method_number); + String anchor = ""; + + /* Set an anchor mark if this line is targetted by a goto, jsr, etc. + * Defining an anchor for every line is very inefficient! + */ + if(goto_set.get(offset)) + anchor = "<A NAME=code" + method_number + "@" + offset + "></A>"; + + String anchor2; + if(stream.getIndex() == code.length) // last loop + anchor2 = "<A NAME=code" + method_number + "@" + code.length + ">" + offset + "</A>"; + else + anchor2 = "" + offset; + + file.println("<TR VALIGN=TOP><TD>" + anchor2 + "</TD><TD>" + anchor + str + "</TR>"); + } + + // Mark last line, may be targetted from Attributes window + file.println("<TR><TD> </A></TD></TR>"); + file.println("</TABLE>"); + } + + } +} |