View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   package com.sun.org.apache.bcel.internal.classfile;
6   
7   /* ====================================================================
8    * The Apache Software License, Version 1.1
9    *
10   * Copyright (c) 2001 The Apache Software Foundation.  All rights
11   * reserved.
12   *
13   * Redistribution and use in source and binary forms, with or without
14   * modification, are permitted provided that the following conditions
15   * are met:
16   *
17   * 1. Redistributions of source code must retain the above copyright
18   *    notice, this list of conditions and the following disclaimer.
19   *
20   * 2. Redistributions in binary form must reproduce the above copyright
21   *    notice, this list of conditions and the following disclaimer in
22   *    the documentation and/or other materials provided with the
23   *    distribution.
24   *
25   * 3. The end-user documentation included with the redistribution,
26   *    if any, must include the following acknowledgment:
27   *       "This product includes software developed by the
28   *        Apache Software Foundation (http://www.apache.org/)."
29   *    Alternately, this acknowledgment may appear in the software itself,
30   *    if and wherever such third-party acknowledgments normally appear.
31   *
32   * 4. The names "Apache" and "Apache Software Foundation" and
33   *    "Apache BCEL" must not be used to endorse or promote products
34   *    derived from this software without prior written permission. For
35   *    written permission, please contact apache@apache.org.
36   *
37   * 5. Products derived from this software may not be called "Apache",
38   *    "Apache BCEL", nor may "Apache" appear in their name, without
39   *    prior written permission of the Apache Software Foundation.
40   *
41   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52   * SUCH DAMAGE.
53   * ====================================================================
54   *
55   * This software consists of voluntary contributions made by many
56   * individuals on behalf of the Apache Software Foundation.  For more
57   * information on the Apache Software Foundation, please see
58   * <http://www.apache.org/>.
59   */
60  
61  import  com.sun.org.apache.bcel.internal.Constants;
62  import  java.io.*;
63  
64  /**
65   * This class represents a chunk of Java byte code contained in a
66   * method. It is instantiated by the
67   * <em>Attribute.readAttribute()</em> method. A <em>Code</em>
68   * attribute contains informations about operand stack, local
69   * variables, byte code and the exceptions handled within this
70   * method.
71   *
72   * This attribute has attributes itself, namely <em>LineNumberTable</em> which
73   * is used for debugging purposes and <em>LocalVariableTable</em> which
74   * contains information about the local variables.
75   *
76   * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
77   * @see     Attribute
78   * @see     CodeException
79   * @see     LineNumberTable
80   * @see LocalVariableTable
81   */
82  public final class Code extends Attribute {
83    private int             max_stack;   // Maximum size of stack used by this method
84    private int             max_locals;  // Number of local variables
85    private int             code_length; // Length of code in bytes
86    private byte[]          code;        // Actual byte code
87  
88    private int             exception_table_length;
89    private CodeException[] exception_table;  // Table of handled exceptions
90    private int             attributes_count; // Attributes of code: LineNumber
91    private Attribute[]     attributes;       // or LocalVariable
92  
93    /**
94     * Initialize from another object. Note that both objects use the same
95     * references (shallow copy). Use copy() for a physical copy.
96     */
97    public Code(Code c) {
98      this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(),
99           c.getCode(), c.getExceptionTable(), c.getAttributes(),
100          c.getConstantPool());
101   }
102 
103   /**
104    * @param name_index Index pointing to the name <em>Code</em>
105    * @param length Content length in bytes
106    * @param file Input stream
107    * @param constant_pool Array of constants
108    */
109   Code(int name_index, int length, DataInputStream file,
110        ConstantPool constant_pool) throws IOException
111   {
112     // Initialize with some default values which will be overwritten later
113     this(name_index, length,
114          file.readUnsignedShort(), file.readUnsignedShort(),
115          (byte[])null, (CodeException[])null, (Attribute[])null,
116          constant_pool);
117 
118     code_length = file.readInt();
119     code = new byte[code_length]; // Read byte code
120     file.readFully(code);
121 
122     /* Read exception table that contains all regions where an exception
123      * handler is active, i.e., a try { ... } catch() block.
124      */
125     exception_table_length = file.readUnsignedShort();
126     exception_table        = new CodeException[exception_table_length];
127 
128     for(int i=0; i < exception_table_length; i++)
129       exception_table[i] = new CodeException(file);
130 
131     /* Read all attributes, currently `LineNumberTable' and
132      * `LocalVariableTable'
133      */
134     attributes_count = file.readUnsignedShort();
135     attributes = new Attribute[attributes_count];
136     for(int i=0; i < attributes_count; i++)
137       attributes[i] = Attribute.readAttribute(file, constant_pool);
138 
139     /* Adjust length, because of setAttributes in this(), s.b.  length
140      * is incorrect, because it didn't take the internal attributes
141      * into account yet! Very subtle bug, fixed in 3.1.1.
142      */
143     this.length = length;
144   }
145 
146   /**
147    * @param name_index Index pointing to the name <em>Code</em>
148    * @param length Content length in bytes
149    * @param max_stack Maximum size of stack
150    * @param max_locals Number of local variables
151    * @param code Actual byte code
152    * @param exception_table Table of handled exceptions
153    * @param attributes Attributes of code: LineNumber or LocalVariable
154    * @param constant_pool Array of constants
155    */
156   public Code(int name_index, int length,
157               int max_stack,  int max_locals,
158               byte[]          code,
159               CodeException[] exception_table,
160               Attribute[]     attributes,
161               ConstantPool    constant_pool)
162   {
163     super(Constants.ATTR_CODE, name_index, length, constant_pool);
164 
165     this.max_stack         = max_stack;
166     this.max_locals        = max_locals;
167 
168     setCode(code);
169     setExceptionTable(exception_table);
170     setAttributes(attributes); // Overwrites length!
171   }
172 
173   /**
174    * Called by objects that are traversing the nodes of the tree implicitely
175    * defined by the contents of a Java class. I.e., the hierarchy of methods,
176    * fields, attributes, etc. spawns a tree of objects.
177    *
178    * @param v Visitor object
179    */
180   public void accept(Visitor v) {
181     v.visitCode(this);
182   }
183 
184   /**
185    * Dump code attribute to file stream in binary format.
186    *
187    * @param file Output file stream
188    * @throws IOException
189    */
190   public final void dump(DataOutputStream file) throws IOException
191   {
192     super.dump(file);
193 
194     file.writeShort(max_stack);
195     file.writeShort(max_locals);
196     file.writeInt(code_length);
197     file.write(code, 0, code_length);
198 
199     file.writeShort(exception_table_length);
200     for(int i=0; i < exception_table_length; i++)
201       exception_table[i].dump(file);
202 
203     file.writeShort(attributes_count);
204     for(int i=0; i < attributes_count; i++)
205       attributes[i].dump(file);
206   }
207 
208   /**
209    * @return Collection of code attributes.
210    * @see Attribute
211    */
212   public final Attribute[] getAttributes()         { return attributes; }
213 
214   /**
215    * @return LineNumberTable of Code, if it has one
216    */
217   public LineNumberTable getLineNumberTable() {
218     for(int i=0; i < attributes_count; i++)
219       if(attributes[i] instanceof LineNumberTable)
220         return (LineNumberTable)attributes[i];
221 
222     return null;
223   }
224 
225   /**
226    * @return LocalVariableTable of Code, if it has one
227    */
228   public LocalVariableTable getLocalVariableTable() {
229     for(int i=0; i < attributes_count; i++)
230       if(attributes[i] instanceof LocalVariableTable)
231         return (LocalVariableTable)attributes[i];
232 
233     return null;
234   }
235 
236   /**
237    * @return Actual byte code of the method.
238    */
239   public final byte[] getCode()      { return code; }
240 
241   /**
242    * @return Table of handled exceptions.
243    * @see CodeException
244    */
245   public final CodeException[] getExceptionTable() { return exception_table; }
246 
247   /**
248    * @return Number of local variables.
249    */
250   public final int  getMaxLocals() { return max_locals; }
251 
252   /**
253    * @return Maximum size of stack used by this method.
254    */
255 
256   public final int  getMaxStack()  { return max_stack; }
257 
258   /**
259    * @return the internal length of this code attribute (minus the first 6 bytes)
260    * and excluding all its attributes
261    */
262   private final int getInternalLength() {
263     return 2 /*max_stack*/ + 2 /*max_locals*/ + 4 /*code length*/
264       + code_length /*byte-code*/
265       + 2 /*exception-table length*/
266       + 8 * exception_table_length /* exception table */
267       + 2 /* attributes count */;
268   }
269 
270   /**
271    * @return the full size of this code attribute, minus its first 6 bytes,
272    * including the size of all its contained attributes
273    */
274   private final int calculateLength() {
275     int len = 0;
276 
277     for(int i=0; i < attributes_count; i++)
278       len += attributes[i].length + 6 /*attribute header size*/;
279 
280     return len + getInternalLength();
281   }
282 
283   /**
284    * @param attributes.
285    */
286   public final void setAttributes(Attribute[] attributes) {
287     this.attributes  = attributes;
288     attributes_count = (attributes == null)? 0 : attributes.length;
289     length = calculateLength(); // Adjust length
290   }
291 
292   /**
293    * @param code byte code
294    */
295   public final void setCode(byte[] code) {
296     this.code   = code;
297     code_length = (code == null)? 0 : code.length;
298   }
299 
300   /**
301    * @param exception_table exception table
302    */
303   public final void setExceptionTable(CodeException[] exception_table) {
304     this.exception_table   = exception_table;
305     exception_table_length = (exception_table == null)? 0 :
306       exception_table.length;
307   }
308 
309   /**
310    * @param max_locals maximum number of local variables
311    */
312   public final void setMaxLocals(int max_locals) {
313     this.max_locals = max_locals;
314   }
315 
316   /**
317    * @param max_stack maximum stack size
318    */
319   public final void setMaxStack(int max_stack) {
320     this.max_stack = max_stack;
321   }
322 
323   /**
324    * @return String representation of code chunk.
325    */
326   public final String toString(boolean verbose) {
327     StringBuffer buf;
328 
329     buf = new StringBuffer("Code(max_stack = " + max_stack +
330                            ", max_locals = " + max_locals +
331                            ", code_length = " + code_length + ")\n" +
332                            Utility.codeToString(code, constant_pool, 0, -1, verbose));
333 
334     if(exception_table_length > 0) {
335       buf.append("\nException handler(s) = \n" + "From\tTo\tHandler\tType\n");
336 
337       for(int i=0; i < exception_table_length; i++)
338         buf.append(exception_table[i].toString(constant_pool, verbose) + "\n");
339     }
340 
341     if(attributes_count > 0) {
342       buf.append("\nAttribute(s) = \n");
343 
344       for(int i=0; i < attributes_count; i++)
345         buf.append(attributes[i].toString() + "\n");
346     }
347 
348     return buf.toString();
349   }
350 
351   /**
352    * @return String representation of code chunk.
353    */
354   public final String toString() {
355     return toString(true);
356   }
357 
358   /**
359    * @return deep copy of this attribute
360    */
361   public Attribute copy(ConstantPool constant_pool) {
362     Code c = (Code)clone();
363     c.code          = (byte[])code.clone();
364     c.constant_pool = constant_pool;
365 
366     c.exception_table = new CodeException[exception_table_length];
367     for(int i=0; i < exception_table_length; i++)
368       c.exception_table[i] = exception_table[i].copy();
369 
370     c.attributes = new Attribute[attributes_count];
371     for(int i=0; i < attributes_count; i++)
372       c.attributes[i] = attributes[i].copy(constant_pool);
373 
374     return c;
375   }
376 }