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

Select.java

00001 package de.fub.bytecode.generic;
00002 
00003 import java.io.*;
00004 import de.fub.bytecode.util.ByteSequence;
00005 
00006 /** 
00007  * Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions.
00008  *
00009  * @version $Id: Select.java,v 1.1.1.1 2002/01/24 03:41:41 pserver Exp $
00010  * @author  <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00011  * @see LOOKUPSWITCH
00012  * @see TABLESWITCH
00013  * @see InstructionList
00014  */
00015 public abstract class Select extends BranchInstruction
00016   implements VariableLengthInstruction, StackProducer
00017 {
00018   protected int[]               match;        // matches, i.e., case 1: ...
00019   protected int[]               indices;      // target offsets
00020   protected InstructionHandle[] targets;      // target objects in instruction list
00021   protected int                 fixed_length; // fixed length defined by subclasses
00022   protected int                 match_length; // number of cases
00023   protected int                 padding = 0;  // number of pad bytes for alignment
00024   
00025   /**
00026    * Empty constructor needed for the Class.newInstance() statement in
00027    * Instruction.readInstruction(). Not to be used otherwise.
00028    */
00029   Select() {}  
00030   /**
00031    * (Match, target) pairs for switch.
00032    * `Match' and `targets' must have the same length of course.
00033    *
00034    * @param match array of matching values
00035    * @param targets instruction targets
00036    * @param target default instruction target
00037    */
00038   Select(short tag, int[] match, InstructionHandle[] targets,
00039      InstructionHandle target) {
00040     super(tag, target);
00041 
00042     this.targets = targets;
00043     for(int i=0; i < targets.length; i++)
00044       notifyTarget(null, targets[i], this);
00045 
00046     this.match = match;
00047 
00048     if((match_length = match.length) != targets.length)
00049       throw new ClassGenException("Match and target array have not the same length");
00050 
00051     indices = new int[match_length];
00052   }  
00053   /**
00054    * @return true, if ih is target of this instruction
00055    */
00056   public boolean containsTarget(InstructionHandle ih) {
00057     if(target == ih)
00058       return true;
00059 
00060     for(int i=0; i < targets.length; i++)
00061       if(targets[i] == ih)
00062     return true;
00063 
00064     return false;
00065   }  
00066   /**
00067    * Inform targets that they're not targeted anymore.
00068    */
00069   void dispose() {
00070     super.dispose();
00071 
00072     for(int i=0; i < targets.length; i++)
00073       targets[i].removeTargeter(this);
00074   }  
00075   /**
00076    * Dump instruction as byte code to stream out.
00077    * @param out Output stream
00078    */
00079   public void dump(DataOutputStream out) throws IOException {
00080     out.writeByte(tag);
00081 
00082     for(int i=0; i < padding; i++) // Padding bytes
00083       out.writeByte(0);
00084 
00085     index = getTargetOffset();     // Write default target offset
00086     out.writeInt(index);
00087   }  
00088   /**
00089    * @return array of match target offsets
00090    */
00091   public int[] getIndices() { return indices; }  
00092   /**
00093    * @return array of match indices
00094    */
00095   public int[] getMatchs() { return match; }  
00096   /**
00097    * @return array of match targets
00098    */
00099   public InstructionHandle[] getTargets() { return targets; }  
00100   /**
00101    * Read needed data (e.g. index) from file.
00102    */
00103   protected void initFromFile(ByteSequence bytes, boolean wide) throws IOException
00104   {
00105     padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes
00106 
00107     for(int i=0; i < padding; i++) {
00108       byte b;
00109       if((b=bytes.readByte()) != 0)
00110     throw new ClassGenException("Padding byte != 0: " + b);
00111     }
00112     
00113     // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH)
00114     index = bytes.readInt();
00115   }  
00116   /**
00117    * Set branch target for `i'th case
00118    */
00119   public void setTarget(int i, InstructionHandle target) {
00120     notifyTarget(targets[i], target, this);
00121     targets[i] = target;
00122   }  
00123   /**
00124    * @return mnemonic for instruction
00125    */
00126   public String toString(boolean verbose) {
00127     StringBuffer buf = new StringBuffer(super.toString(verbose));
00128 
00129     if(verbose) {
00130       for(int i=0; i < match_length; i++) {
00131     String s = "null";
00132     
00133     if(targets[i] != null)
00134       s = targets[i].getInstruction().toString();
00135     
00136     buf.append("(" + match[i] + ", " + s + " = {" + indices[i] + "})");
00137       }
00138     }
00139     else
00140       buf.append(" ...");
00141     
00142     return buf.toString();
00143   }  
00144   /**
00145    * Since this is a variable length instruction, it may shift the following
00146    * instructions which then need to update their position.
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; // Additional offset caused by preceding SWITCHs, GOTOs, etc.
00159 
00160     short old_length = length;
00161 
00162     /* Alignment on 4-byte-boundary, + 1, because of tag byte.
00163      */
00164     padding = (4 - ((position + 1) % 4)) % 4;
00165     length  = (short)(fixed_length + padding); // Update length
00166 
00167     return length - old_length;
00168   }  
00169   /**
00170    * @param old_ih old target
00171    * @param new_ih new target
00172    */
00173   public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) {
00174     boolean targeted = false;
00175 
00176     if(target == old_ih) {
00177       targeted = true;
00178       setTarget(new_ih);
00179     }
00180 
00181     for(int i=0; i < targets.length; i++) {
00182       if(targets[i] == old_ih) {
00183     targeted = true;
00184     setTarget(i, new_ih);
00185       }
00186     }
00187     
00188     if(!targeted)
00189       throw new ClassGenException("Not targeting " + old_ih);
00190   }  
00191 }

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