FileDocCategorySizeDatePackage
InstructionList.javaAPI DocJava SE 6 API38634Tue Jun 10 00:22:20 BST 2008com.sun.org.apache.bcel.internal.generic

InstructionList

public class InstructionList extends Object implements Serializable
This class is a container for a list of Instruction objects. Instructions can be appended, inserted, moved, deleted, etc.. Instructions are being wrapped into InstructionHandles objects that are returned upon append/insert operations. They give the user (read only) access to the list structure, such that it can be traversed and manipulated in a controlled way. A list is finally dumped to a byte code array with getByteCode.
version
$Id: InstructionList.java,v 1.1.2.1 2005/07/31 23:45:45 jeffsuttor Exp $
author
M. Dahm
see
Instruction
see
InstructionHandle
see
BranchHandle

Fields Summary
private InstructionHandle
start
private InstructionHandle
end
private int
length
private int[]
byte_positions
private ArrayList
observers
Constructors Summary
public InstructionList()
Create (empty) instruction list.

 // byte code offsets corresponding to instructions

         
    
public InstructionList(Instruction i)
Create instruction list containing one instruction.

param
i initial instruction

    append(i);
  
public InstructionList(BranchInstruction i)
Create instruction list containing one instruction.

param
i initial instruction

    append(i);
  
public InstructionList(CompoundInstruction c)
Initialize list with (nonnull) compound instruction. Consumes argument list, i.e., it becomes empty.

param
c compound instruction (list)

    append(c.getInstructionList());
  
public InstructionList(byte[] code)
Initialize instruction list from byte array.

param
code byte array containing the instructions

    ByteSequence        bytes = new ByteSequence(code);
    InstructionHandle[] ihs   = new InstructionHandle[code.length];
    int[]               pos   = new int[code.length]; // Can't be more than that
    int                 count = 0; // Contains actual length

    /* Pass 1: Create an object for each byte code and append them
     * to the list.
     */
    try {
      while(bytes.available() > 0) {
	// Remember byte offset and associate it with the instruction
	int off =  bytes.getIndex();
	pos[count] = off;
	
	/* Read one instruction from the byte stream, the byte position is set
	 * accordingly.
	 */
	Instruction       i = Instruction.readInstruction(bytes);
	InstructionHandle ih;
	if(i instanceof BranchInstruction) // Use proper append() method
	  ih = append((BranchInstruction)i);
	else
	  ih = append(i);

	ih.setPosition(off);
	ihs[count] = ih;
	
	count++;
      }
    } catch(IOException e) { throw new ClassGenException(e.toString()); }

    byte_positions = new int[count]; // Trim to proper size
    System.arraycopy(pos, 0, byte_positions, 0, count);

    /* Pass 2: Look for BranchInstruction and update their targets, i.e.,
     * convert offsets to instruction handles.
     */
    for(int i=0; i < count; i++) {
      if(ihs[i] instanceof BranchHandle) {
	BranchInstruction bi = (BranchInstruction)ihs[i].instruction;
	int target = bi.position + bi.getIndex(); /* Byte code position:
						   * relative -> absolute. */
	// Search for target position
	InstructionHandle ih = findHandle(ihs, pos, count, target);

	if(ih == null) // Search failed
	  throw new ClassGenException("Couldn't find target for branch: " + bi);
	
	bi.setTarget(ih); // Update target
	
	// If it is a Select instruction, update all branch targets
	if(bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
          Select s       = (Select)bi;
          int[]  indices = s.getIndices();
	  
	  for(int j=0; j < indices.length; j++) {
	    target = bi.position + indices[j];
	    ih     = findHandle(ihs, pos, count, target);
	    
	    if(ih == null) // Search failed
	      throw new ClassGenException("Couldn't find target for switch: " + bi);

	    s.setTarget(j, ih); // Update target      
	  }
	}
      }
    }
  
Methods Summary
public voidaddObserver(com.sun.org.apache.bcel.internal.generic.InstructionListObserver o)
Add observer for this object.

    if(observers == null)
      observers = new ArrayList();

    observers.add(o);
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.Instruction i, com.sun.org.apache.bcel.internal.generic.InstructionList il)
Append another list after instruction i contained in this list. Consumes argument list, i.e., it becomes empty.

param
i where to append the instruction list
param
il Instruction list to append to this one
return
instruction handle pointing to the first appended instruction

    InstructionHandle ih;

    if((ih = findInstruction2(i)) == null) // Also applies for empty list
      throw new ClassGenException("Instruction " + i +
				  " is not contained in this list.");

    return append(ih, il);
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.InstructionList il)
Append another list to this one. Consumes argument list, i.e., it becomes empty.

param
il list to append to end of this list
return
instruction handle of the first appended instruction

    if(il == null)
      throw new ClassGenException("Appending null InstructionList");

    if(il.isEmpty()) // Nothing to do
      return null;

    if(isEmpty()) {
      start  = il.start;
      end    = il.end;
      length = il.length;

      il.clear();

      return start;
    } else
      return append(end, il);  // was end.instruction
  
private voidappend(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih)
Append an instruction to the end of this list.

param
ih instruction to append

    if(isEmpty()) {
      start = end = ih;
      ih.next = ih.prev = null;
    }
    else {
      end.next = ih;
      ih.prev  = end;
      ih.next  = null;
      end      = ih;
    }
    
    length++; // Update length
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.Instruction i)
Append an instruction to the end of this list.

param
i instruction to append
return
instruction handle of the appended instruction

    InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
    append(ih);

    return ih;
  
public com.sun.org.apache.bcel.internal.generic.BranchHandleappend(com.sun.org.apache.bcel.internal.generic.BranchInstruction i)
Append a branch instruction to the end of this list.

param
i branch instruction to append
return
branch instruction handle of the appended instruction

    BranchHandle ih = BranchHandle.getBranchHandle(i);
    append(ih);

    return ih;
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.Instruction i, com.sun.org.apache.bcel.internal.generic.Instruction j)
Append a single instruction j after another instruction i, which must be in this list of course!

param
i Instruction in list
param
j Instruction to append after i in list
return
instruction handle of the first appended instruction

    return append(i, new InstructionList(j)); 
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.Instruction i, com.sun.org.apache.bcel.internal.generic.CompoundInstruction c)
Append a compound instruction, after instruction i.

param
i Instruction in list
param
c The composite instruction (containing an InstructionList)
return
instruction handle of the first appended instruction

 
    return append(i, c.getInstructionList()); 
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.CompoundInstruction c)
Append a compound instruction.

param
c The composite instruction (containing an InstructionList)
return
instruction handle of the first appended instruction

    return append(c.getInstructionList()); 
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.CompoundInstruction c)
Append a compound instruction.

param
ih where to append the instruction list
param
c The composite instruction (containing an InstructionList)
return
instruction handle of the first appended instruction

    return append(ih, c.getInstructionList()); 
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.Instruction i)
Append an instruction after instruction (handle) ih contained in this list.

param
ih where to append the instruction list
param
i Instruction to append
return
instruction handle pointing to the first appended instruction

    return append(ih, new InstructionList(i));
  
public com.sun.org.apache.bcel.internal.generic.BranchHandleappend(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.BranchInstruction i)
Append an instruction after instruction (handle) ih contained in this list.

param
ih where to append the instruction list
param
i Instruction to append
return
instruction handle pointing to the first appended instruction

    BranchHandle    bh = BranchHandle.getBranchHandle(i);
    InstructionList il = new InstructionList();
    il.append(bh);

    append(ih, il);

    return bh;
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleappend(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.InstructionList il)
Append another list after instruction (handle) ih contained in this list. Consumes argument list, i.e., it becomes empty.

param
ih where to append the instruction list
param
il Instruction list to append to this one
return
instruction handle pointing to the first appended instruction

    if(il == null)
      throw new ClassGenException("Appending null InstructionList");

    if(il.isEmpty()) // Nothing to do
      return ih;

    InstructionHandle next = ih.next, ret = il.start;

    ih.next = il.start;
    il.start.prev = ih;

    il.end.next = next;

    if(next != null) // i == end ?
      next.prev = il.end;
    else
      end = il.end; // Update end ...

    length += il.length; // Update length

    il.clear();

    return ret;
  
private voidclear()

    start = end = null;
    length = 0;
  
public booleancontains(com.sun.org.apache.bcel.internal.generic.InstructionHandle i)

    if(i == null)
      return false;

    for(InstructionHandle ih=start; ih != null; ih = ih.next)
      if(ih == i)
	return true;

    return false;
  
public booleancontains(com.sun.org.apache.bcel.internal.generic.Instruction i)

    return findInstruction1(i) != null;
  
public com.sun.org.apache.bcel.internal.generic.InstructionListcopy()

return
complete, i.e., deep copy of this list

    HashMap         map = new HashMap();
    InstructionList il  = new InstructionList();

    /* Pass 1: Make copies of all instructions, append them to the new list
     * and associate old instruction references with the new ones, i.e.,
     * a 1:1 mapping.
     */
    for(InstructionHandle ih=start; ih != null; ih = ih.next) {
      Instruction i = ih.instruction;
      Instruction c = i.copy(); // Use clone for shallow copy

      if(c instanceof BranchInstruction)
	map.put(ih, il.append((BranchInstruction)c));
      else
	map.put(ih, il.append(c));
    }
    
    /* Pass 2: Update branch targets.
     */
    InstructionHandle ih=start;
    InstructionHandle ch=il.start;

    while(ih != null) {
      Instruction i = ih.instruction;
      Instruction c = ch.instruction;

      if(i instanceof BranchInstruction) {
	BranchInstruction bi      = (BranchInstruction)i;
	BranchInstruction bc      = (BranchInstruction)c;
	InstructionHandle itarget = bi.getTarget(); // old target

	// New target is in hash map
	bc.setTarget((InstructionHandle)map.get(itarget));

	if(bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
	  InstructionHandle[] itargets = ((Select)bi).getTargets();
	  InstructionHandle[] ctargets = ((Select)bc).getTargets();
	  
	  for(int j=0; j < itargets.length; j++) { // Update all targets
	    ctargets[j] = (InstructionHandle)map.get(itargets[j]);
	  }
	}
      }

      ih = ih.next;
      ch = ch.next;
    }

    return il;
  
public voiddelete(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih)
Remove instruction from this list. The corresponding Instruction handles must not be reused!

param
ih instruction (handle) to remove

    remove(ih.prev, ih.next);
  
public voiddelete(com.sun.org.apache.bcel.internal.generic.Instruction i)
Remove instruction from this list. The corresponding Instruction handles must not be reused!

param
i instruction to remove

    InstructionHandle ih;

    if((ih = findInstruction1(i)) == null)
      throw new ClassGenException("Instruction " + i +
				  " is not contained in this list.");
    delete(ih);
  
public voiddelete(com.sun.org.apache.bcel.internal.generic.InstructionHandle from, com.sun.org.apache.bcel.internal.generic.InstructionHandle to)
Remove instructions from instruction `from' to instruction `to' contained in this list. The user must ensure that `from' is an instruction before `to', or risk havoc. The corresponding Instruction handles must not be reused!

param
from where to start deleting (inclusive)
param
to where to end deleting (inclusive)

    remove(from.prev, to.next);
  
public voiddelete(com.sun.org.apache.bcel.internal.generic.Instruction from, com.sun.org.apache.bcel.internal.generic.Instruction to)
Remove instructions from instruction `from' to instruction `to' contained in this list. The user must ensure that `from' is an instruction before `to', or risk havoc. The corresponding Instruction handles must not be reused!

param
from where to start deleting (inclusive)
param
to where to end deleting (inclusive)

    InstructionHandle from_ih, to_ih;

    if((from_ih = findInstruction1(from)) == null)
      throw new ClassGenException("Instruction " + from +
				  " is not contained in this list.");

    if((to_ih = findInstruction2(to)) == null)
      throw new ClassGenException("Instruction " + to +
				  " is not contained in this list.");
    delete(from_ih, to_ih);
  
public voiddispose()
Delete contents of list. Provides besser memory utilization, because the system then may reuse the instruction handles. This method is typically called right after MethodGen.getMethod().

    // Traverse in reverse order, because ih.next is overwritten
    for(InstructionHandle ih=end; ih != null; ih = ih.prev)
      /* Causes BranchInstructions to release target and targeters, because it
       * calls dispose() on the contained instruction.
       */
      ih.dispose();

    clear();
  
public static com.sun.org.apache.bcel.internal.generic.InstructionHandlefindHandle(com.sun.org.apache.bcel.internal.generic.InstructionHandle[] ihs, int[] pos, int count, int target)
Find the target instruction (handle) that corresponds to the given target position (byte code offset).

param
ihs array of instruction handles, i.e. il.getInstructionHandles()
param
pos array of positions corresponding to ihs, i.e. il.getInstructionPositions()
param
count length of arrays
param
target target position to search for
return
target position's instruction handle if available

    int l=0, r = count - 1;
    
    /* Do a binary search since the pos array is orderd.
     */
    do {
      int i = (l + r) / 2;
      int j = pos[i];

      if(j == target) // target found
 	return ihs[i];
      else if(target < j) // else constrain search area
	r = i - 1;
      else // target > j
	l = i + 1;
    } while(l <= r);

    return null;
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandlefindHandle(int pos)
Get instruction handle for instruction at byte code position pos. This only works properly, if the list is freshly initialized from a byte array or setPositions() has been called before this method.

param
pos byte code position to search for
return
target position's instruction handle if available

    InstructionHandle[] ihs = getInstructionHandles();
    return findHandle(ihs, byte_positions, length, pos);
  
private com.sun.org.apache.bcel.internal.generic.InstructionHandlefindInstruction1(com.sun.org.apache.bcel.internal.generic.Instruction i)
Search for given Instruction reference, start at beginning of list.

param
i instruction to search for
return
instruction found on success, null otherwise

    for(InstructionHandle ih=start; ih != null; ih = ih.next)
      if(ih.instruction == i)
	return ih;

    return null;
  
private com.sun.org.apache.bcel.internal.generic.InstructionHandlefindInstruction2(com.sun.org.apache.bcel.internal.generic.Instruction i)
Search for given Instruction reference, start at end of list

param
i instruction to search for
return
instruction found on success, null otherwise

    for(InstructionHandle ih=end; ih != null; ih = ih.prev)
      if(ih.instruction == i)
	return ih;

    return null;
  
public byte[]getByteCode()
When everything is finished, use this method to convert the instruction list into an array of bytes.

return
the byte code ready to be dumped

    // Update position indices of instructions
    setPositions();

    ByteArrayOutputStream b   = new ByteArrayOutputStream();
    DataOutputStream      out = new DataOutputStream(b);

    try {
      for(InstructionHandle ih=start; ih != null; ih = ih.next) {
	Instruction i = ih.instruction;
	i.dump(out); // Traverse list
      }
    } catch(IOException e) { 
      System.err.println(e);
      return null;
    }

    return b.toByteArray();
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandlegetEnd()

return
end of list

 return end; 
public com.sun.org.apache.bcel.internal.generic.InstructionHandle[]getInstructionHandles()

return
array containing all instructions (handles)

    InstructionHandle[] ihs = new InstructionHandle[length];
    InstructionHandle   ih  = start;

    for(int i=0; i < length; i++) {
      ihs[i] = ih;
      ih = ih.next;
    }

    return ihs;
  
public int[]getInstructionPositions()
Get positions (offsets) of all instructions in the list. This relies on that the list has been freshly created from an byte code array, or that setPositions() has been called. Otherwise this may be inaccurate.

return
array containing all instruction's offset in byte code

 return byte_positions; 
public com.sun.org.apache.bcel.internal.generic.Instruction[]getInstructions()

return
an array of instructions without target information for branch instructions.

    ByteSequence  bytes        = new ByteSequence(getByteCode());
    ArrayList     instructions = new ArrayList();

    try {
      while(bytes.available() > 0) {
	instructions.add(Instruction.readInstruction(bytes));
      }
    } catch(IOException e) { throw new ClassGenException(e.toString()); }

    Instruction[] result = new Instruction[instructions.size()];
    instructions.toArray(result);
    return result;
  
public intgetLength()

return
length of list (Number of instructions, not bytes)

 return length; 
public com.sun.org.apache.bcel.internal.generic.InstructionHandlegetStart()

return
start of list

 return start; 
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.InstructionList il)
Insert another list before Instruction handle ih contained in this list. Consumes argument list, i.e., it becomes empty.

param
i where to append the instruction list
param
il Instruction list to insert
return
instruction handle of the first inserted instruction

    if(il == null)
      throw new ClassGenException("Inserting null InstructionList");

    if(il.isEmpty()) // Nothing to do
      return ih;

    InstructionHandle prev = ih.prev, ret = il.start;

    ih.prev = il.end;
    il.end.next = ih;

    il.start.prev = prev;

    if(prev != null) // ih == start ?
      prev.next = il.start;
    else
      start = il.start; // Update start ...

    length += il.length; // Update length

    il.clear();

    return ret;
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.InstructionList il)
Insert another list.

param
il list to insert before start of this list
return
instruction handle of the first inserted instruction

    if(isEmpty()) {
      append(il); // Code is identical for this case
      return start;
    }
    else
      return insert(start, il); 
  
private voidinsert(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih)
Insert an instruction at start of this list.

param
ih instruction to insert

    if(isEmpty()) {
      start = end = ih;
      ih.next = ih.prev = null;
    } else {
      start.prev = ih;
      ih.next    = start;
      ih.prev    = null;
      start      = ih;
    }

    length++;
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.Instruction i, com.sun.org.apache.bcel.internal.generic.InstructionList il)
Insert another list before Instruction i contained in this list. Consumes argument list, i.e., it becomes empty.

param
i where to append the instruction list
param
il Instruction list to insert
return
instruction handle pointing to the first inserted instruction, i.e., il.getStart()

    InstructionHandle ih;

    if((ih = findInstruction1(i)) == null)
      throw new ClassGenException("Instruction " + i +
				  " is not contained in this list.");
    
    return insert(ih, il);
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.Instruction i)
Insert an instruction at start of this list.

param
i instruction to insert
return
instruction handle of the inserted instruction

    InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
    insert(ih);

    return ih;
  
public com.sun.org.apache.bcel.internal.generic.BranchHandleinsert(com.sun.org.apache.bcel.internal.generic.BranchInstruction i)
Insert a branch instruction at start of this list.

param
i branch instruction to insert
return
branch instruction handle of the appended instruction

    BranchHandle ih = BranchHandle.getBranchHandle(i);
    insert(ih);
    return ih;
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.Instruction i, com.sun.org.apache.bcel.internal.generic.Instruction j)
Insert a single instruction j before another instruction i, which must be in this list of course!

param
i Instruction in list
param
j Instruction to insert before i in list
return
instruction handle of the first inserted instruction

    return insert(i, new InstructionList(j));
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.Instruction i, com.sun.org.apache.bcel.internal.generic.CompoundInstruction c)
Insert a compound instruction before instruction i.

param
i Instruction in list
param
c The composite instruction (containing an InstructionList)
return
instruction handle of the first inserted instruction

 
    return insert(i, c.getInstructionList()); 
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.CompoundInstruction c)
Insert a compound instruction.

param
c The composite instruction (containing an InstructionList)
return
instruction handle of the first inserted instruction

    return insert(c.getInstructionList()); 
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.Instruction i)
Insert an instruction before instruction (handle) ih contained in this list.

param
ih where to insert to the instruction list
param
i Instruction to insert
return
instruction handle of the first inserted instruction

    return insert(ih, new InstructionList(i));
  
public com.sun.org.apache.bcel.internal.generic.InstructionHandleinsert(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.CompoundInstruction c)
Insert a compound instruction.

param
ih where to insert the instruction list
param
c The composite instruction (containing an InstructionList)
return
instruction handle of the first inserted instruction

    return insert(ih, c.getInstructionList()); 
  
public com.sun.org.apache.bcel.internal.generic.BranchHandleinsert(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.BranchInstruction i)
Insert an instruction before instruction (handle) ih contained in this list.

param
ih where to insert to the instruction list
param
i Instruction to insert
return
instruction handle of the first inserted instruction

    BranchHandle    bh = BranchHandle.getBranchHandle(i);
    InstructionList il = new InstructionList();
    il.append(bh);

    insert(ih, il);

    return bh;
  
public booleanisEmpty()
Test for empty list.

 return start == null; 
public java.util.Iteratoriterator()

return
Enumeration that lists all instructions (handles)

    return new Iterator() {
      private InstructionHandle ih = start;

      public Object next() {
	InstructionHandle i = ih;
	ih = ih.next;
	return i;
      }

      public void remove() {
	throw new UnsupportedOperationException();
      }

      public boolean hasNext() { return ih != null; }
    };
  
public voidmove(com.sun.org.apache.bcel.internal.generic.InstructionHandle start, com.sun.org.apache.bcel.internal.generic.InstructionHandle end, com.sun.org.apache.bcel.internal.generic.InstructionHandle target)
Take all instructions (handles) from "start" to "end" and append them after the new location "target". Of course, "end" must be after "start" and target must not be located withing this range. If you want to move something to the start of the list use null as value for target.
Any instruction targeters pointing to handles within the block, keep their targets.

param
start of moved block
param
end of moved block
param
target of moved block

    // Step 1: Check constraints

    if((start == null) || (end == null))
      throw new ClassGenException("Invalid null handle: From " + start + " to " + end);

    if((target == start) || (target == end))
      throw new ClassGenException("Invalid range: From " + start + " to " + end +
				  " contains target " + target);

    for(InstructionHandle ih = start; ih != end.next; ih = ih.next) {
      if(ih == null) // At end of list, end not found yet
	throw new ClassGenException("Invalid range: From " + start + " to " + end);
      else if(ih == target) // target may be null
	throw new ClassGenException("Invalid range: From " + start + " to " + end +
				    " contains target " + target);
    }

    // Step 2: Temporarily remove the given instructions from the list

    InstructionHandle prev = start.prev, next = end.next;

    if(prev != null)
      prev.next = next;
    else // start == this.start!
      this.start = next;

    if(next != null)
      next.prev = prev;
    else // end == this.end!
      this.end = prev;

    start.prev = end.next = null;

    // Step 3: append after target

    if(target == null) { // append to start of list
      end.next = this.start;
      this.start = start;
    } else {
      next = target.next;

      target.next = start;
      start.prev  = target;
      end.next    = next;

      if(next != null)
	next.prev = end;
    }
  
public voidmove(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, com.sun.org.apache.bcel.internal.generic.InstructionHandle target)
Move a single instruction (handle) to a new location.

param
ih moved instruction
param
target new location of moved instruction

    move(ih, ih, target);
  
public voidredirectBranches(com.sun.org.apache.bcel.internal.generic.InstructionHandle old_target, com.sun.org.apache.bcel.internal.generic.InstructionHandle new_target)
Redirect all references from old_target to new_target, i.e., update targets of branch instructions.

param
old_target the old target instruction handle
param
new_target the new target instruction handle

    for(InstructionHandle ih = start; ih != null; ih = ih.next) {
      Instruction i  = ih.getInstruction();

      if(i instanceof BranchInstruction) {
	BranchInstruction b      = (BranchInstruction)i;
	InstructionHandle target = b.getTarget();

	if(target == old_target)
	  b.setTarget(new_target);

	if(b instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
	  InstructionHandle[] targets = ((Select)b).getTargets();
	  
	  for(int j=0; j < targets.length; j++) // Update targets
	    if(targets[j] == old_target)
	      ((Select)b).setTarget(j, new_target);
	}
      }
    }
  
public voidredirectExceptionHandlers(com.sun.org.apache.bcel.internal.generic.CodeExceptionGen[] exceptions, com.sun.org.apache.bcel.internal.generic.InstructionHandle old_target, com.sun.org.apache.bcel.internal.generic.InstructionHandle new_target)
Redirect all references of exception handlers from old_target to new_target.

param
exceptions array of exception handlers
param
old_target the old target instruction handle
param
new_target the new target instruction handle
see
MethodGen

    for(int i=0; i < exceptions.length; i++) {
      if(exceptions[i].getStartPC() == old_target)
	exceptions[i].setStartPC(new_target);

      if(exceptions[i].getEndPC() == old_target)
	exceptions[i].setEndPC(new_target);

      if(exceptions[i].getHandlerPC() == old_target)
	exceptions[i].setHandlerPC(new_target);
    }
  
public voidredirectLocalVariables(com.sun.org.apache.bcel.internal.generic.LocalVariableGen[] lg, com.sun.org.apache.bcel.internal.generic.InstructionHandle old_target, com.sun.org.apache.bcel.internal.generic.InstructionHandle new_target)
Redirect all references of local variables from old_target to new_target.

param
lg array of local variables
param
old_target the old target instruction handle
param
new_target the new target instruction handle
see
MethodGen

    for(int i=0; i < lg.length; i++) {
      InstructionHandle start = lg[i].getStart();
      InstructionHandle end   = lg[i].getEnd();
      
      if(start == old_target)
	lg[i].setStart(new_target);

      if(end == old_target)
	lg[i].setEnd(new_target);
    }
  
private voidremove(com.sun.org.apache.bcel.internal.generic.InstructionHandle prev, com.sun.org.apache.bcel.internal.generic.InstructionHandle next)
Remove from instruction `prev' to instruction `next' both contained in this list. Throws TargetLostException when one of the removed instruction handles is still being targeted.

param
prev where to start deleting (predecessor, exclusive)
param
next where to end deleting (successor, exclusive)

    InstructionHandle first, last; // First and last deleted instruction

    if((prev == null) && (next == null)) { // singleton list
      first = last = start;
      start = end = null;
    } else {
      if(prev == null) { // At start of list
	first = start;
	start = next;
      } else {
	first     = prev.next;
	prev.next = next;
      }
      
      if(next == null) { // At end of list
	last = end;
	end  = prev;
      } else {
	last      = next.prev;
	next.prev = prev;
      }
    }

    first.prev = null; // Completely separated from rest of list
    last.next  = null;

    ArrayList target_vec = new ArrayList();

    for(InstructionHandle ih=first; ih != null; ih = ih.next)
      ih.getInstruction().dispose(); // e.g. BranchInstructions release their targets

    StringBuffer buf = new StringBuffer("{ ");
    for(InstructionHandle ih=first; ih != null; ih = next) {
      next = ih.next;
      length--;
	
      if(ih.hasTargeters()) { // Still got targeters?
	target_vec.add(ih);
	buf.append(ih.toString(true) + " ");
	ih.next = ih.prev = null;
      } else
	ih.dispose();
    }

    buf.append("}");

    if(!target_vec.isEmpty()) {
      InstructionHandle[] targeted = new InstructionHandle[target_vec.size()];
      target_vec.toArray(targeted);
      throw new TargetLostException(targeted, buf.toString());
    }
  
public voidremoveObserver(com.sun.org.apache.bcel.internal.generic.InstructionListObserver o)
Remove observer for this object.

    if(observers != null)
      observers.remove(o);
  
public voidreplaceConstantPool(com.sun.org.apache.bcel.internal.generic.ConstantPoolGen old_cp, com.sun.org.apache.bcel.internal.generic.ConstantPoolGen new_cp)
Replace all references to the old constant pool with references to the new constant pool

    for(InstructionHandle ih=start; ih != null; ih = ih.next) {
      Instruction i = ih.instruction;

      if(i instanceof CPInstruction) {
	CPInstruction ci = (CPInstruction)i;
	Constant      c  = old_cp.getConstant(ci.getIndex());
	ci.setIndex(new_cp.addConstant(c, old_cp));
      }
    }    
  
public voidsetPositions()

    setPositions(false);
  
public voidsetPositions(boolean check)
Give all instructions their position number (offset in byte stream), i.e., make the list ready to be dumped.

param
check Perform sanity checks, e.g. if all targeted instructions really belong to this list

    int max_additional_bytes = 0, additional_bytes = 0;
    int index = 0, count = 0;
    int[] pos = new int[length];

    /* Pass 0: Sanity checks
     */
    if(check) {
      for(InstructionHandle ih=start; ih != null; ih = ih.next) {
	Instruction i = ih.instruction;

	if(i instanceof BranchInstruction) { // target instruction within list?
	  Instruction inst = ((BranchInstruction)i).getTarget().instruction;
	  if(!contains(inst))
	    throw new ClassGenException("Branch target of " +
					Constants.OPCODE_NAMES[i.opcode] + ":" +
					inst + " not in instruction list");

	  if(i instanceof Select) {
	    InstructionHandle[] targets = ((Select)i).getTargets();
	    
	    for(int j=0; j < targets.length; j++) {
	      inst = targets[j].instruction;
	      if(!contains(inst))
		throw new ClassGenException("Branch target of " +
					    Constants.OPCODE_NAMES[i.opcode] + ":" +
					    inst + " not in instruction list");
	    }
	  }

	  if(!(ih instanceof BranchHandle))
	    throw new ClassGenException("Branch instruction " +
					Constants.OPCODE_NAMES[i.opcode] + ":" +
					inst + " not contained in BranchHandle.");

	}
      }
    }

    /* Pass 1: Set position numbers and sum up the maximum number of bytes an
     * instruction may be shifted.
     */
    for(InstructionHandle ih=start; ih != null; ih = ih.next) {
      Instruction i = ih.instruction;

      ih.setPosition(index);
      pos[count++] = index;

      /* Get an estimate about how many additional bytes may be added, because
       * BranchInstructions may have variable length depending on the target
       * offset (short vs. int) or alignment issues (TABLESWITCH and
       * LOOKUPSWITCH).
       */
      switch(i.getOpcode()) {
      case Constants.JSR: case Constants.GOTO:
	max_additional_bytes += 2;
	break;

      case Constants.TABLESWITCH: case Constants.LOOKUPSWITCH:
	max_additional_bytes += 3;
	break;
      }

      index += i.getLength();
    }
    
    /* Pass 2: Expand the variable-length (Branch)Instructions depending on
     * the target offset (short or int) and ensure that branch targets are
     * within this list.
     */
    for(InstructionHandle ih=start; ih != null; ih = ih.next)
      additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes);

    /* Pass 3: Update position numbers (which may have changed due to the
     * preceding expansions), like pass 1.
     */
    index=count=0;
    for(InstructionHandle ih=start; ih != null; ih = ih.next) {
      Instruction i = ih.instruction;

      ih.setPosition(index);
      pos[count++] = index;
      index += i.getLength();
    }

    byte_positions = new int[count]; // Trim to proper size
    System.arraycopy(pos, 0, byte_positions, 0, count);
  
public intsize()

return
length of list (Number of instructions, not bytes)

 return length; 
public java.lang.StringtoString()

    return toString(true);
  
public java.lang.StringtoString(boolean verbose)

param
verbose toggle output format
return
String containing all instructions in this list.

    StringBuffer buf = new StringBuffer();

    for(InstructionHandle ih=start; ih != null; ih = ih.next) {
      buf.append(ih.toString(verbose) + "\n");
    }

    return buf.toString();
  
public voidupdate()
Call notify() method on all observers. This method is not called automatically whenever the state has changed, but has to be called by the user after he has finished editing the object.

    if(observers != null)
      for(Iterator e = observers.iterator(); e.hasNext(); )
	((InstructionListObserver)e.next()).notify(this);