Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

Code.java

00001 package de.fub.bytecode.classfile;
00002 
00003 import  de.fub.bytecode.Constants;
00004 import  java.io.*;
00005 
00006 /** 
00007  * This class is derived from <em>Attribute</em> and represents a
00008  * code chunk. It is instantiated by the
00009  * <em>Attribute.readAttribute()</em> method. A <em>Code</em>
00010  * attribute contains informations about operand stack, local variables,
00011  * byte code and the exceptions handled within this method.
00012  *
00013  * This attribute has attributes itself, namely <em>LineNumberTable</em> which
00014  * is used for debugging purposes and <em>LocalVariableTable</em> which 
00015  * contains information about the local variables.
00016  *
00017  * @version $Id: Code.java,v 1.1.1.1 2002/01/24 03:44:00 pserver Exp $
00018  * @author  <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00019  * @see     Attribute
00020  * @see     CodeException
00021  * @see     LineNumberTable
00022  * @see     LocalVariableTable 
00023 */
00024 public final class Code extends Attribute {
00025   private int             max_stack;   // Maximum size of stack used by this method
00026   private int             max_locals;  // Number of local variables
00027   private int             code_length; // Length of code in bytes
00028   private byte[]          code;        // Actual byte code
00029 
00030   private int             exception_table_length;
00031   private CodeException[] exception_table;  // Table of handled exceptions
00032   private int             attributes_count; // Attributes of code: LineNumber
00033   private Attribute[]     attributes;       // or LocalVariable
00034 
00035   /**
00036    * @param name_index Index pointing to the name <em>Code</em>
00037    * @param length Content length in bytes
00038    * @param max_stack Maximum size of stack
00039    * @param max_locals Number of local variables
00040    * @param code Actual byte code
00041    * @param exception_table Table of handled exceptions
00042    * @param attributes Attributes of code: LineNumber or LocalVariable
00043    * @param constant_pool Array of constants
00044    */
00045   public Code(int name_index, int length, 
00046           int max_stack,  int max_locals,
00047           byte[]          code,
00048           CodeException[] exception_table,
00049           Attribute[]     attributes,
00050           ConstantPool    constant_pool)
00051   {
00052     super(ATTR_CODE, name_index, length, constant_pool);
00053 
00054     this.max_stack         = max_stack;
00055     this.max_locals        = max_locals;
00056 
00057     setCode(code);
00058     setExceptionTable(exception_table);
00059     setAttributes(attributes); // Overwrites length!
00060   }  
00061   /**
00062    * @param name_index Index pointing to the name <em>Code</em>
00063    * @param length Content length in bytes
00064    * @param file Input stream
00065    * @param constant_pool Array of constants
00066    */
00067   Code(int name_index, int length, DataInputStream file,
00068        ConstantPool constant_pool) throws IOException
00069   {
00070     // Initialize with some default values which will be overwritten later
00071     this(name_index, length,
00072      file.readUnsignedShort(), file.readUnsignedShort(),
00073      (byte[])null, (CodeException[])null, (Attribute[])null,
00074      constant_pool);
00075 
00076     code_length = file.readInt();
00077     code = new byte[code_length]; // Read byte code
00078     file.readFully(code);
00079 
00080     /* Read exception table that contains all regions where an exception
00081      * handler is active, i.e. a try { ... } catch() block.
00082      */
00083     exception_table_length = file.readUnsignedShort();
00084     exception_table        = new CodeException[exception_table_length];
00085 
00086     for(int i=0; i < exception_table_length; i++)
00087       exception_table[i] = new CodeException(file);
00088 
00089     /* Read all attributes, currently `LineNumberTable' and
00090      * `LocalVariableTable'
00091      */
00092     attributes_count = file.readUnsignedShort();
00093     attributes = new Attribute[attributes_count];
00094     for(int i=0; i < attributes_count; i++)
00095       attributes[i] = Attribute.readAttribute(file, constant_pool);
00096 
00097     /* Adjust length, because of setAttributes in this(), s.b.  length
00098      * is incorrect, because it didn't take the internal attributes
00099      * into account yet! Very subtle bug, fixed in 3.1.1.
00100      */
00101     this.length = length;
00102   }  
00103   /**
00104    * Initialize from another object. Note that both objects use the same
00105    * references (shallow copy). Use clone() for a physical copy.
00106    */
00107   public Code(Code c) {
00108     this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(),
00109      c.getCode(), c.getExceptionTable(), c.getAttributes(), 
00110      c.getConstantPool());
00111   }  
00112   /**
00113    * Called by objects that are traversing the nodes of the tree implicitely
00114    * defined by the contents of a Java class. I.e., the hierarchy of methods,
00115    * fields, attributes, etc. spawns a tree of objects.
00116    *
00117    * @param v Visitor object
00118    */
00119   public void accept(Visitor v) {
00120     v.visitCode(this);
00121   }  
00122   /**
00123    * @return the full size of this code attribute, minus its first 6 bytes,
00124    * including the size of all its contained attributes
00125    */
00126   private final int calculateLength() {
00127     int len = 0;
00128 
00129     for(int i=0; i < attributes_count; i++)
00130       len += attributes[i].length + 6 /*attribute header size*/;
00131 
00132     return len + getInternalLength();
00133   }  
00134   /**
00135    * @return deep copy of this attribute
00136    */
00137   public Attribute copy(ConstantPool constant_pool) {
00138     Code c = (Code)clone();
00139     c.code          = (byte[])code.clone();
00140     c.constant_pool = constant_pool;
00141   
00142     c.exception_table = new CodeException[exception_table_length];
00143     for(int i=0; i < exception_table_length; i++)
00144       c.exception_table[i] = exception_table[i].copy();
00145 
00146     c.attributes = new Attribute[attributes_count];
00147     for(int i=0; i < attributes_count; i++)
00148       c.attributes[i] = attributes[i].copy(constant_pool);
00149 
00150     return c;
00151   }  
00152   /**
00153    * Dump code attribute to file stream in binary format.
00154    *
00155    * @param file Output file stream
00156    * @throw IOException
00157    */ 
00158   public final void dump(DataOutputStream file) throws IOException
00159   {
00160     super.dump(file);
00161 
00162     file.writeShort(max_stack);
00163     file.writeShort(max_locals);
00164     file.writeInt(code_length);
00165     file.write(code, 0, code_length);
00166 
00167     file.writeShort(exception_table_length);
00168     for(int i=0; i < exception_table_length; i++)
00169       exception_table[i].dump(file);
00170     
00171     file.writeShort(attributes_count);
00172     for(int i=0; i < attributes_count; i++)
00173       attributes[i].dump(file);
00174   }  
00175   /**
00176    * @return Collection of code attributes.
00177    * @see Attribute
00178    */   
00179   public final Attribute[] getAttributes()         { return attributes; }  
00180   /**
00181    * @return Actual byte code of the method.
00182    */  
00183   public final byte[] getCode()      { return code; }  
00184   /**
00185    * @return Table of handled exceptions.
00186    * @see CodeException
00187    */  
00188   public final CodeException[] getExceptionTable() { return exception_table; }  
00189   /**
00190    * @return the internal length of this code attribute (minus the first 6 bytes) 
00191    * and excluding all its attributes
00192    */
00193   private final int getInternalLength() {
00194     return 2 /*max_stack*/ + 2 /*max_locals*/ + 4 /*code length*/ 
00195       + code_length /*byte-code*/
00196       + 2 /*exception-table length*/ 
00197       + 8 * exception_table_length /* exception table */
00198       + 2 /* attributes count */;
00199   }  
00200   /**
00201    * @return LineNumberTable of Code, if it has one
00202    */
00203   public LineNumberTable getLineNumberTable() {
00204     for(int i=0; i < attributes_count; i++)
00205       if(attributes[i] instanceof LineNumberTable)
00206     return (LineNumberTable)attributes[i];
00207 
00208     return null;
00209   }  
00210   /**
00211    * @return LocalVariableTable of Code, if it has one
00212    */
00213   public LocalVariableTable getLocalVariableTable() {
00214     for(int i=0; i < attributes_count; i++)
00215       if(attributes[i] instanceof LocalVariableTable)
00216     return (LocalVariableTable)attributes[i];
00217 
00218     return null;
00219   }  
00220   /**
00221    * @return Number of local variables.
00222    */  
00223   public final int  getMaxLocals() { return max_locals; }  
00224   /**
00225    * @return Maximum size of stack used by this method.
00226    */
00227 
00228   public final int  getMaxStack()  { return max_stack; }  
00229   /**
00230    * @param attributes.
00231    */
00232   public final void setAttributes(Attribute[] attributes) {
00233     this.attributes  = attributes;
00234     attributes_count = (attributes == null)? 0 : attributes.length;
00235     length = calculateLength(); // Adjust length
00236   }  
00237   /**
00238    * @param code byte code
00239    */
00240   public final void setCode(byte[] code) {
00241     this.code   = code;
00242     code_length = (code == null)? 0 : code.length;
00243   }  
00244   /**
00245    * @param exception_table exception table
00246    */
00247   public final void setExceptionTable(CodeException[] exception_table) {
00248     this.exception_table   = exception_table;
00249     exception_table_length = (exception_table == null)? 0 :
00250       exception_table.length;
00251   }  
00252   /**
00253    * @param max_locals maximum number of local variables
00254    */
00255   public final void setMaxLocals(int max_locals) {
00256     this.max_locals = max_locals;
00257   }  
00258   /**
00259    * @param max_stack maximum stack size
00260    */
00261   public final void setMaxStack(int max_stack) {
00262     this.max_stack = max_stack;
00263   }  
00264   /**
00265    * @return String representation of code chunk.
00266    */ 
00267   public final String toString() {
00268     return toString(true);
00269   }  
00270   /**
00271    * @return String representation of code chunk.
00272    */ 
00273   public final String toString(boolean verbose) {
00274     StringBuffer buf;
00275 
00276     buf = new StringBuffer("Code(max_stack = " + max_stack +
00277                ", max_locals = " + max_locals +
00278                ", code_length = " + code_length + ")\n" +
00279                Utility.codeToString(code, constant_pool, 0, -1, verbose));
00280 
00281     if(exception_table_length > 0) {
00282       buf.append("\nException handler(s) = \n" + "From\tTo\tHandler\tType\n");
00283 
00284       for(int i=0; i < exception_table_length; i++)
00285     buf.append(exception_table[i].toString(constant_pool, verbose) + "\n");
00286     }
00287 
00288     if(attributes_count > 0) {
00289       buf.append("\nAttribute(s) = \n");
00290 
00291       for(int i=0; i < attributes_count; i++)
00292     buf.append(attributes[i].toString() + "\n");
00293     }
00294 
00295     return buf.toString();    
00296   }  
00297 }

Generated at Thu Feb 7 06:42:33 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001