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

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