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

InstructionHandle.java

00001 package de.fub.bytecode.generic;
00002 
00003 import de.fub.bytecode.classfile.Utility;
00004 import java.util.Vector;
00005 import java.util.Hashtable;
00006 
00007 /**
00008  * Instances of this class give users a handle to the instructions contained in
00009  * an InstructionList. Instruction objects may be uesd more than once within a
00010  * list, this is useful because it saves memory and may be much faster.
00011  *
00012  * Within an InstructionList an InstructionHandle object is wrapped
00013  * around all instructions, i.e., it implements a cell in a
00014  * doubly-linked list. From the outside only the next and the
00015  * previous instruction (handle) are accessible. One
00016  * can traverse the list via an Enumeration returned by
00017  * InstructionList.elements().
00018  *
00019  * @version $Id: InstructionHandle.java,v 1.1.1.1 2002/01/24 03:41:40 pserver Exp $
00020  * @author  <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00021  * @see Instruction
00022  * @see BranchHandle
00023  * @see InstructionList 
00024  */
00025 public class InstructionHandle implements java.io.Serializable {
00026   InstructionHandle next, prev;  // Will be set from the outside
00027   Instruction       instruction;
00028   protected int     i_position = -1; // byte code offset of instruction
00029   private Vector    targeters;
00030   private Hashtable attributes;
00031 
00032   private static InstructionHandle ih_list = null; // List of reusable handles
00033 
00034   /*private*/ protected InstructionHandle(Instruction i) {
00035     setInstruction(i);
00036   }  
00037   /** Convenience method, simply calls accept() on the contained instruction.
00038    *
00039    * @param v Visitor object
00040    */
00041   public void accept(Visitor v) {
00042     instruction.accept(v);
00043   }  
00044   /** Add an attribute to an instruction handle.
00045    *
00046    * @param key the key object to store/retrieve the attribute
00047    * @param attr the attribute to associate with this handle
00048    */
00049   public void addAttribute(Object key, Object attr) {
00050     if(attributes == null)
00051       attributes = new Hashtable(3);
00052     
00053     attributes.put(key, attr);
00054   }  
00055   /** Overridden in BranchHandle
00056    */
00057   protected void addHandle() {
00058     next    = ih_list;
00059     ih_list = this;
00060   }  
00061   /**
00062    * Denote this handle is being referenced by t.
00063    */
00064   public void addTargeter(InstructionTargeter t) {
00065     if(targeters == null)
00066       targeters = new Vector();
00067 
00068     if(!targeters.contains(t))
00069       targeters.addElement(t);
00070   }  
00071   /**
00072    * Delete contents, i.e., remove user access and make handle reusable.
00073    */
00074   void dispose() {
00075     next = prev = null;
00076     instruction.dispose();
00077     instruction = null;
00078     i_position = -1;
00079     attributes = null;
00080     removeAllTargeters();
00081     addHandle();
00082   }  
00083   /** Get attribute of an instruction handle.
00084    *
00085    * @param key the key object to store/retrieve the attribute
00086    */
00087   public Object getAttribute(Object key) {
00088     if(attributes != null)
00089       return attributes.get(key);
00090 
00091     return null;
00092   }  
00093   public final Instruction       getInstruction() { return instruction; }  
00094   /** Factory method.
00095    */
00096   static final InstructionHandle getInstructionHandle(Instruction i) {
00097     if(ih_list == null)
00098       return new InstructionHandle(i);
00099     else {
00100       InstructionHandle ih = ih_list;
00101       ih_list = ih.next;
00102 
00103       ih.setInstruction(i);
00104 
00105       return ih;
00106     }
00107   }  
00108   public final InstructionHandle getNext()        { return next; }  
00109   /** @return the position, i.e., the byte code offset of the contained
00110    * instruction. This is accurate only after
00111    * InstructionList.setPositions() has been called.
00112    */
00113   public int getPosition() { return i_position; }  
00114   public final InstructionHandle getPrev()        { return prev; }  
00115   /**
00116    * @return null, if there are no targeters
00117    */
00118   public InstructionTargeter[] getTargeters() {
00119     if(!hasTargeters())
00120       return null;
00121     
00122     InstructionTargeter[] t = new InstructionTargeter[targeters.size()];
00123     targeters.copyInto(t);
00124     return t;
00125   }  
00126   public boolean hasTargeters() {
00127     return (targeters != null) && (targeters.size() > 0);
00128   }  
00129   /** Remove all targeters, if any.
00130    */
00131   public void removeAllTargeters() {
00132     if(targeters != null)
00133       targeters.removeAllElements();
00134   }  
00135   /** Delete an attribute of an instruction handle.
00136    *
00137    * @param key the key object to retrieve the attribute
00138    */
00139   public void removeAttribute(Object key) {
00140     if(attributes != null)
00141       attributes.remove(key);
00142   }  
00143   /**
00144    * Denote this handle isn't referenced anymore by t.
00145    */
00146   public void removeTargeter(InstructionTargeter t) {
00147     targeters.removeElement(t);
00148   }  
00149   /**
00150    * Replace current instruction contained in this handle.
00151    * Old instruction is disposed using Instruction.dispose().
00152    */
00153   public void setInstruction(Instruction i) { // Overridden in BranchHandle
00154     if(i == null)
00155       throw new ClassGenException("Assigning null to handle");
00156 
00157     if((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction))
00158       throw new ClassGenException("Assigning branch instruction " + i + " to plain handle");
00159 
00160     if(instruction != null)
00161       instruction.dispose();
00162 
00163     instruction = i;
00164   }  
00165   /** Set the position, i.e., the byte code offset of the contained
00166    * instruction.
00167    */
00168   void setPosition(int pos) { i_position = pos; }  
00169   /**
00170    * Temporarily swap the current instruction, without disturbing
00171    * anything. Meant to be used by a debugger, implementing
00172    * breakpoints. Current instruction is returned.
00173    */
00174   public Instruction swapInstruction(Instruction i) {
00175     Instruction oldInstruction = instruction;
00176     instruction = i;
00177     return oldInstruction;
00178   }  
00179   /** @return a string representation of the contained instruction. 
00180    */
00181   public String toString() {
00182     return toString(true);
00183   }  
00184   /** @return a (verbose) string representation of the contained instruction. 
00185    */
00186   public String toString(boolean verbose) {
00187     return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose);
00188   }  
00189   /**
00190    * Called by InstructionList.setPositions when setting the position for every
00191    * instruction. In the presence of variable length instructions `setPositions()'
00192    * performs multiple passes over the instruction list to calculate the
00193    * correct (byte) positions and offsets by calling this function.
00194    *
00195    * @param offset additional offset caused by preceding (variable length) instructions
00196    * @param max_offset the maximum offset that may be caused by these instructions
00197    * @return additional offset caused by possible change of this instruction's length
00198    */
00199   protected int updatePosition(int offset, int max_offset) {
00200     i_position += offset;
00201     return 0;
00202   }  
00203 }

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