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

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