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