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