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

BranchInstruction.java

00001 package de.fub.bytecode.generic;
00002 
00003 import java.io.*;
00004 import de.fub.bytecode.util.ByteSequence;
00005 
00006 /** 
00007  * Abstract super class for branching instructions like GOTO, IFEQ, etc..
00008  * Branch instructions may have a variable length, namely GOTO, JSR, 
00009  * LOOKUPSWITCH and TABLESWITCH.
00010  *
00011  * @see InstructionList
00012  * @version $Id: BranchInstruction.java,v 1.1.1.1 2002/01/24 03:41:38 pserver Exp $
00013  * @author  <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00014  */
00015 public abstract class BranchInstruction extends Instruction implements InstructionTargeter {
00016   protected int               index;    // Branch target relative to this instruction
00017   protected InstructionHandle target;   // Target object in instruction list
00018   protected int               position; // Byte code offset
00019 
00020   /**
00021    * Empty constructor needed for the Class.newInstance() statement in
00022    * Instruction.readInstruction(). Not to be used otherwise.
00023    */
00024   BranchInstruction() {}  
00025   /** Common super constructor
00026    * @param tag Instruction opcode
00027    * @param target instruction to branch to
00028    */
00029   protected BranchInstruction(short tag, InstructionHandle target) {
00030     super(tag, (short)3);
00031     setTarget(target);
00032   }  
00033   /**
00034    * @return true, if ih is target of this instruction
00035    */
00036   public boolean containsTarget(InstructionHandle ih) {
00037     return (target == ih);
00038   }  
00039   /**
00040    * Inform target that it's not targeted anymore.
00041    */
00042   void dispose() {
00043     setTarget(null);
00044     index=-1;
00045     position=-1;
00046   }  
00047   /**
00048    * Dump instruction as byte code to stream out.
00049    * @param out Output stream
00050    */
00051   public void dump(DataOutputStream out) throws IOException {
00052     out.writeByte(tag);
00053 
00054     index = getTargetOffset();
00055 
00056     if(Math.abs(index) >= 32767) // too large for short
00057       throw new ClassGenException("Branch target offset too large for short");
00058 
00059     out.writeShort(index); // May be negative, i.e., point backwards
00060   }  
00061   /**
00062    * @return target offset in byte code
00063    */
00064   public final int getIndex() { return index; }  
00065   /**
00066    * @return target of branch instruction
00067    */
00068   public InstructionHandle getTarget() { return target; }  
00069   /**
00070    * @return the offset to this instruction's target
00071    */
00072   protected int getTargetOffset() { return getTargetOffset(target); }  
00073   /**
00074    * @param target branch target
00075    * @return the offset to  `target' relative to this instruction
00076    */
00077   protected int getTargetOffset(InstructionHandle target) {
00078     if(target == null)
00079       throw new ClassGenException("Target of " + super.toString(true) + 
00080                   " is invalid null handle");
00081 
00082     int t = target.getPosition();
00083 
00084     if(t < 0)
00085       throw new ClassGenException("Invalid branch target position offset for " +
00086                   super.toString(true) + ":" + t + ":" + target);
00087 
00088     return t - position;
00089   }  
00090   /**
00091    * Read needed data (e.g. index) from file. Conversion to a InstructionHandle
00092    * is done in InstructionList(byte[]).
00093    *
00094    * @param bytes input stream
00095    * @param wide wide prefix?
00096    * @see InstructionList
00097    */
00098   protected void initFromFile(ByteSequence bytes, boolean wide) throws IOException
00099   {
00100     length = 3;
00101     index  = bytes.readShort();
00102   }  
00103   /**
00104    * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen
00105    */
00106   static final void notifyTarget(InstructionHandle old_ih, InstructionHandle new_ih,
00107                  InstructionTargeter t) {
00108     if(old_ih != null)
00109       old_ih.removeTargeter(t);
00110     if(new_ih != null)
00111       new_ih.addTargeter(t);
00112   }  
00113   /**
00114    * Set branch target
00115    * @param target branch target
00116    */
00117   public void setTarget(InstructionHandle target) {
00118     notifyTarget(this.target, target, this);
00119     this.target = target;
00120   }  
00121   /**
00122    * Long output format:
00123    *
00124    * &lt;position in byte code&gt;
00125    * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" 
00126    * "("&lt;length of instruction&gt;")"
00127    * "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target offset&gt;
00128    *
00129    * @param verbose long/short format switch
00130    * @return mnemonic for instruction
00131    */
00132   public String toString(boolean verbose) {
00133     String s = super.toString(verbose);
00134     String t = "null";
00135 
00136     if(verbose) {
00137       if(target != null) {
00138     if(target.getInstruction() == this)
00139       t = "<points to itself>";
00140     else if(target.getInstruction() == null)
00141       t = "<null instruction!!!?>";
00142     else
00143       t = target.getInstruction().toString(verbose);
00144       }
00145     } else {
00146       if(target != null) {
00147     index = getTargetOffset();
00148     t = "" + (index + position);
00149       }
00150     }
00151 
00152     return s + " -> " + t;
00153   }  
00154   /**
00155    * Called by InstructionList.setPositions when setting the position for every
00156    * instruction. In the presence of variable length instructions `setPositions'
00157    * performs multiple passes over the instruction list to calculate the
00158    * correct (byte) positions and offsets by calling this function.
00159    *
00160    * @param offset additional offset caused by preceding (variable length) instructions
00161    * @param max_offset the maximum offset that may be caused by these instructions
00162    * @return additional offset caused by possible change of this instruction's length
00163    */
00164   protected int updatePosition(int offset, int max_offset) {
00165     position += offset;
00166     return 0;
00167   }  
00168   /**
00169    * @param old_ih old target
00170    * @param new_ih new target
00171    */
00172   public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) {
00173     if(target == old_ih)
00174       setTarget(new_ih);
00175     else
00176       throw new ClassGenException("Not targeting " + old_ih + ", but " + target);
00177   }  
00178 }

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