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:44:04 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 implements VariableLengthInstruction
00016 {
00017   protected int[]               match;        // matches, i.e. case 1: ...
00018   protected int[]               indices;      // target offsets
00019   protected InstructionHandle[] targets;      // target objects in instruction list
00020   protected int                 fixed_length; // fixed length defined by subclasses
00021   protected int                 match_length; // number of cases
00022   protected int                 padding = 0;  // number of pad bytes for alignment
00023   
00024   /**
00025    * Empty constructor needed for the Class.newInstance() statement in
00026    * Instruction.readInstruction(). Not to be used otherwise.
00027    */
00028   Select() {}  
00029   /**
00030    * (Match, target) pairs for switch.
00031    * `Match' and `targets' must have the same length of course.
00032    *
00033    * @param match array of matching values
00034    * @param targets instruction targets
00035    * @param target default instruction target
00036    */
00037   Select(short tag, int[] match, InstructionHandle[] targets,
00038      InstructionHandle target) {
00039     super(tag, target);
00040 
00041     this.targets = targets;
00042     for(int i=0; i < targets.length; i++)
00043       notifyTarget(null, targets[i], this);
00044 
00045     this.match = match;
00046 
00047     if((match_length = match.length) != targets.length)
00048       throw new ClassGenException("Match and target array have not the same length");
00049 
00050     indices = new int[match_length];
00051   }  
00052   /**
00053    * @return true, if ih is target of this instruction
00054    */
00055   public boolean containsTarget(InstructionHandle ih) {
00056     if(target == ih)
00057       return true;
00058 
00059     for(int i=0; i < targets.length; i++)
00060       if(targets[i] == ih)
00061     return true;
00062 
00063     return false;
00064   }  
00065   /**
00066    * Inform targets that they're not targeted anymore.
00067    */
00068   void dispose() {
00069     super.dispose();
00070 
00071     for(int i=0; i < targets.length; i++)
00072       targets[i].removeTargeter(this);
00073   }  
00074   /**
00075    * Dump instruction as byte code to stream out.
00076    * @param out Output stream
00077    */
00078   public void dump(DataOutputStream out) throws IOException {
00079     out.writeByte(tag);
00080 
00081     for(int i=0; i < padding; i++) // Padding bytes
00082       out.writeByte(0);
00083 
00084     index = getTargetOffset();     // Write default target offset
00085     out.writeInt(index);
00086   }  
00087   /**
00088    * @return array of match target offsets
00089    */
00090   public int[] getIndices() { return indices; }  
00091   /**
00092    * @return array of match indices
00093    */
00094   public int[] getMatchs() { return match; }  
00095   /**
00096    * @return array of match targets
00097    */
00098   public InstructionHandle[] getTargets() { return targets; }  
00099   /**
00100    * Read needed data (e.g. index) from file.
00101    */
00102   protected void initFromFile(ByteSequence bytes, boolean wide) throws IOException
00103   {
00104     padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes
00105 
00106     for(int i=0; i < padding; i++) {
00107       byte b;
00108       if((b=bytes.readByte()) != 0)
00109     throw new ClassGenException("Padding byte != 0: " + b);
00110     }
00111     
00112     // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH)
00113     index = bytes.readInt();
00114   }  
00115   /**
00116    * Set branch target for `i'th case
00117    */
00118   public void setTarget(int i, InstructionHandle target) {
00119     notifyTarget(targets[i], target, this);
00120     targets[i] = target;
00121   }  
00122   /**
00123    * @return mnemonic for instruction
00124    */
00125   public String toString(boolean verbose) {
00126     StringBuffer buf = new StringBuffer(super.toString(verbose));
00127 
00128     if(verbose) {
00129       for(int i=0; i < match_length; i++) {
00130     String s = "null";
00131     
00132     if(targets[i] != null)
00133       s = targets[i].getInstruction().toString();
00134     
00135     buf.append("(" + match[i] + ", " + s + " = {" + indices[i] + "})");
00136       }
00137     }
00138     else
00139       buf.append(" ...");
00140     
00141     return buf.toString();
00142   }  
00143   /**
00144    * Since this is a variable length instruction, it may shift the following
00145    * instructions which then need to update their position.
00146    *
00147    * Called by InstructionList.setPositions when setting the position for every
00148    * instruction. In the presence of variable length instructions `setPositions'
00149    * performs multiple passes over the instruction list to calculate the
00150    * correct (byte) positions and offsets by calling this function.
00151    *
00152    * @param offset additional offset caused by preceding (variable length) instructions
00153    * @param max_offset the maximum offset that may be caused by these instructions
00154    * @return additional offset caused by possible change of this instruction's length
00155    */
00156   protected int updatePosition(int offset, int max_offset) {
00157     position += offset; // Additional offset caused by preceding SWITCHs, GOTOs, etc.
00158 
00159     short old_length = length;
00160 
00161     /* Alignment on 4-byte-boundary, + 1, because of tag byte.
00162      */
00163     padding = (4 - ((position + 1) % 4)) % 4;
00164     length  = (short)(fixed_length + padding); // Update length
00165 
00166     return length - old_length;
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     boolean targeted = false;
00174 
00175     if(target == old_ih) {
00176       targeted = true;
00177       setTarget(new_ih);
00178     }
00179 
00180     for(int i=0; i < targets.length; i++) {
00181       if(targets[i] == old_ih) {
00182     targeted = true;
00183     setTarget(i, new_ih);
00184       }
00185     }
00186     
00187     if(!targeted)
00188       throw new ClassGenException("Not targeting " + old_ih);
00189   }  
00190 }

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