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