All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jdk8u.jaxp.org.apache.bcel.external.util.CodeHTML Maven / Gradle / Ivy

The newest version!
/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
package jdk8u.jaxp.org.apache.bcel.external.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 [email protected].
 *
 * 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
 * .
 */

import jdk8u.jaxp.org.apache.bcel.external.classfile.*;
import java.io.*;
import java.util.BitSet;

/**
 * Convert code into HTML file.
 *
 * @author  M. Dahm
 *
 */
final class CodeHTML implements jdk8u.jaxp.org.apache.bcel.external.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("");

    for(int i=0; i < methods.length; i++)
      writeMethod(methods[i], i);

    file.println("");
    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("" + OPCODE_NAMES[opcode] + "");

    /* 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("");

      // 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("");
      }
      buf.append("\n");

      // Print target and default indices in second row
      for(int i=0; i < jump_table.length; i++)
        buf.append("");
      buf.append("\n
" + (low + i) + "default
" + jump_table[i] + "" + default_offset + "
\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(""); // 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(""); } buf.append("\n"); // Print target and default indices in second row for(int i=0; i < npairs; i++) buf.append(""); buf.append("\n
" + match + "default
" + jump_table[i] + "" + default_offset + "
\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("" + index + ""); break; /* Same for 32-bit wide jumps */ case GOTO_W: case JSR_W: int windex = bytes.getIndex() + bytes.readInt() - 1; buf.append("" + windex + ""); 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("" + TYPE_NAMES[bytes.readByte()] + ""); 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("" + field_name + "\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 + "." + str + "" + "("); // 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("" + Class2HTML.toHTML(constant_pool.constantToString(index, constant_pool. getConstant(index).getTag()))+ ""); break; case LDC: index = bytes.readUnsignedByte(); buf.append("" + Class2HTML.toHTML(constant_pool.constantToString(index, constant_pool. getConstant(index).getTag()))+ ""); 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(""); 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("

" + access + " " + "" + Class2HTML.referenceType(type) + " " + html_name + "("); for(int i=0; i < args.length; i++) { file.print(Class2HTML.referenceType(args[i])); if(i < args.length - 1) file.print(", "); } file.println(")

"); Code c=null; byte[] code=null; if(attributes.length > 0) { file.print("

Attributes

    \n"); for(int i=0; i < attributes.length; i++) { byte tag = attributes[i].getTag(); if(tag != ATTR_UNKNOWN) file.print("
  • " + ATTRIBUTE_NAMES[tag] + "
  • \n"); else file.print("
  • " + attributes[i] + "
  • "); if(tag == ATTR_CODE) { c = (Code)attributes[i]; Attribute[] attributes2 = c.getAttributes(); code = c.getCode(); file.print(""); } } file.println("
"); } 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("" + ""); 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 = ""; String anchor2; if(stream.getIndex() == code.length) // last loop anchor2 = "" + offset + ""; else anchor2 = "" + offset; file.println(""); } // Mark last line, may be targetted from Attributes window file.println(""); file.println("
Byte
offset
InstructionArgument
" + anchor2 + "" + anchor + str + "
"); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy