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 }