View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.classfile;
    18
    19  import java.io.DataInputStream;
    20  import java.io.DataOutputStream;
    21  import java.io.IOException;
    22  import org.apache.bcel.Constants;
    23
    24  /***
    25   * This class represents a chunk of Java byte code contained in a
    26   * method. It is instantiated by the
    27   * <em>Attribute.readAttribute()</em> method. A <em>Code</em>
    28   * attribute contains informations about operand stack, local
    29   * variables, byte code and the exceptions handled within this
    30   * method.
    31   *
    32   * This attribute has attributes itself, namely <em>LineNumberTable</em> which
    33   * is used for debugging purposes and <em>LocalVariableTable</em> which
    34   * contains information about the local variables.
    35   *
    36   * @version $Id: Code.java 386056 2006-03-15 11:31:56Z tcurdt $
    37   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    38   * @see     Attribute
    39   * @see     CodeException
    40   * @see     LineNumberTable
    41   * @see LocalVariableTable
    42   */
    43  public final class Code extends Attribute {
    44
    45      private int max_stack; // Maximum size of stack used by this method
    46      private int max_locals; // Number of local variables
    47      private int code_length; // Length of code in bytes
    48      private byte[] code; // Actual byte code
    49      private int exception_table_length;
    50      private CodeException[] exception_table; // Table of handled exceptions
    51      private int attributes_count; // Attributes of code: LineNumber
    52      private Attribute[] attributes; // or LocalVariable
    53
    54
    55      /***
    56       * Initialize from another object. Note that both objects use the same
    57       * references (shallow copy). Use copy() for a physical copy.
    58       */
    59      public Code(Code c) {
    60          this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(), c.getCode(), c
    61                  .getExceptionTable(), c.getAttributes(), c.getConstantPool());
    62      }
    63
    64
    65      /***
    66       * @param name_index Index pointing to the name <em>Code</em>
    67       * @param length Content length in bytes
    68       * @param file Input stream
    69       * @param constant_pool Array of constants
    70       */
    71      Code(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
    72              throws IOException {
    73          // Initialize with some default values which will be overwritten later
    74          this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null,
    75                  (CodeException[]) null, (Attribute[]) null, constant_pool);
    76          code_length = file.readInt();
    77          code = new byte[code_length]; // Read byte code
    78          file.readFully(code);
    79          /* Read exception table that contains all regions where an exception
    80           * handler is active, i.e., a try { ... } catch() block.
    81           */
    82          exception_table_length = file.readUnsignedShort();
    83          exception_table = new CodeException[exception_table_length];
    84          for (int i = 0; i < exception_table_length; i++) {
    85              exception_table[i] = new CodeException(file);
    86          }
    87          /* Read all attributes, currently `LineNumberTable' and
    88           * `LocalVariableTable'
    89           */
    90          attributes_count = file.readUnsignedShort();
    91          attributes = new Attribute[attributes_count];
    92          for (int i = 0; i < attributes_count; i++) {
    93              attributes[i] = Attribute.readAttribute(file, constant_pool);
    94          }
    95          /* Adjust length, because of setAttributes in this(), s.b.  length
    96           * is incorrect, because it didn't take the internal attributes
    97           * into account yet! Very subtle bug, fixed in 3.1.1.
    98           */
    99          this.length = length;
    100     }
    101
    102
    103     /***
    104      * @param name_index Index pointing to the name <em>Code</em>
    105      * @param length Content length in bytes
    106      * @param max_stack Maximum size of stack
    107      * @param max_locals Number of local variables
    108      * @param code Actual byte code
    109      * @param exception_table Table of handled exceptions
    110      * @param attributes Attributes of code: LineNumber or LocalVariable
    111      * @param constant_pool Array of constants
    112      */
    113     public Code(int name_index, int length, int max_stack, int max_locals, byte[] code,
    114             CodeException[] exception_table, Attribute[] attributes, ConstantPool constant_pool) {
    115         super(Constants.ATTR_CODE, name_index, length, constant_pool);
    116         this.max_stack = max_stack;
    117         this.max_locals = max_locals;
    118         setCode(code);
    119         setExceptionTable(exception_table);
    120         setAttributes(attributes); // Overwrites length!
    121     }
    122
    123
    124     /***
    125      * Called by objects that are traversing the nodes of the tree implicitely
    126      * defined by the contents of a Java class. I.e., the hierarchy of methods,
    127      * fields, attributes, etc. spawns a tree of objects.
    128      *
    129      * @param v Visitor object
    130      */
    131     public void accept( Visitor v ) {
    132         v.visitCode(this);
    133     }
    134
    135
    136     /***
    137      * Dump code attribute to file stream in binary format.
    138      *
    139      * @param file Output file stream
    140      * @throws IOException
    141      */
    142     public final void dump( DataOutputStream file ) throws IOException {
    143         super.dump(file);
    144         file.writeShort(max_stack);
    145         file.writeShort(max_locals);
    146         file.writeInt(code_length);
    147         file.write(code, 0, code_length);
    148         file.writeShort(exception_table_length);
    149         for (int i = 0; i < exception_table_length; i++) {
    150             exception_table[i].dump(file);
    151         }
    152         file.writeShort(attributes_count);
    153         for (int i = 0; i < attributes_count; i++) {
    154             attributes[i].dump(file);
    155         }
    156     }
    157
    158
    159     /***
    160      * @return Collection of code attributes.
    161      * @see Attribute
    162      */
    163     public final Attribute[] getAttributes() {
    164         return attributes;
    165     }
    166
    167
    168     /***
    169      * @return LineNumberTable of Code, if it has one
    170      */
    171     public LineNumberTable getLineNumberTable() {
    172         for (int i = 0; i < attributes_count; i++) {
    173             if (attributes[i] instanceof LineNumberTable) {
    174                 return (LineNumberTable) attributes[i];
    175             }
    176         }
    177         return null;
    178     }
    179
    180
    181     /***
    182      * @return LocalVariableTable of Code, if it has one
    183      */
    184     public LocalVariableTable getLocalVariableTable() {
    185         for (int i = 0; i < attributes_count; i++) {
    186             if (attributes[i] instanceof LocalVariableTable) {
    187                 return (LocalVariableTable) attributes[i];
    188             }
    189         }
    190         return null;
    191     }
    192
    193
    194     /***
    195      * @return Actual byte code of the method.
    196      */
    197     public final byte[] getCode() {
    198         return code;
    199     }
    200
    201
    202     /***
    203      * @return Table of handled exceptions.
    204      * @see CodeException
    205      */
    206     public final CodeException[] getExceptionTable() {
    207         return exception_table;
    208     }
    209
    210
    211     /***
    212      * @return Number of local variables.
    213      */
    214     public final int getMaxLocals() {
    215         return max_locals;
    216     }
    217
    218
    219     /***
    220      * @return Maximum size of stack used by this method.
    221      */
    222     public final int getMaxStack() {
    223         return max_stack;
    224     }
    225
    226
    227     /***
    228      * @return the internal length of this code attribute (minus the first 6 bytes)
    229      * and excluding all its attributes
    230      */
    231     private final int getInternalLength() {
    232         return 2 /*max_stack*/+ 2 /*max_locals*/+ 4 /*code length*/
    233                 + code_length /*byte-code*/
    234                 + 2 /*exception-table length*/
    235                 + 8 * exception_table_length /* exception table */
    236                 + 2 /* attributes count */;
    237     }
    238
    239
    240     /***
    241      * @return the full size of this code attribute, minus its first 6 bytes,
    242      * including the size of all its contained attributes
    243      */
    244     private final int calculateLength() {
    245         int len = 0;
    246         for (int i = 0; i < attributes_count; i++) {
    247             len += attributes[i].length + 6 /*attribute header size*/;
    248         }
    249         return len + getInternalLength();
    250     }
    251
    252
    253     /***
    254      * @param attributes the attributes to set for this Code
    255      */
    256     public final void setAttributes( Attribute[] attributes ) {
    257         this.attributes = attributes;
    258         attributes_count = (attributes == null) ? 0 : attributes.length;
    259         length = calculateLength(); // Adjust length
    260     }
    261
    262
    263     /***
    264      * @param code byte code
    265      */
    266     public final void setCode( byte[] code ) {
    267         this.code = code;
    268         code_length = (code == null) ? 0 : code.length;
    269     }
    270
    271
    272     /***
    273      * @param exception_table exception table
    274      */
    275     public final void setExceptionTable( CodeException[] exception_table ) {
    276         this.exception_table = exception_table;
    277         exception_table_length = (exception_table == null) ? 0 : exception_table.length;
    278     }
    279
    280
    281     /***
    282      * @param max_locals maximum number of local variables
    283      */
    284     public final void setMaxLocals( int max_locals ) {
    285         this.max_locals = max_locals;
    286     }
    287
    288
    289     /***
    290      * @param max_stack maximum stack size
    291      */
    292     public final void setMaxStack( int max_stack ) {
    293         this.max_stack = max_stack;
    294     }
    295
    296
    297     /***
    298      * @return String representation of code chunk.
    299      */
    300     public final String toString( boolean verbose ) {
    301         StringBuffer buf;
    302         buf = new StringBuffer(100);
    303         buf.append("Code(max_stack = ").append(max_stack).append(", max_locals = ").append(
    304                 max_locals).append(", code_length = ").append(code_length).append(")\n").append(
    305                 Utility.codeToString(code, constant_pool, 0, -1, verbose));
    306         if (exception_table_length > 0) {
    307             buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
    308             for (int i = 0; i < exception_table_length; i++) {
    309                 buf.append(exception_table[i].toString(constant_pool, verbose)).append("\n");
    310             }
    311         }
    312         if (attributes_count > 0) {
    313             buf.append("\nAttribute(s) = \n");
    314             for (int i = 0; i < attributes_count; i++) {
    315                 buf.append(attributes[i].toString()).append("\n");
    316             }
    317         }
    318         return buf.toString();
    319     }
    320
    321
    322     /***
    323      * @return String representation of code chunk.
    324      */
    325     public final String toString() {
    326         return toString(true);
    327     }
    328
    329
    330     /***
    331      * @return deep copy of this attribute
    332      *
    333      * @param _constant_pool the constant pool to duplicate
    334      */
    335     public Attribute copy( ConstantPool _constant_pool ) {
    336         Code c = (Code) clone();
    337         if (code != null) {
    338             c.code = new byte[code.length];
    339             System.arraycopy(code, 0, c.code, 0, code.length);
    340         }
    341         c.constant_pool = _constant_pool;
    342         c.exception_table = new CodeException[exception_table_length];
    343         for (int i = 0; i < exception_table_length; i++) {
    344             c.exception_table[i] = exception_table[i].copy();
    345         }
    346         c.attributes = new Attribute[attributes_count];
    347         for (int i = 0; i < attributes_count; i++) {
    348             c.attributes[i] = attributes[i].copy(_constant_pool);
    349         }
    350         return c;
    351     }
    352 }