Package com.sun.org.apache.bcel.internal.util

Source Code of com.sun.org.apache.bcel.internal.util.CodeHTML

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.
*
* @version $Id: CodeHTML.java,v 1.1.2.1 2005/07/31 23:46:59 jeffsuttor Exp $
* @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("&nbsp;");
  }
      }
    }

    buf.append("</TD>");
    return buf.toString();
  }

  /**
   * Find all target addresses in code, so that they can be marked
   * with &lt;A NAME = ...&gt;. 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, " ", "&nbsp;");
    // Get the method's attributes, the Code Attribute in particular
    Attribute[]  attributes= method.getAttributes()

    file.print("<P><B><FONT COLOR=\"#FF0000\">" + access + "</FONT>&nbsp;" +
         "<A NAME=method" + method_number + ">" + Class2HTML.referenceType(type) +
         "</A>&nbsp<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(",&nbsp;");
    }

    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>");
    }

  }                         
}
TOP

Related Classes of com.sun.org.apache.bcel.internal.util.CodeHTML

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.