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

Instruction.java

00001 package de.fub.bytecode.generic;
00002 
00003 import de.fub.bytecode.Constants;
00004 import de.fub.bytecode.classfile.Utility;
00005 import de.fub.bytecode.classfile.ConstantPool;
00006 import java.io.*;
00007 import de.fub.bytecode.util.ByteSequence;
00008 import java.util.*;
00009 
00010 /** 
00011  * Abstract super class for all Java byte codes.
00012  *
00013  * @version $Id: Instruction.java,v 1.1.1.1 2002/01/24 03:41:40 pserver Exp $
00014  * @author  <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00015  */
00016 public abstract class Instruction implements Cloneable, Serializable {
00017   protected short length = 1;  // Length of instruction in bytes 
00018   protected short tag    = -1; // Opcode number
00019 
00020   /**
00021    * Empty constructor needed for the Class.newInstance() statement in
00022    * Instruction.readInstruction(). Not to be used otherwise.
00023    */
00024   Instruction() {}  
00025   public Instruction(short tag, short length) {
00026     this.length = length;
00027     this.tag    = tag;
00028   }  
00029   /**
00030    * Call corresponding visitor method(s). The order is:
00031    * Call visitor methods of implemented interfaces first, then
00032    * call methods according to the class hierarchy in descending order,
00033    * i.e., the most specific visitXXX() call comes last.
00034    *
00035    * @param v Visitor object
00036    */
00037   public abstract void accept(Visitor v);  
00038   private static final String className(short tag) {
00039     String name = Constants.OPCODE_NAMES[tag].toUpperCase();
00040 
00041     /* ICONST_0, etc. will be shortened to ICONST, etc., since ICONST_0 and the like
00042      * are not implemented (directly).
00043      */
00044     try {
00045       int  len = name.length();
00046       char ch1 = name.charAt(len - 2), ch2 = name.charAt(len - 1);
00047 
00048       if((ch1 == '_') && (ch2 >= '0')  && (ch2 <= '5'))
00049     name = name.substring(0, len - 2);
00050       
00051       if(name.equals("ICONST_M1")) // Special case
00052     name = "ICONST";
00053     } catch(StringIndexOutOfBoundsException e) { System.err.println(e); }
00054 
00055     return "de.fub.bytecode.generic." + name;
00056   }  
00057   /**
00058    * @return Number of words consumed from stack by this instruction
00059    */
00060   public int consumeStack() { return Constants.CONSUME_STACK[tag]; }  
00061   /**
00062    * Also works for instructions whose stack effect depends on the
00063    * constant pool entry they reference.
00064    * @return Number of words consumed from stack by this instruction
00065    */
00066   public int consumeStack(ConstantPoolGen cpg) {
00067     return consumeStack();
00068   }  
00069   /**
00070    * Use with caution, since `BranchInstruction's have a `target' reference which
00071    * is not copied correctly (only basic types are). This also applies for 
00072    * `Select' instructions with their multiple branch targets.
00073    *
00074    * @see BranchInstruction
00075    * @return (shallow) copy of an instruction
00076    */
00077   public Instruction copy() {
00078     Instruction i = null;
00079 
00080     try {
00081       i = (Instruction)clone();
00082     } catch(CloneNotSupportedException e) {
00083       System.err.println(e);
00084     }
00085 
00086     return i;
00087   }  
00088   /** Some instructions may be reused, so don't do anything by default.
00089    */
00090   void dispose() {  }  
00091   /**
00092    * Dump instruction as byte code to stream out.
00093    * @param out Output stream
00094    */
00095   public void dump(DataOutputStream out) throws IOException {
00096     out.writeByte(tag); // Common for all instructions
00097   }  
00098   /**
00099    * @return length (in bytes) of instruction
00100    */
00101   public int getLength()   { return length; }  
00102   /**
00103    * @return opcode number
00104    */
00105   public short getTag()    { return tag; }  
00106   /**
00107    * Read needed data (e.g. index) from file.
00108    *
00109    * @param bytes byte sequence to read from
00110    * @param wide "wide" instruction flag
00111    */
00112   protected void initFromFile(ByteSequence bytes, boolean wide)
00113     throws IOException
00114   {}  
00115   /**
00116    * @return Number of words produced onto stack by this instruction
00117    */
00118   public int produceStack() { return Constants.PRODUCE_STACK[tag]; }  
00119   /**
00120    * Also works for instructions whose stack effect depends on the
00121    * constant pool entry they reference.
00122    * @return Number of words produced onto stack by this instruction
00123    */
00124   public int produceStack(ConstantPoolGen cpg) {
00125     return produceStack();
00126   }  
00127   /**
00128    * Read an instruction from (byte code) input stream and return the
00129    * appropiate object.
00130    *
00131    * @param file file to read from
00132    * @return instruction object being read
00133    */
00134   public static final Instruction readInstruction(ByteSequence bytes)
00135     throws IOException
00136   {
00137     boolean     wide = false;
00138     short       tag  = (short)bytes.readUnsignedByte();
00139     Instruction obj  = null;
00140 
00141     if(tag == Constants.WIDE) { // Read next tag after wide byte
00142       wide = true;
00143       tag  = (short)bytes.readUnsignedByte();
00144     }
00145 
00146     if(InstructionConstants.INSTRUCTIONS[tag] != null)
00147       return InstructionConstants.INSTRUCTIONS[tag]; // Used predefined immutable object, if available
00148 
00149     /* Find appropiate class, instantiate an (empty) instruction object
00150      * and initialize it by hand.
00151      */
00152     try {
00153       Class clazz = Class.forName(className(tag));
00154       obj = (Instruction)clazz.newInstance();
00155 
00156       if(wide && !((obj instanceof LocalVariableInstruction) || (obj instanceof IINC) ||
00157            (obj instanceof RET)))
00158     throw new Exception("Illegal opcode after wide: " + tag);
00159 
00160       obj.setTag(tag);
00161       obj.initFromFile(bytes, wide); // Do further initializations, if any
00162       // Byte code offset set in InstructionList
00163     } catch(Exception e) { throw new ClassGenException(e.toString()); }
00164 
00165     return obj;
00166   }  
00167   /**
00168    * Needed in readInstruction.
00169    */
00170   private void setTag(short tag) { this.tag = tag; }  
00171   /**
00172    * @return mnemonic for instruction in verbose format
00173    */
00174   public String toString() {
00175     return toString(true);
00176   }  
00177   /**
00178    * @return mnemonic for instruction with sumbolic references resolved
00179    */
00180   public String toString(ConstantPool cp) {
00181     return toString(false);
00182   }  
00183   /**
00184    * Long output format:
00185    *
00186    * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" 
00187    * "("&lt;length of instruction&gt;")"
00188    *
00189    * @param verbose long/short format switch
00190    * @return mnemonic for instruction
00191    */
00192   public String toString(boolean verbose) {
00193     if(verbose)
00194       return Constants.OPCODE_NAMES[tag] + "[" + tag + "](" + length + ")";
00195     else
00196       return Constants.OPCODE_NAMES[tag];
00197   }  
00198 }

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