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

InstructionList.java

00001 package de.fub.bytecode.generic;
00002 
00003 import de.fub.bytecode.Constants;
00004 import de.fub.bytecode.util.ByteSequence;
00005 import java.io.*;
00006 import java.util.Enumeration;
00007 import java.util.Hashtable;
00008 import java.util.Vector;
00009 
00010 /** 
00011  * This class is a container for a list of <a
00012  * href="Instruction.html">Instruction</a> objects. Instructions can
00013  * be appended, inserted, moved, deleted, etc.. Instructions are being
00014  * wrapped into <a
00015  * href="InstructionHandle.html">InstructionHandles</a> objects that
00016  * are returned upon append/insert operations. They give the user
00017  * (read only) access to the list structure, such that it can be traversed and
00018  * manipulated in a controlled way.
00019  *
00020  * A list is finally dumped to a byte code array with <a
00021  * href="#getByteCode()">getByteCode</a>.
00022  *
00023  * @version $Id: InstructionList.java,v 1.1.1.1 2002/01/24 03:41:40 pserver Exp $
00024  * @author  <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00025  * @see     Instruction
00026  * @see     InstructionHandle
00027  * @see BranchHandle
00028  */
00029 public class InstructionList implements Serializable {
00030   private InstructionHandle start  = null, end = null;
00031   private int               length = 0; // number of elements in list
00032   private int[]             byte_positions; // byte code offsets corresponding to instructions
00033 
00034   private Vector observers;
00035 
00036   /**
00037    * Create (empty) instruction list.
00038    */
00039   public InstructionList() {}  
00040   /**
00041    * Initialize instruction list from byte array.
00042    *
00043    * @param code byte array containing the instructions
00044    */
00045   public InstructionList(byte[] code) {
00046     ByteSequence        bytes = new ByteSequence(code);
00047     InstructionHandle[] ihs   = new InstructionHandle[code.length];
00048     int[]               pos   = new int[code.length]; // Can't be more than that
00049     int                 count = 0; // Contains actual length
00050 
00051     /* Pass 1: Create an object for each byte code and append them
00052      * to the list.
00053      */
00054     try {
00055       while(bytes.available() > 0) {
00056     // Remember byte offset and associate it with the instruction
00057     int off =  bytes.getIndex();
00058     pos[count] = off;
00059     
00060     /* Read one instruction from the byte stream, the byte position is set
00061      * accordingly.
00062      */
00063     Instruction       i = Instruction.readInstruction(bytes);
00064     InstructionHandle ih;
00065     if(i instanceof BranchInstruction) // Use proper append() method
00066       ih = append((BranchInstruction)i);
00067     else
00068       ih = append(i);
00069 
00070     ih.setPosition(off);
00071     ihs[count] = ih;
00072     
00073     count++;
00074       }
00075     } catch(IOException e) { throw new ClassGenException(e.toString()); }
00076 
00077     byte_positions = new int[count]; // Trim to proper size
00078     System.arraycopy(pos, 0, byte_positions, 0, count);
00079 
00080     /* Pass 2: Look for BranchInstruction and update their targets, i.e.,
00081      * convert offsets to instruction handles.
00082      */
00083     for(int i=0; i < count; i++) {
00084       if(ihs[i] instanceof BranchHandle) {
00085     BranchInstruction bi = (BranchInstruction)ihs[i].instruction;
00086     int target = bi.position + bi.getIndex(); /* Byte code position:
00087                            * relative -> absolute. */
00088     // Search for target position
00089     InstructionHandle ih = findHandle(ihs, pos, count, target);
00090 
00091     if(ih == null) // Search failed
00092       throw new ClassGenException("Couldn't find target for branch: " + bi);
00093     
00094     bi.setTarget(ih); // Update target
00095     
00096     // If it is a Select instruction, update all branch targets
00097     if(bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
00098           Select s       = (Select)bi;
00099           int[]  indices = s.getIndices();
00100       
00101       for(int j=0; j < indices.length; j++) {
00102         target = bi.position + indices[j];
00103         ih     = findHandle(ihs, pos, count, target);
00104         
00105         if(ih == null) // Search failed
00106           throw new ClassGenException("Couldn't find target for switch: " + bi);
00107 
00108         s.setTarget(j, ih); // Update target      
00109       }
00110     }
00111       }
00112     }
00113   }  
00114   /**
00115    * Create instruction list containing one instruction.
00116    * @param i initial instruction
00117    */
00118   public InstructionList(BranchInstruction i) {
00119     append(i);
00120   }  
00121   /**
00122    * Initialize list with (nonnull) compound instruction. Consumes argument
00123    * list, i.e., it becomes empty.
00124    *
00125    * @param c compound instruction (list)
00126    */
00127   public InstructionList(CompoundInstruction c) {
00128     append(c.getInstructionList());
00129   }  
00130   /**
00131    * Create instruction list containing one instruction.
00132    * @param i initial instruction
00133    */
00134   public InstructionList(Instruction i) {
00135     append(i);
00136   }  
00137   /** Add observer for this object.
00138    */
00139   public void addObserver(InstructionListObserver o) {
00140     if(observers == null)
00141       observers = new Vector();
00142 
00143     observers.add(o);
00144   }  
00145   /**
00146    * Append a branch instruction to the end of this list.
00147    *
00148    * @param i branch instruction to append
00149    * @return branch instruction handle of the appended instruction
00150    */
00151   public BranchHandle append(BranchInstruction i) {
00152     BranchHandle ih = BranchHandle.getBranchHandle(i);
00153     append(ih);
00154 
00155     return ih;
00156   }  
00157   /**
00158    * Append a compound instruction.
00159    *
00160    * @param c The composite instruction (containing an InstructionList)
00161    * @return instruction handle of the first appended instruction
00162    */
00163   public InstructionHandle append(CompoundInstruction c) {
00164     return append(c.getInstructionList()); 
00165   }  
00166   /**
00167    * Append an instruction to the end of this list.
00168    *
00169    * @param i instruction to append
00170    * @return instruction handle of the appended instruction
00171    */
00172   public InstructionHandle append(Instruction i) {
00173     InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
00174     append(ih);
00175 
00176     return ih;
00177   }  
00178   /**
00179    * Append a compound instruction, after instruction i.
00180    *
00181    * @param i Instruction in list
00182    * @param c The composite instruction (containing an InstructionList)
00183    * @return instruction handle of the first appended instruction
00184    */
00185   public InstructionHandle append(Instruction i, CompoundInstruction c) { 
00186     return append(i, c.getInstructionList()); 
00187   }  
00188   /**
00189    * Append a single instruction j after another instruction i, which
00190    * must be in this list of course!
00191    *
00192    * @param i Instruction in list
00193    * @param j Instruction to append after i in list
00194    * @return instruction handle of the first appended instruction
00195    */
00196   public InstructionHandle append(Instruction i, Instruction j) {
00197     return append(i, new InstructionList(j)); 
00198   }  
00199   /**
00200    * Append another list after instruction i contained in this list.
00201    * Consumes argument list, i.e., it becomes empty.
00202    *
00203    * @param i  where to append the instruction list 
00204    * @param il Instruction list to append to this one
00205    * @return instruction handle pointing to the <B>first</B> appended instruction
00206    */
00207   public InstructionHandle append(Instruction i, InstructionList il) {
00208     InstructionHandle ih;
00209 
00210     if((ih = findInstruction2(i)) == null) // Also applies for empty list
00211       throw new ClassGenException("Instruction " + i +
00212                   " is not contained in this list.");
00213 
00214     return append(ih, il);
00215   }  
00216   /**
00217    * Append an instruction to the end of this list.
00218    *
00219    * @param ih instruction to append
00220    */
00221   private void append(InstructionHandle ih) {
00222     if(isEmpty()) {
00223       start = end = ih;
00224       ih.next = ih.prev = null;
00225     }
00226     else {
00227       end.next = ih;
00228       ih.prev  = end;
00229       ih.next  = null;
00230       end      = ih;
00231     }
00232     
00233     length++; // Update length
00234   }  
00235   /**
00236    * Append an instruction after instruction (handle) ih contained in this list.
00237    *
00238    * @param ih where to append the instruction list 
00239    * @param i Instruction to append
00240    * @return instruction handle pointing to the <B>first</B> appended instruction
00241    */
00242   public BranchHandle append(InstructionHandle ih, BranchInstruction i) {
00243     BranchHandle    bh = BranchHandle.getBranchHandle(i);
00244     InstructionList il = new InstructionList();
00245     il.append(bh);
00246 
00247     append(ih, il);
00248 
00249     return bh;
00250   }  
00251   /**
00252    * Append a compound instruction.
00253    *
00254    * @param ih where to append the instruction list 
00255    * @param c The composite instruction (containing an InstructionList)
00256    * @return instruction handle of the first appended instruction
00257    */
00258   public InstructionHandle append(InstructionHandle ih, CompoundInstruction c) {
00259     return append(ih, c.getInstructionList()); 
00260   }  
00261   /**
00262    * Append an instruction after instruction (handle) ih contained in this list.
00263    *
00264    * @param ih where to append the instruction list 
00265    * @param i Instruction to append
00266    * @return instruction handle pointing to the <B>first</B> appended instruction
00267    */
00268   public InstructionHandle append(InstructionHandle ih, Instruction i) {
00269     return append(ih, new InstructionList(i));
00270   }  
00271   /**
00272    * Append another list after instruction (handle) ih contained in this list.
00273    * Consumes argument list, i.e., it becomes empty.
00274    *
00275    * @param ih where to append the instruction list 
00276    * @param il Instruction list to append to this one
00277    * @return instruction handle pointing to the <B>first</B> appended instruction
00278    */
00279   public InstructionHandle append(InstructionHandle ih, InstructionList il) {
00280     if(il == null)
00281       throw new ClassGenException("Appending null InstructionList");
00282 
00283     if(il.isEmpty()) // Nothing to do
00284       return ih;
00285 
00286     InstructionHandle next = ih.next, ret = il.start;
00287 
00288     ih.next = il.start;
00289     il.start.prev = ih;
00290 
00291     il.end.next = next;
00292 
00293     if(next != null) // i == end ?
00294       next.prev = il.end;
00295     else
00296       end = il.end; // Update end ...
00297 
00298     length += il.length; // Update length
00299 
00300     il.clear();
00301 
00302     return ret;
00303   }  
00304   /**
00305    * Append another list to this one.
00306    * Consumes argument list, i.e., it becomes empty.
00307    *
00308    * @param il list to append to end of this list
00309    * @return instruction handle of the <B>first</B> appended instruction
00310    */
00311   public InstructionHandle append(InstructionList il) {
00312     if(il == null)
00313       throw new ClassGenException("Appending null InstructionList");
00314 
00315     if(il.isEmpty()) // Nothing to do
00316       return null;
00317 
00318     if(isEmpty()) {
00319       start  = il.start;
00320       end    = il.end;
00321       length = il.length;
00322 
00323       il.clear();
00324 
00325       return start;
00326     } else
00327       return append(end, il);  // was end.instruction
00328   }  
00329   private void clear() {
00330     start = end = null;
00331     length = 0;
00332   }  
00333   public boolean contains(Instruction i) {
00334     return findInstruction1(i) != null;
00335   }  
00336   public boolean contains(InstructionHandle i) {
00337     if(i == null)
00338       return false;
00339 
00340     for(InstructionHandle ih=start; ih != null; ih = ih.next)
00341       if(ih == i)
00342     return true;
00343 
00344     return false;
00345   }  
00346   /**
00347    * @return complete, i.e., deep copy of this list
00348    */
00349   public InstructionList copy() {
00350     Hashtable       map = new Hashtable();
00351     InstructionList il  = new InstructionList();
00352 
00353     /* Pass 1: Make copies of all instructions, append them to the new list
00354      * and associate old instruction references with the new ones, i.e.,
00355      * a 1:1 mapping.
00356      */
00357     for(InstructionHandle ih=start; ih != null; ih = ih.next) {
00358       Instruction i = ih.instruction;
00359       Instruction c = i.copy(); // Use clone for shallow copy
00360 
00361       map.put(ih, il.append(c));
00362     }
00363     
00364     /* Pass 2: Update branch targets.
00365      */
00366     InstructionHandle ih=start;
00367     InstructionHandle ch=il.start;
00368 
00369     while(ih != null) {
00370       Instruction i = ih.instruction;
00371       Instruction c = ch.instruction;
00372 
00373       if(i instanceof BranchInstruction) {
00374     BranchInstruction bi      = (BranchInstruction)i;
00375     BranchInstruction bc      = (BranchInstruction)c;
00376     InstructionHandle itarget = bi.getTarget(); // old target
00377 
00378     // New target is in hash map
00379     bc.setTarget((InstructionHandle)map.get(itarget));
00380 
00381     if(bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
00382       InstructionHandle[] itargets = ((Select)bi).getTargets();
00383       InstructionHandle[] ctargets = ((Select)bc).getTargets();
00384       
00385       for(int j=0; j < itargets.length; j++) { // Update all targets
00386         ctargets[j] = (InstructionHandle)map.get(itargets[j]);
00387       }
00388     }
00389       }
00390 
00391       ih = ih.next;
00392       ch = ch.next;
00393     }
00394 
00395     return il;
00396   }  
00397   /**
00398    * Remove instruction from this list. The corresponding Instruction
00399    * handles must not be reused!
00400    *
00401    * @param i instruction to remove
00402    */
00403   public void delete(Instruction i) throws TargetLostException {
00404     InstructionHandle ih;
00405 
00406     if((ih = findInstruction1(i)) == null)
00407       throw new ClassGenException("Instruction " + i +
00408                   " is not contained in this list.");
00409     delete(ih);
00410   }  
00411   /**
00412    * Remove instructions from instruction `from' to instruction `to' contained
00413    * in this list. The user must ensure that `from' is an instruction before
00414    * `to', or risk havoc. The corresponding Instruction handles must not be reused!
00415    *
00416    * @param from where to start deleting (inclusive)
00417    * @param to   where to end deleting (inclusive)
00418    */
00419   public void delete(Instruction from, Instruction to) throws TargetLostException {
00420     InstructionHandle from_ih, to_ih;
00421 
00422     if((from_ih = findInstruction1(from)) == null)
00423       throw new ClassGenException("Instruction " + from +
00424                   " is not contained in this list.");
00425 
00426     if((to_ih = findInstruction2(to)) == null)
00427       throw new ClassGenException("Instruction " + to +
00428                   " is not contained in this list.");
00429     delete(from_ih, to_ih);
00430   }  
00431   /**
00432    * Remove instruction from this list. The corresponding Instruction
00433    * handles must not be reused!
00434    *
00435    * @param ih instruction (handle) to remove 
00436    */
00437   public void delete(InstructionHandle ih) throws TargetLostException {
00438     remove(ih.prev, ih.next);
00439   }  
00440   /**
00441    * Remove instructions from instruction `from' to instruction `to' contained
00442    * in this list. The user must ensure that `from' is an instruction before
00443    * `to', or risk havoc. The corresponding Instruction handles must not be reused!
00444    *
00445    * @param from where to start deleting (inclusive)
00446    * @param to   where to end deleting (inclusive)
00447    */
00448   public void delete(InstructionHandle from, InstructionHandle to)
00449     throws TargetLostException
00450   {
00451     remove(from.prev, to.next);
00452   }  
00453   /**
00454    * Delete contents of list. Provides besser memory utilization,
00455    * because the system then may reuse the instruction handles. This
00456    * method is typically called right after
00457    * <href="MethodGen.html#getMethod()">MethodGen.getMethod()</a>.
00458    */
00459   public void dispose() {
00460     // Traverse in reverse order, because ih.next is overwritten
00461     for(InstructionHandle ih=end; ih != null; ih = ih.prev)
00462       /* Causes BranchInstructions to release target and targeters, because it
00463        * calls dispose() on the contained instruction.
00464        */
00465       ih.dispose();
00466 
00467     clear();
00468   }  
00469   /**
00470    * @return Enumeration that lists all instructions (handles)
00471    */
00472   public Enumeration elements() {
00473     return new Enumeration() {
00474       private InstructionHandle ih = start;
00475 
00476       public Object nextElement() {
00477     InstructionHandle i = ih;
00478     ih = ih.next;
00479     return i;
00480       }
00481 
00482       public boolean hasMoreElements() { return ih != null; }
00483     };
00484   }  
00485   /**
00486    * Find the target instruction (handle) that corresponds to the given target
00487    * position (byte code offset).
00488    *
00489    * @param ihs array of instruction handles, i.e. il.getInstructionHandles()
00490    * @param pos array of positions corresponding to ihs, i.e. il.getInstructionPositions()
00491    * @param count length of arrays
00492    * @param target target position to search for
00493    * @return target position's instruction handle if available
00494    */
00495   public static InstructionHandle findHandle(InstructionHandle[] ihs,
00496                          int[] pos, int count,
00497                          int target) {
00498     int l=0, r = count - 1;
00499     
00500     /* Do a binary search since the pos array is orderd.
00501      */
00502     do {
00503       int i = (l + r) / 2;
00504       int j = pos[i];
00505 
00506       if(j == target) // target found
00507     return ihs[i];
00508       else if(target < j) // else constrain search area
00509     r = i - 1;
00510       else // target > j
00511     l = i + 1;
00512     } while(l <= r);
00513 
00514     return null;
00515   }  
00516   /**
00517    * Get instruction handle for instruction at byte code position pos.
00518    * This only works properly, if the list is freshly initialized from a byte array or
00519    * setPositions() has been called before this method.
00520    *
00521    * @param pos byte code position to search for
00522    * @return target position's instruction handle if available
00523    */
00524   public InstructionHandle findHandle(int pos) {
00525     InstructionHandle[] ihs = getInstructionHandles();
00526     return findHandle(ihs, byte_positions, length, pos);
00527   }  
00528   /**
00529    * Search for given Instruction reference, start at beginning of list.
00530    *
00531    * @param i instruction to search for
00532    * @return instruction found on success, null otherwise
00533    */
00534   private InstructionHandle findInstruction1(Instruction i) {
00535     for(InstructionHandle ih=start; ih != null; ih = ih.next)
00536       if(ih.instruction == i)
00537     return ih;
00538 
00539     return null;
00540   }  
00541   /**
00542    * Search for given Instruction reference, start at end of list
00543    *
00544    * @param i instruction to search for
00545    * @return instruction found on success, null otherwise
00546    */
00547   private InstructionHandle findInstruction2(Instruction i) {
00548     for(InstructionHandle ih=end; ih != null; ih = ih.prev)
00549       if(ih.instruction == i)
00550     return ih;
00551 
00552     return null;
00553   }  
00554   /**
00555    * When everything is finished, use this method to convert the instruction
00556    * list into an array of bytes.
00557    *
00558    * @return the byte code ready to be dumped
00559    */
00560   public byte[] getByteCode() {
00561     // Update position indices of instructions
00562     setPositions();
00563 
00564     ByteArrayOutputStream b   = new ByteArrayOutputStream();
00565     DataOutputStream      out = new DataOutputStream(b);
00566 
00567     try {
00568       for(InstructionHandle ih=start; ih != null; ih = ih.next) {
00569     Instruction i = ih.instruction;
00570     i.dump(out); // Traverse list
00571       }
00572     } catch(IOException e) { 
00573       System.err.println(e);
00574       return null;
00575     }
00576 
00577     return b.toByteArray();
00578   }  
00579   /**
00580    * @return end of list
00581    */
00582   public InstructionHandle getEnd()   { return end; }  
00583   /**
00584    * @return array containing all instructions (handles)
00585    */
00586   public InstructionHandle[] getInstructionHandles() {
00587     InstructionHandle[] ihs = new InstructionHandle[length];
00588     InstructionHandle   ih  = start;
00589 
00590     for(int i=0; i < length; i++) {
00591       ihs[i] = ih;
00592       ih = ih.next;
00593     }
00594 
00595     return ihs;
00596   }  
00597   /**
00598    * Get positions (offsets) of all instructions in the list. This relies on that
00599    * the list has been freshly created from an byte code array, or that setPositions()
00600    * has been called. Otherwise this may be inaccurate.
00601    *
00602    * @return array containing all instruction's offset in byte code
00603    */
00604   public int[] getInstructionPositions() { return byte_positions; }  
00605   /**
00606    * @return an array of instructions without target information for branch instructions.
00607    */
00608   public Instruction[] getInstructions() {
00609     ByteSequence  bytes        = new ByteSequence(getByteCode());
00610     Vector        instructions = new Vector();
00611 
00612     try {
00613       while(bytes.available() > 0) {
00614     instructions.addElement(Instruction.readInstruction(bytes));
00615       }
00616     } catch(IOException e) { throw new ClassGenException(e.toString()); }
00617     Instruction[] result = new Instruction[instructions.size()];
00618     instructions.copyInto(result);
00619     return result;
00620   }  
00621   /**
00622    * @return length of list (Number of instructions, not bytes)
00623    */
00624   public int getLength() { return length; }  
00625   /**
00626    * @return start of list
00627    */
00628   public InstructionHandle getStart() { return start; }  
00629   /**
00630    * Insert a branch instruction at start of this list.
00631    *
00632    * @param i branch instruction to insert
00633    * @return branch instruction handle of the appended instruction
00634    */
00635   public BranchHandle insert(BranchInstruction i) {
00636     BranchHandle ih = BranchHandle.getBranchHandle(i);
00637     insert(ih);
00638     return ih;
00639   }  
00640   /**
00641    * Insert a compound instruction.
00642    *
00643    * @param c The composite instruction (containing an InstructionList)
00644    * @return instruction handle of the first inserted instruction
00645    */
00646   public InstructionHandle insert(CompoundInstruction c) {
00647     return insert(c.getInstructionList()); 
00648   }  
00649   /**
00650    * Insert an instruction at start of this list.
00651    *
00652    * @param i instruction to insert
00653    * @return instruction handle of the inserted instruction
00654    */
00655   public InstructionHandle insert(Instruction i) {
00656     InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
00657     insert(ih);
00658 
00659     return ih;
00660   }  
00661   /**
00662    * Insert a compound instruction before instruction i.
00663    *
00664    * @param i Instruction in list
00665    * @param c The composite instruction (containing an InstructionList)
00666    * @return instruction handle of the first inserted instruction
00667    */
00668   public InstructionHandle insert(Instruction i, CompoundInstruction c) { 
00669     return insert(i, c.getInstructionList()); 
00670   }  
00671   /**
00672    * Insert a single instruction j before another instruction i, which
00673    * must be in this list of course!
00674    *
00675    * @param i Instruction in list
00676    * @param j Instruction to insert before i in list
00677    * @return instruction handle of the first inserted instruction
00678    */
00679   public InstructionHandle insert(Instruction i, Instruction j) {
00680     return insert(i, new InstructionList(j));
00681   }  
00682   /**
00683    * Insert another list before Instruction i contained in this list.
00684    * Consumes argument list, i.e., it becomes empty.
00685    *
00686    * @param i  where to append the instruction list 
00687    * @param il Instruction list to insert
00688    * @return instruction handle pointing to the first inserted instruction,
00689    * i.e., il.getStart()
00690    */
00691   public InstructionHandle insert(Instruction i, InstructionList il) {
00692     InstructionHandle ih;
00693 
00694     if((ih = findInstruction1(i)) == null)
00695       throw new ClassGenException("Instruction " + i +
00696                   " is not contained in this list.");
00697     
00698     return insert(ih, il);
00699   }  
00700   /**
00701    * Insert an instruction at start of this list.
00702    *
00703    * @param ih instruction to insert
00704    */
00705   private void insert(InstructionHandle ih) {
00706     if(isEmpty()) {
00707       start = end = ih;
00708       ih.next = ih.prev = null;
00709     } else {
00710       start.prev = ih;
00711       ih.next    = start;
00712       ih.prev    = null;
00713       start      = ih;
00714     }
00715 
00716     length++;
00717   }  
00718   /**
00719    * Insert an instruction before instruction (handle) ih contained in this list.
00720    *
00721    * @param ih where to insert to the instruction list 
00722    * @param i Instruction to insert
00723    * @return instruction handle of the first inserted instruction
00724    */
00725   public BranchHandle insert(InstructionHandle ih, BranchInstruction i) {
00726     BranchHandle    bh = BranchHandle.getBranchHandle(i);
00727     InstructionList il = new InstructionList();
00728     il.append(bh);
00729 
00730     insert(ih, il);
00731 
00732     return bh;
00733   }  
00734   /**
00735    * Insert a compound instruction.
00736    *
00737    * @param ih where to insert the instruction list 
00738    * @param c The composite instruction (containing an InstructionList)
00739    * @return instruction handle of the first inserted instruction
00740    */
00741   public InstructionHandle insert(InstructionHandle ih, CompoundInstruction c) {
00742     return insert(ih, c.getInstructionList()); 
00743   }  
00744   /**
00745    * Insert an instruction before instruction (handle) ih contained in this list.
00746    *
00747    * @param ih where to insert to the instruction list 
00748    * @param i Instruction to insert
00749    * @return instruction handle of the first inserted instruction
00750    */
00751   public InstructionHandle insert(InstructionHandle ih, Instruction i) {
00752     return insert(ih, new InstructionList(i));
00753   }  
00754   /**
00755    * Insert another list before Instruction handle ih contained in this list.
00756    * Consumes argument list, i.e., it becomes empty.
00757    *
00758    * @param i  where to append the instruction list 
00759    * @param il Instruction list to insert
00760    * @return instruction handle of the first inserted instruction
00761    */
00762   public InstructionHandle insert(InstructionHandle ih, InstructionList il) {
00763     if(il == null)
00764       throw new ClassGenException("Inserting null InstructionList");
00765 
00766     if(il.isEmpty()) // Nothing to do
00767       return ih;
00768 
00769     InstructionHandle prev = ih.prev, ret = il.start;
00770 
00771     ih.prev = il.end;
00772     il.end.next = ih;
00773 
00774     il.start.prev = prev;
00775 
00776     if(prev != null) // ih == start ?
00777       prev.next = il.start;
00778     else
00779       start = il.start; // Update start ...
00780 
00781     length += il.length; // Update length
00782 
00783     il.clear();
00784 
00785     return ret;
00786   }  
00787   /**
00788    * Insert another list.   
00789    *
00790    * @param il list to insert before start of this list
00791    * @return instruction handle of the first inserted instruction
00792    */
00793   public InstructionHandle insert(InstructionList il) {
00794     if(isEmpty()) {
00795       append(il); // Code is identical for this case
00796       return start;
00797     }
00798     else
00799       return insert(start, il); 
00800   }  
00801   /**
00802    * Test for empty list.
00803    */
00804   public boolean isEmpty() { return start == null; } // && end == null  
00805   /**
00806    * Move a single instruction (handle) to a new location.
00807    *
00808    * @param ih     moved instruction
00809    * @param target new location of moved instruction
00810    */
00811   public void move(InstructionHandle ih, InstructionHandle target) {
00812     move(ih, ih, target);
00813   }  
00814   /**
00815    * Take all instructions (handles) from "start" to "end" and append them after the
00816    * new location "target". Of course, "end" must be after "start" and target must
00817    * not be located withing this range. If you want to move something to the start of
00818    * the list use null as value for target.<br>
00819    * Any instruction targeters pointing to handles within the block, keep their targets.
00820    *
00821    * @param start  of moved block
00822    * @param end    of moved block
00823    * @param target of moved block
00824    */
00825   public void move(InstructionHandle start, InstructionHandle end, InstructionHandle target) {
00826     // Step 1: Check constraints
00827 
00828     if((start == null) || (end == null))
00829       throw new ClassGenException("Invalid null handle: From " + start + " to " + end);
00830 
00831     if((target == start) || (target == end))
00832       throw new ClassGenException("Invalid range: From " + start + " to " + end +
00833                   " contains target " + target);
00834 
00835     for(InstructionHandle ih = start; ih != end.next; ih = ih.next) {
00836       if(ih == null) // At end of list, end not found yet
00837     throw new ClassGenException("Invalid range: From " + start + " to " + end);
00838       else if(ih == target) // target may be null
00839     throw new ClassGenException("Invalid range: From " + start + " to " + end +
00840                     " contains target " + target);
00841     }
00842 
00843     // Step 2: Temporarily remove the given instructions from the list
00844 
00845     InstructionHandle prev = start.prev, next = end.next;
00846 
00847     if(prev != null)
00848       prev.next = next;
00849     else // start == this.start!
00850       this.start = next;
00851 
00852     if(next != null)
00853       next.prev = prev;
00854     else // end == this.end!
00855       this.end = prev;
00856 
00857     start.prev = end.next = null;
00858 
00859     // Step 3: append after target
00860 
00861     if(target == null) { // append to start of list
00862       end.next = this.start;
00863       this.start = start;
00864     } else {
00865       next = target.next;
00866 
00867       target.next = start;
00868       start.prev  = target;
00869       end.next    = next;
00870 
00871       if(next != null)
00872     next.prev = end;
00873     }
00874   }  
00875   /**
00876    * Redirect all references from old_target to new_target, i.e., update targets 
00877    * of branch instructions.
00878    *
00879    * @param old_target the old target instruction handle
00880    * @param new_target the new target instruction handle
00881    */
00882   public void redirectBranches(InstructionHandle old_target, 
00883                    InstructionHandle new_target) {
00884     for(InstructionHandle ih = start; ih != null; ih = ih.next) {
00885       Instruction i  = ih.getInstruction();
00886 
00887       if(i instanceof BranchInstruction) {
00888     BranchInstruction b      = (BranchInstruction)i;
00889     InstructionHandle target = b.getTarget();
00890 
00891     if(target == old_target)
00892       b.setTarget(new_target);
00893 
00894     if(b instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
00895       InstructionHandle[] targets = ((Select)b).getTargets();
00896       
00897       for(int j=0; j < targets.length; j++) // Update targets
00898         if(targets[j] == old_target)
00899           ((Select)b).setTarget(j, new_target);
00900     }
00901       }
00902     }
00903   }  
00904   /**
00905    * Redirect all references of exception handlers from old_target to new_target.
00906    *
00907    * @@param exceptions array of exception handlers
00908    * @@param old_target the old target instruction handle
00909    * @@param new_target the new target instruction handle
00910    * @@see MethodGen
00911    */
00912   public void redirectExceptionHandlers(CodeExceptionGen[] exceptions,
00913                     InstructionHandle old_target, 
00914                     InstructionHandle new_target) {
00915     for(int i=0; i < exceptions.length; i++) {
00916       if(exceptions[i].getStartPC() == old_target)
00917     exceptions[i].setStartPC(new_target);
00918 
00919       if(exceptions[i].getEndPC() == old_target)
00920     exceptions[i].setEndPC(new_target);
00921 
00922       if(exceptions[i].getHandlerPC() == old_target)
00923     exceptions[i].setHandlerPC(new_target);
00924     }
00925   }  
00926   /**
00927    * Redirect all references of local variables from old_target to new_target.
00928    *
00929    * @@param lg array of local variables
00930    * @@param old_target the old target instruction handle
00931    * @@param new_target the new target instruction handle
00932    * @@see MethodGen
00933    */
00934   public void redirectLocalVariables(LocalVariableGen[] lg,
00935                      InstructionHandle old_target, 
00936                      InstructionHandle new_target) {
00937     for(int i=0; i < lg.length; i++) {
00938       InstructionHandle start = lg[i].getStart();
00939       InstructionHandle end   = lg[i].getEnd();
00940       
00941       if(start == old_target)
00942     lg[i].setStart(new_target);
00943 
00944       if(end == old_target)
00945     lg[i].setEnd(new_target);
00946     }
00947   }  
00948   /**
00949    * Remove from instruction `prev' to instruction `next' both contained
00950    * in this list. Throws TargetLostException when one of the removed instruction handles
00951    * is still being targeted.
00952    *
00953    * @param prev where to start deleting (predecessor, exclusive)
00954    * @param next where to end deleting (successor, exclusive)
00955    */
00956   private void remove(InstructionHandle prev, InstructionHandle next)
00957     throws TargetLostException
00958   {
00959     InstructionHandle first, last; // First and last deleted instruction
00960 
00961     if((prev == null) && (next == null)) { // singleton list
00962       first = last = start;
00963       start = end = null;
00964     } else {
00965       if(prev == null) { // At start of list
00966     first = start;
00967     start = next;
00968       } else {
00969     first     = prev.next;
00970     prev.next = next;
00971       }
00972       
00973       if(next == null) { // At end of list
00974     last = end;
00975     end  = prev;
00976       } else {
00977     last      = next.prev;
00978     next.prev = prev;
00979       }
00980     }
00981 
00982     first.prev = null; // Completely separated from rest of list
00983     last.next  = null;
00984 
00985     Vector target_vec = new Vector();
00986 
00987     for(InstructionHandle ih=first; ih != null; ih = ih.next)
00988       ih.getInstruction().dispose(); // e.g. BranchInstructions release their targets
00989 
00990     StringBuffer buf = new StringBuffer("{ ");
00991     for(InstructionHandle ih=first; ih != null; ih = next) {
00992       next = ih.next;
00993       length--;
00994     
00995       if(ih.hasTargeters()) { // Still got targeters?
00996     target_vec.addElement(ih);
00997     buf.append(ih.toString(true) + " ");
00998     ih.next = ih.prev = null;
00999       } else
01000     ih.dispose();
01001     }
01002 
01003     buf.append("}");
01004 
01005     if(!target_vec.isEmpty()) {
01006       InstructionHandle[] targeted = new InstructionHandle[target_vec.size()];
01007       target_vec.copyInto(targeted);
01008       throw new TargetLostException(targeted, buf.toString());
01009     }
01010   }  
01011   /** Remove observer for this object.
01012    */
01013   public void removeObserver(InstructionListObserver o) {
01014     if(observers != null)
01015       observers.removeElement(o);
01016   }  
01017   public void setPositions() {
01018     setPositions(false);
01019   }  
01020   /**
01021    * Give all instructions their position number (offset in byte stream), i.e.,
01022    * make the list ready to be dumped.
01023    *
01024    * @param check Perform sanity checks, e.g. if all targeted instructions really belong
01025    * to this list
01026    */
01027   public void setPositions(boolean check) {
01028     int max_additional_bytes = 0, additional_bytes = 0;
01029     int index = 0, count = 0;
01030     int[] pos = new int[length];
01031 
01032     /* Pass 0: Sanity checks
01033      */
01034     if(check) {
01035       for(InstructionHandle ih=start; ih != null; ih = ih.next) {
01036     Instruction i = ih.instruction;
01037 
01038     if(i instanceof BranchInstruction) { // target instruction within list?
01039       Instruction inst = ((BranchInstruction)i).getTarget().instruction;
01040       if(!contains(inst))
01041         throw new ClassGenException("Branch target of " +
01042                     Constants.OPCODE_NAMES[i.tag] + ":" +
01043                     inst + " not in instruction list");
01044 
01045       if(i instanceof Select) {
01046         InstructionHandle[] targets = ((Select)i).getTargets();
01047         
01048         for(int j=0; j < targets.length; j++) {
01049           inst = targets[j].instruction;
01050           if(!contains(inst))
01051         throw new ClassGenException("Branch target of " +
01052                         Constants.OPCODE_NAMES[i.tag] + ":" +
01053                         inst + " not in instruction list");
01054         }
01055       }
01056 
01057       if(!(ih instanceof BranchHandle))
01058         throw new ClassGenException("Branch instruction " +
01059                     Constants.OPCODE_NAMES[i.tag] + ":" +
01060                     inst + " not contained in BranchHandle.");
01061 
01062     }
01063       }
01064     }
01065 
01066     /* Pass 1: Set position numbers and sum up the maximum number of bytes an
01067      * instruction may be shifted.
01068      */
01069     for(InstructionHandle ih=start; ih != null; ih = ih.next) {
01070       Instruction i = ih.instruction;
01071 
01072       ih.setPosition(index);
01073       pos[count++] = index;
01074 
01075       /* Get an estimate about how many additional bytes may be added, because
01076        * BranchInstructions may have variable length depending on the target
01077        * offset (short vs. int) or alignment issues (TABLESWITCH and
01078        * LOOKUPSWITCH).
01079        */
01080       switch(i.getTag()) {
01081       case Constants.JSR: case Constants.GOTO:
01082     max_additional_bytes += 2;
01083     break;
01084 
01085       case Constants.TABLESWITCH: case Constants.LOOKUPSWITCH:
01086     max_additional_bytes += 3;
01087     break;
01088       }
01089 
01090       index += i.getLength();
01091     }
01092     
01093     /* Pass 2: Expand the variable-length (Branch)Instructions depending on
01094      * the target offset (short or int) and ensure that branch targets are
01095      * within this list.
01096      */
01097     for(InstructionHandle ih=start; ih != null; ih = ih.next)
01098       additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes);
01099 
01100     /* Pass 3: Update position numbers (which may have changed due to the
01101      * preceding expansions), like pass 1.
01102      */
01103     index=count=0;
01104     for(InstructionHandle ih=start; ih != null; ih = ih.next) {
01105       Instruction i = ih.instruction;
01106 
01107       ih.setPosition(index);
01108       pos[count++] = index;
01109       index += i.getLength();
01110     }
01111 
01112     byte_positions = new int[count]; // Trim to proper size
01113     System.arraycopy(pos, 0, byte_positions, 0, count);
01114   }  
01115   /**
01116    * @return length of list (Number of instructions, not bytes)
01117    */
01118   public int size() { return length; }  
01119   public String toString() {
01120     return toString(true);
01121   }  
01122   /**
01123    * @param verbose toggle output format
01124    * @return String containing all instructions in this list.
01125    */ 
01126   public String toString(boolean verbose) {
01127     StringBuffer buf = new StringBuffer();
01128 
01129     for(InstructionHandle ih=start; ih != null; ih = ih.next) {
01130       buf.append(ih.toString(verbose) + "\n");
01131     }
01132 
01133     return buf.toString();
01134   }  
01135   /** Call notify() method on all observers. This method is not called
01136    * automatically whenever the state has changed, but has to be
01137    * called by the user after he has finished editing the object.
01138    */
01139   public void update() {
01140     if(observers != null)
01141       for(Enumeration e = observers.elements(); e.hasMoreElements(); )
01142     ((InstructionListObserver)e.nextElement()).notify(this);
01143   }  
01144 }

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