You are viewing a plain text version of this content. The canonical link for it is here.
Posted to bcel-dev@jakarta.apache.org by tc...@apache.org on 2006/03/15 12:33:43 UTC
svn commit: r386056 [18/28] - in /jakarta/bcel/trunk: examples/
examples/Mini/ src/java/org/apache/bcel/
src/java/org/apache/bcel/classfile/ src/java/org/apache/bcel/generic/
src/java/org/apache/bcel/util/ src/java/org/apache/bcel/verifier/
src/java/or...
Modified: jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionList.java
URL: http://svn.apache.org/viewcvs/jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionList.java?rev=386056&r1=386055&r2=386056&view=diff
==============================================================================
--- jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionList.java (original)
+++ jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionList.java Wed Mar 15 03:31:56 2006
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- */
+ */
package org.apache.bcel.generic;
-
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -50,1208 +49,1217 @@
* @see BranchHandle
*/
public class InstructionList implements Serializable {
- private InstructionHandle start = null, end = null;
- private int length = 0; // number of elements in list
- private int[] byte_positions; // byte code offsets corresponding to instructions
-
- /**
- * Create (empty) instruction list.
- */
- public InstructionList() {}
-
- /**
- * Create instruction list containing one instruction.
- * @param i initial instruction
- */
- public InstructionList(Instruction i) {
- append(i);
- }
-
- /**
- * Create instruction list containing one instruction.
- * @param i initial instruction
- */
- public InstructionList(BranchInstruction i) {
- append(i);
- }
-
- /**
- * Initialize list with (nonnull) compound instruction. Consumes argument
- * list, i.e., it becomes empty.
- *
- * @param c compound instruction (list)
- */
- public InstructionList(CompoundInstruction c) {
- append(c.getInstructionList());
- }
-
- /**
- * Test for empty list.
- */
- public boolean isEmpty() { return start == null; } // && end == null
-
- /**
- * 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
- */
- public static InstructionHandle findHandle(InstructionHandle[] ihs,
- int[] pos, int count,
- int target) {
- 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;
- }
-
- /**
- * 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
- */
- public InstructionHandle findHandle(int pos) {
- InstructionHandle[] ihs = getInstructionHandles();
- return findHandle(ihs, byte_positions, length, pos);
- }
-
- /**
- * Initialize instruction list from byte array.
- *
- * @param code byte array containing the instructions
- */
- public InstructionList(byte[] code) {
- 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
- }
- }
- }
- }
- }
-
- /**
- * 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 <B>first</B> appended instruction
- */
- public InstructionHandle append(InstructionHandle ih, InstructionList il) {
- 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;
- }
-
- /**
- * 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 <B>first</B> appended instruction
- */
- public InstructionHandle append(Instruction i, InstructionList il) {
- 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);
- }
-
- /**
- * 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 <B>first</B> appended instruction
- */
- public InstructionHandle append(InstructionList il) {
- 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
- }
-
- /**
- * Append an instruction to the end of this list.
- *
- * @param ih instruction to append
- */
- private void append(InstructionHandle ih) {
- 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
- }
-
- /**
- * Append an instruction to the end of this list.
- *
- * @param i instruction to append
- * @return instruction handle of the appended instruction
- */
- public InstructionHandle append(Instruction i) {
- InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
- append(ih);
-
- return ih;
- }
-
- /**
- * Append a branch instruction to the end of this list.
- *
- * @param i branch instruction to append
- * @return branch instruction handle of the appended instruction
- */
- public BranchHandle append(BranchInstruction i) {
- BranchHandle ih = BranchHandle.getBranchHandle(i);
- append(ih);
-
- return ih;
- }
-
- /**
- * 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
- */
- public InstructionHandle append(Instruction i, Instruction j) {
- return append(i, new InstructionList(j));
- }
-
- /**
- * 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
- */
- public InstructionHandle append(Instruction i, CompoundInstruction c) {
- return append(i, c.getInstructionList());
- }
-
- /**
- * Append a compound instruction.
- *
- * @param c The composite instruction (containing an InstructionList)
- * @return instruction handle of the first appended instruction
- */
- public InstructionHandle append(CompoundInstruction c) {
- return append(c.getInstructionList());
- }
-
- /**
- * 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
- */
- public InstructionHandle append(InstructionHandle ih, CompoundInstruction c) {
- return append(ih, c.getInstructionList());
- }
-
- /**
- * 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 <B>first</B> appended instruction
- */
- public InstructionHandle append(InstructionHandle ih, Instruction i) {
- return append(ih, new InstructionList(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 <B>first</B> appended instruction
- */
- public BranchHandle append(InstructionHandle ih, BranchInstruction i) {
- BranchHandle bh = BranchHandle.getBranchHandle(i);
- InstructionList il = new InstructionList();
- il.append(bh);
-
- append(ih, il);
-
- return bh;
- }
-
- /**
- * Insert another list before 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 insert
- * @return instruction handle of the first inserted instruction
- */
- public InstructionHandle insert(InstructionHandle ih, InstructionList il) {
- 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;
- }
-
- /**
- * Insert another list.
- *
- * @param il list to insert before start of this list
- * @return instruction handle of the first inserted instruction
- */
- public InstructionHandle insert(InstructionList il) {
- if(isEmpty()) {
- append(il); // Code is identical for this case
- return start;
- }
- else
- return insert(start, il);
- }
-
- /**
- * Insert an instruction at start of this list.
- *
- * @param ih instruction to insert
- */
- private void insert(InstructionHandle ih) {
- if(isEmpty()) {
- start = end = ih;
- ih.next = ih.prev = null;
- } else {
- start.prev = ih;
- ih.next = start;
- ih.prev = null;
- start = ih;
- }
-
- length++;
- }
-
- /**
- * 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()
- */
- public InstructionHandle insert(Instruction i, InstructionList il) {
- InstructionHandle ih;
-
- if((ih = findInstruction1(i)) == null)
- throw new ClassGenException("Instruction " + i +
- " is not contained in this list.");
-
- return insert(ih, il);
- }
-
- /**
- * Insert an instruction at start of this list.
- *
- * @param i instruction to insert
- * @return instruction handle of the inserted instruction
- */
- public InstructionHandle insert(Instruction i) {
- InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
- insert(ih);
-
- return ih;
- }
-
- /**
- * Insert a branch instruction at start of this list.
- *
- * @param i branch instruction to insert
- * @return branch instruction handle of the appended instruction
- */
- public BranchHandle insert(BranchInstruction i) {
- BranchHandle ih = BranchHandle.getBranchHandle(i);
- insert(ih);
- return ih;
- }
-
- /**
- * 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
- */
- public InstructionHandle insert(Instruction i, Instruction j) {
- return insert(i, new InstructionList(j));
- }
-
- /**
- * 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
- */
- public InstructionHandle insert(Instruction i, CompoundInstruction c) {
- return insert(i, c.getInstructionList());
- }
-
- /**
- * Insert a compound instruction.
- *
- * @param c The composite instruction (containing an InstructionList)
- * @return instruction handle of the first inserted instruction
- */
- public InstructionHandle insert(CompoundInstruction c) {
- return insert(c.getInstructionList());
- }
-
- /**
- * 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
- */
- public InstructionHandle insert(InstructionHandle ih, Instruction i) {
- return insert(ih, new InstructionList(i));
- }
-
- /**
- * 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
- */
- public InstructionHandle insert(InstructionHandle ih, CompoundInstruction c) {
- return insert(ih, c.getInstructionList());
- }
-
- /**
- * 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
- */
- public BranchHandle insert(InstructionHandle ih, BranchInstruction i) {
- BranchHandle bh = BranchHandle.getBranchHandle(i);
- InstructionList il = new InstructionList();
- il.append(bh);
-
- insert(ih, il);
-
- return bh;
- }
-
- /**
- * 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.<br>
- * 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
- */
- public void move(InstructionHandle start, InstructionHandle end, InstructionHandle target) {
- // 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
- if (this.start != null)
- this.start.prev = end;
- 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;
- else
- this.end = end;
- }
- }
-
- /**
- * Move a single instruction (handle) to a new location.
- *
- * @param ih moved instruction
- * @param target new location of moved instruction
- */
- public void move(InstructionHandle ih, InstructionHandle target) {
- move(ih, ih, target);
- }
-
- /**
- * 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)
- */
- private void remove(InstructionHandle prev, InstructionHandle next)
- throws TargetLostException
- {
- 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;
-
- List 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());
- }
- }
-
- /**
- * Remove instruction from this list. The corresponding Instruction
- * handles must not be reused!
- *
- * @param ih instruction (handle) to remove
- */
- public void delete(InstructionHandle ih) throws TargetLostException {
- remove(ih.prev, ih.next);
- }
-
- /**
- * Remove instruction from this list. The corresponding Instruction
- * handles must not be reused!
- *
- * @param i instruction to remove
- */
- public void delete(Instruction i) throws TargetLostException {
- InstructionHandle ih;
-
- if((ih = findInstruction1(i)) == null)
- throw new ClassGenException("Instruction " + i +
- " is not contained in this list.");
- delete(ih);
- }
-
- /**
- * 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)
- */
- public void delete(InstructionHandle from, InstructionHandle to)
- throws TargetLostException
- {
- remove(from.prev, to.next);
- }
-
- /**
- * 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)
- */
- public void delete(Instruction from, Instruction to) throws TargetLostException {
- 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);
- }
-
- /**
- * Search for given Instruction reference, start at beginning of list.
- *
- * @param i instruction to search for
- * @return instruction found on success, null otherwise
- */
- private InstructionHandle findInstruction1(Instruction i) {
- for(InstructionHandle ih=start; ih != null; ih = ih.next)
- if(ih.instruction == i)
- return ih;
-
- return null;
- }
-
- /**
- * Search for given Instruction reference, start at end of list
- *
- * @param i instruction to search for
- * @return instruction found on success, null otherwise
- */
- private InstructionHandle findInstruction2(Instruction i) {
- for(InstructionHandle ih=end; ih != null; ih = ih.prev)
- if(ih.instruction == i)
- return ih;
-
- return null;
- }
-
- public boolean contains(InstructionHandle i) {
- if(i == null)
- return false;
-
- for(InstructionHandle ih=start; ih != null; ih = ih.next)
- if(ih == i)
- return true;
-
- return false;
- }
-
- public boolean contains(Instruction i) {
- return findInstruction1(i) != null;
- }
-
- public void setPositions() {
- setPositions(false);
- }
-
- /**
- * 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
- */
- public void setPositions(boolean check) {
- 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);
- }
-
- /**
- * 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
- */
- public byte[] getByteCode() {
- // 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();
- }
-
- /**
- * @return an array of instructions without target information for branch instructions.
- */
- public Instruction[] getInstructions() {
- ByteSequence bytes = new ByteSequence(getByteCode());
- List instructions = new ArrayList();
-
- try {
- while(bytes.available() > 0) {
- instructions.add(Instruction.readInstruction(bytes));
- }
- } catch(IOException e) { throw new ClassGenException(e.toString()); }
-
- return (Instruction[])instructions.toArray(new Instruction[instructions.size()]);
- }
-
- public String toString() {
- return toString(true);
- }
-
- /**
- * @param verbose toggle output format
- * @return String containing all instructions in this list.
- */
- public String toString(boolean verbose) {
- StringBuffer buf = new StringBuffer();
-
- for(InstructionHandle ih=start; ih != null; ih = ih.next) {
- buf.append(ih.toString(verbose)).append("\n");
- }
-
- return buf.toString();
- }
-
- /**
- * @return Enumeration that lists all instructions (handles)
- */
- public Iterator iterator() {
- 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; }
- };
- }
-
- /**
- * @return array containing all instructions (handles)
- */
- public InstructionHandle[] getInstructionHandles() {
- InstructionHandle[] ihs = new InstructionHandle[length];
- InstructionHandle ih = start;
-
- for(int i=0; i < length; i++) {
- ihs[i] = ih;
- ih = ih.next;
- }
-
- return ihs;
- }
-
- /**
- * 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
- */
- public int[] getInstructionPositions() { return byte_positions; }
-
- /**
- * @return complete, i.e., deep copy of this list
- */
- public InstructionList copy() {
- Map 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;
- }
-
- /** Replace all references to the old constant pool with references to the new
- * constant pool
- */
- public void replaceConstantPool(ConstantPoolGen old_cp, ConstantPoolGen new_cp) {
- 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));
- }
- }
- }
-
- private void clear() {
- start = end = null;
- length = 0;
- }
-
- /**
- * Delete contents of list. Provides besser memory utilization,
- * because the system then may reuse the instruction handles. This
- * method is typically called right after
- * <href="MethodGen.html#getMethod()">MethodGen.getMethod()</a>.
- */
- public void dispose() {
- // 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();
- }
-
- /**
- * @return start of list
- */
- public InstructionHandle getStart() { return start; }
-
- /**
- * @return end of list
- */
- public InstructionHandle getEnd() { return end; }
-
- /**
- * @return length of list (Number of instructions, not bytes)
- */
- public int getLength() { return length; }
-
- /**
- * @return length of list (Number of instructions, not bytes)
- */
- public int size() { return length; }
-
- /**
- * 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
- */
- public void redirectBranches(InstructionHandle old_target,
- InstructionHandle new_target) {
- 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);
- }
- }
- }
- }
-
- /**
- * 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
- */
- public void redirectLocalVariables(LocalVariableGen[] lg,
- InstructionHandle old_target,
- InstructionHandle new_target) {
- 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);
- }
- }
-
- /**
- * 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
- */
- public void redirectExceptionHandlers(CodeExceptionGen[] exceptions,
- InstructionHandle old_target,
- InstructionHandle new_target) {
- 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);
- }
- }
-
- private List observers;
-
- /** Add observer for this object.
- */
- public void addObserver(InstructionListObserver o) {
- if(observers == null)
- observers = new ArrayList();
-
- observers.add(o);
- }
-
- /** Remove observer for this object.
- */
- public void removeObserver(InstructionListObserver o) {
- if(observers != null)
- observers.remove(o);
- }
-
- /** 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.
- */
- public void update() {
- if(observers != null)
- for(Iterator e = observers.iterator(); e.hasNext(); )
- ((InstructionListObserver)e.next()).notify(this);
- }
-}
+ private InstructionHandle start = null, end = null;
+ private int length = 0; // number of elements in list
+ private int[] byte_positions; // byte code offsets corresponding to instructions
+
+
+ /**
+ * Create (empty) instruction list.
+ */
+ public InstructionList() {
+ }
+
+
+ /**
+ * Create instruction list containing one instruction.
+ * @param i initial instruction
+ */
+ public InstructionList(Instruction i) {
+ append(i);
+ }
+
+
+ /**
+ * Create instruction list containing one instruction.
+ * @param i initial instruction
+ */
+ public InstructionList(BranchInstruction i) {
+ append(i);
+ }
+
+
+ /**
+ * Initialize list with (nonnull) compound instruction. Consumes argument
+ * list, i.e., it becomes empty.
+ *
+ * @param c compound instruction (list)
+ */
+ public InstructionList(CompoundInstruction c) {
+ append(c.getInstructionList());
+ }
+
+
+ /**
+ * Test for empty list.
+ */
+ public boolean isEmpty() {
+ return start == null;
+ } // && end == null
+
+
+ /**
+ * 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
+ */
+ public static InstructionHandle findHandle( InstructionHandle[] ihs, int[] pos, int count,
+ int target ) {
+ 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) {
+ return ihs[i];
+ } else if (target < j) {
+ r = i - 1;
+ } else {
+ l = i + 1;
+ }
+ } while (l <= r);
+ return null;
+ }
+
+
+ /**
+ * 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
+ */
+ public InstructionHandle findHandle( int pos ) {
+ InstructionHandle[] ihs = getInstructionHandles();
+ return findHandle(ihs, byte_positions, length, pos);
+ }
+
+
+ /**
+ * Initialize instruction list from byte array.
+ *
+ * @param code byte array containing the instructions
+ */
+ public InstructionList(byte[] code) {
+ 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) {
+ 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) {
+ 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) {
+ throw new ClassGenException("Couldn't find target for switch: " + bi);
+ }
+ s.setTarget(j, ih); // Update target
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * 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 <B>first</B> appended instruction
+ */
+ public InstructionHandle append( InstructionHandle ih, InstructionList il ) {
+ if (il == null) {
+ throw new ClassGenException("Appending null InstructionList");
+ }
+ if (il.isEmpty()) {
+ return ih;
+ }
+ InstructionHandle next = ih.next, ret = il.start;
+ ih.next = il.start;
+ il.start.prev = ih;
+ il.end.next = next;
+ if (next != null) {
+ next.prev = il.end;
+ } else {
+ end = il.end; // Update end ...
+ }
+ length += il.length; // Update length
+ il.clear();
+ return ret;
+ }
+
+
+ /**
+ * 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 <B>first</B> appended instruction
+ */
+ public InstructionHandle append( Instruction i, InstructionList il ) {
+ InstructionHandle ih;
+ if ((ih = findInstruction2(i)) == null) {
+ throw new ClassGenException("Instruction " + i + " is not contained in this list.");
+ }
+ return append(ih, 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 <B>first</B> appended instruction
+ */
+ public InstructionHandle append( InstructionList il ) {
+ if (il == null) {
+ throw new ClassGenException("Appending null InstructionList");
+ }
+ if (il.isEmpty()) {
+ 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
+ }
+ }
+
+
+ /**
+ * Append an instruction to the end of this list.
+ *
+ * @param ih instruction to append
+ */
+ private void append( InstructionHandle ih ) {
+ 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
+ }
+
+
+ /**
+ * Append an instruction to the end of this list.
+ *
+ * @param i instruction to append
+ * @return instruction handle of the appended instruction
+ */
+ public InstructionHandle append( Instruction i ) {
+ InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
+ append(ih);
+ return ih;
+ }
+
+
+ /**
+ * Append a branch instruction to the end of this list.
+ *
+ * @param i branch instruction to append
+ * @return branch instruction handle of the appended instruction
+ */
+ public BranchHandle append( BranchInstruction i ) {
+ BranchHandle ih = BranchHandle.getBranchHandle(i);
+ append(ih);
+ return ih;
+ }
+
+
+ /**
+ * 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
+ */
+ public InstructionHandle append( Instruction i, Instruction j ) {
+ return append(i, new InstructionList(j));
+ }
+
+
+ /**
+ * 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
+ */
+ public InstructionHandle append( Instruction i, CompoundInstruction c ) {
+ return append(i, c.getInstructionList());
+ }
+
+
+ /**
+ * Append a compound instruction.
+ *
+ * @param c The composite instruction (containing an InstructionList)
+ * @return instruction handle of the first appended instruction
+ */
+ public InstructionHandle append( CompoundInstruction c ) {
+ return append(c.getInstructionList());
+ }
+
+
+ /**
+ * 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
+ */
+ public InstructionHandle append( InstructionHandle ih, CompoundInstruction c ) {
+ return append(ih, c.getInstructionList());
+ }
+
+
+ /**
+ * 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 <B>first</B> appended instruction
+ */
+ public InstructionHandle append( InstructionHandle ih, Instruction i ) {
+ return append(ih, new InstructionList(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 <B>first</B> appended instruction
+ */
+ public BranchHandle append( InstructionHandle ih, BranchInstruction i ) {
+ BranchHandle bh = BranchHandle.getBranchHandle(i);
+ InstructionList il = new InstructionList();
+ il.append(bh);
+ append(ih, il);
+ return bh;
+ }
+
+
+ /**
+ * Insert another list before 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 insert
+ * @return instruction handle of the first inserted instruction
+ */
+ public InstructionHandle insert( InstructionHandle ih, InstructionList il ) {
+ if (il == null) {
+ throw new ClassGenException("Inserting null InstructionList");
+ }
+ if (il.isEmpty()) {
+ return ih;
+ }
+ InstructionHandle prev = ih.prev, ret = il.start;
+ ih.prev = il.end;
+ il.end.next = ih;
+ il.start.prev = prev;
+ if (prev != null) {
+ prev.next = il.start;
+ } else {
+ start = il.start; // Update start ...
+ }
+ length += il.length; // Update length
+ il.clear();
+ return ret;
+ }
+
+
+ /**
+ * Insert another list.
+ *
+ * @param il list to insert before start of this list
+ * @return instruction handle of the first inserted instruction
+ */
+ public InstructionHandle insert( InstructionList il ) {
+ if (isEmpty()) {
+ append(il); // Code is identical for this case
+ return start;
+ } else {
+ return insert(start, il);
+ }
+ }
+
+
+ /**
+ * Insert an instruction at start of this list.
+ *
+ * @param ih instruction to insert
+ */
+ private void insert( InstructionHandle ih ) {
+ if (isEmpty()) {
+ start = end = ih;
+ ih.next = ih.prev = null;
+ } else {
+ start.prev = ih;
+ ih.next = start;
+ ih.prev = null;
+ start = ih;
+ }
+ length++;
+ }
+
+
+ /**
+ * 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()
+ */
+ public InstructionHandle insert( Instruction i, InstructionList il ) {
+ InstructionHandle ih;
+ if ((ih = findInstruction1(i)) == null) {
+ throw new ClassGenException("Instruction " + i + " is not contained in this list.");
+ }
+ return insert(ih, il);
+ }
+
+
+ /**
+ * Insert an instruction at start of this list.
+ *
+ * @param i instruction to insert
+ * @return instruction handle of the inserted instruction
+ */
+ public InstructionHandle insert( Instruction i ) {
+ InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
+ insert(ih);
+ return ih;
+ }
+
+
+ /**
+ * Insert a branch instruction at start of this list.
+ *
+ * @param i branch instruction to insert
+ * @return branch instruction handle of the appended instruction
+ */
+ public BranchHandle insert( BranchInstruction i ) {
+ BranchHandle ih = BranchHandle.getBranchHandle(i);
+ insert(ih);
+ return ih;
+ }
+
+
+ /**
+ * 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
+ */
+ public InstructionHandle insert( Instruction i, Instruction j ) {
+ return insert(i, new InstructionList(j));
+ }
+
+
+ /**
+ * 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
+ */
+ public InstructionHandle insert( Instruction i, CompoundInstruction c ) {
+ return insert(i, c.getInstructionList());
+ }
+
+
+ /**
+ * Insert a compound instruction.
+ *
+ * @param c The composite instruction (containing an InstructionList)
+ * @return instruction handle of the first inserted instruction
+ */
+ public InstructionHandle insert( CompoundInstruction c ) {
+ return insert(c.getInstructionList());
+ }
+
+
+ /**
+ * 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
+ */
+ public InstructionHandle insert( InstructionHandle ih, Instruction i ) {
+ return insert(ih, new InstructionList(i));
+ }
+
+
+ /**
+ * 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
+ */
+ public InstructionHandle insert( InstructionHandle ih, CompoundInstruction c ) {
+ return insert(ih, c.getInstructionList());
+ }
+
+
+ /**
+ * 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
+ */
+ public BranchHandle insert( InstructionHandle ih, BranchInstruction i ) {
+ BranchHandle bh = BranchHandle.getBranchHandle(i);
+ InstructionList il = new InstructionList();
+ il.append(bh);
+ insert(ih, il);
+ return bh;
+ }
+
+
+ /**
+ * 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.<br>
+ * 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
+ */
+ public void move( InstructionHandle start, InstructionHandle end, InstructionHandle target ) {
+ // 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) {
+ throw new ClassGenException("Invalid range: From " + start + " to " + end);
+ } else if (ih == target) {
+ 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 {
+ this.start = next;
+ }
+ if (next != null) {
+ next.prev = prev;
+ } else {
+ this.end = prev;
+ }
+ start.prev = end.next = null;
+ // Step 3: append after target
+ if (target == null) { // append to start of list
+ if (this.start != null) {
+ this.start.prev = end;
+ }
+ 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;
+ } else {
+ this.end = end;
+ }
+ }
+ }
+
+
+ /**
+ * Move a single instruction (handle) to a new location.
+ *
+ * @param ih moved instruction
+ * @param target new location of moved instruction
+ */
+ public void move( InstructionHandle ih, InstructionHandle target ) {
+ move(ih, ih, target);
+ }
+
+
+ /**
+ * 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)
+ */
+ private void remove( InstructionHandle prev, InstructionHandle next )
+ throws TargetLostException {
+ 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;
+ List 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());
+ }
+ }
+
+
+ /**
+ * Remove instruction from this list. The corresponding Instruction
+ * handles must not be reused!
+ *
+ * @param ih instruction (handle) to remove
+ */
+ public void delete( InstructionHandle ih ) throws TargetLostException {
+ remove(ih.prev, ih.next);
+ }
+
+
+ /**
+ * Remove instruction from this list. The corresponding Instruction
+ * handles must not be reused!
+ *
+ * @param i instruction to remove
+ */
+ public void delete( Instruction i ) throws TargetLostException {
+ InstructionHandle ih;
+ if ((ih = findInstruction1(i)) == null) {
+ throw new ClassGenException("Instruction " + i + " is not contained in this list.");
+ }
+ delete(ih);
+ }
+
+
+ /**
+ * 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)
+ */
+ public void delete( InstructionHandle from, InstructionHandle to ) throws TargetLostException {
+ remove(from.prev, to.next);
+ }
+
+
+ /**
+ * 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)
+ */
+ public void delete( Instruction from, Instruction to ) throws TargetLostException {
+ 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);
+ }
+
+
+ /**
+ * Search for given Instruction reference, start at beginning of list.
+ *
+ * @param i instruction to search for
+ * @return instruction found on success, null otherwise
+ */
+ private InstructionHandle findInstruction1( Instruction i ) {
+ for (InstructionHandle ih = start; ih != null; ih = ih.next) {
+ if (ih.instruction == i) {
+ return ih;
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Search for given Instruction reference, start at end of list
+ *
+ * @param i instruction to search for
+ * @return instruction found on success, null otherwise
+ */
+ private InstructionHandle findInstruction2( Instruction i ) {
+ for (InstructionHandle ih = end; ih != null; ih = ih.prev) {
+ if (ih.instruction == i) {
+ return ih;
+ }
+ }
+ return null;
+ }
+
+
+ public boolean contains( InstructionHandle i ) {
+ if (i == null) {
+ return false;
+ }
+ for (InstructionHandle ih = start; ih != null; ih = ih.next) {
+ if (ih == i) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ public boolean contains( Instruction i ) {
+ return findInstruction1(i) != null;
+ }
+
+
+ public void setPositions() {
+ setPositions(false);
+ }
+
+
+ /**
+ * 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
+ */
+ public void setPositions( boolean check ) {
+ 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);
+ }
+
+
+ /**
+ * 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
+ */
+ public byte[] getByteCode() {
+ // 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();
+ }
+
+
+ /**
+ * @return an array of instructions without target information for branch instructions.
+ */
+ public Instruction[] getInstructions() {
+ ByteSequence bytes = new ByteSequence(getByteCode());
+ List instructions = new ArrayList();
+ try {
+ while (bytes.available() > 0) {
+ instructions.add(Instruction.readInstruction(bytes));
+ }
+ } catch (IOException e) {
+ throw new ClassGenException(e.toString());
+ }
+ return (Instruction[]) instructions.toArray(new Instruction[instructions.size()]);
+ }
+
+
+ public String toString() {
+ return toString(true);
+ }
+
+
+ /**
+ * @param verbose toggle output format
+ * @return String containing all instructions in this list.
+ */
+ public String toString( boolean verbose ) {
+ StringBuffer buf = new StringBuffer();
+ for (InstructionHandle ih = start; ih != null; ih = ih.next) {
+ buf.append(ih.toString(verbose)).append("\n");
+ }
+ return buf.toString();
+ }
+
+
+ /**
+ * @return Enumeration that lists all instructions (handles)
+ */
+ public Iterator iterator() {
+ 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;
+ }
+ };
+ }
+
+
+ /**
+ * @return array containing all instructions (handles)
+ */
+ public InstructionHandle[] getInstructionHandles() {
+ InstructionHandle[] ihs = new InstructionHandle[length];
+ InstructionHandle ih = start;
+ for (int i = 0; i < length; i++) {
+ ihs[i] = ih;
+ ih = ih.next;
+ }
+ return ihs;
+ }
+
+
+ /**
+ * 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
+ */
+ public int[] getInstructionPositions() {
+ return byte_positions;
+ }
+
+
+ /**
+ * @return complete, i.e., deep copy of this list
+ */
+ public InstructionList copy() {
+ Map 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;
+ }
+
+
+ /** Replace all references to the old constant pool with references to the new
+ * constant pool
+ */
+ public void replaceConstantPool( ConstantPoolGen old_cp, ConstantPoolGen new_cp ) {
+ 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));
+ }
+ }
+ }
+
+
+ private void clear() {
+ start = end = null;
+ length = 0;
+ }
+
+
+ /**
+ * Delete contents of list. Provides besser memory utilization,
+ * because the system then may reuse the instruction handles. This
+ * method is typically called right after
+ * <href="MethodGen.html#getMethod()">MethodGen.getMethod()</a>.
+ */
+ public void dispose() {
+ // 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();
+ }
+
+
+ /**
+ * @return start of list
+ */
+ public InstructionHandle getStart() {
+ return start;
+ }
+
+
+ /**
+ * @return end of list
+ */
+ public InstructionHandle getEnd() {
+ return end;
+ }
+
+
+ /**
+ * @return length of list (Number of instructions, not bytes)
+ */
+ public int getLength() {
+ return length;
+ }
+
+
+ /**
+ * @return length of list (Number of instructions, not bytes)
+ */
+ public int size() {
+ return length;
+ }
+
+
+ /**
+ * 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
+ */
+ public void redirectBranches( InstructionHandle old_target, InstructionHandle new_target ) {
+ 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++) {
+ if (targets[j] == old_target) {
+ ((Select) b).setTarget(j, 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
+ */
+ public void redirectLocalVariables( LocalVariableGen[] lg, InstructionHandle old_target,
+ InstructionHandle new_target ) {
+ 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);
+ }
+ }
+ }
+
+
+ /**
+ * 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
+ */
+ public void redirectExceptionHandlers( CodeExceptionGen[] exceptions,
+ InstructionHandle old_target, InstructionHandle new_target ) {
+ 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);
+ }
+ }
+ }
+
+ private List observers;
+
+
+ /** Add observer for this object.
+ */
+ public void addObserver( InstructionListObserver o ) {
+ if (observers == null) {
+ observers = new ArrayList();
+ }
+ observers.add(o);
+ }
+
+
+ /** Remove observer for this object.
+ */
+ public void removeObserver( InstructionListObserver o ) {
+ if (observers != null) {
+ observers.remove(o);
+ }
+ }
+
+
+ /** 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.
+ */
+ public void update() {
+ if (observers != null) {
+ for (Iterator e = observers.iterator(); e.hasNext();) {
+ ((InstructionListObserver) e.next()).notify(this);
+ }
+ }
+ }
+}
Modified: jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionListObserver.java
URL: http://svn.apache.org/viewcvs/jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionListObserver.java?rev=386056&r1=386055&r2=386056&view=diff
==============================================================================
--- jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionListObserver.java (original)
+++ jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionListObserver.java Wed Mar 15 03:31:56 2006
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- */
+ */
package org.apache.bcel.generic;
-
/**
* Implement this interface if you're interested in changes to an InstructionList object
* and register yourself with addObserver().
@@ -25,6 +24,6 @@
* @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
*/
public interface InstructionListObserver {
- public void notify(InstructionList list);
-}
+ public void notify( InstructionList list );
+}
Modified: jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionTargeter.java
URL: http://svn.apache.org/viewcvs/jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionTargeter.java?rev=386056&r1=386055&r2=386056&view=diff
==============================================================================
--- jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionTargeter.java (original)
+++ jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionTargeter.java Wed Mar 15 03:31:56 2006
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- */
+ */
package org.apache.bcel.generic;
-
/**
* Denote that a class targets InstructionHandles within an InstructionList. Namely
* the following implementers:
@@ -28,6 +27,9 @@
* @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
*/
public interface InstructionTargeter {
- public boolean containsTarget(InstructionHandle ih);
- public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih);
+
+ public boolean containsTarget( InstructionHandle ih );
+
+
+ public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih );
}
Modified: jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InvokeInstruction.java
URL: http://svn.apache.org/viewcvs/jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InvokeInstruction.java?rev=386056&r1=386055&r2=386056&view=diff
==============================================================================
--- jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InvokeInstruction.java (original)
+++ jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InvokeInstruction.java Wed Mar 15 03:31:56 2006
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- */
+ */
package org.apache.bcel.generic;
import java.util.StringTokenizer;
@@ -27,84 +27,92 @@
* @version $Id$
* @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
*/
-public abstract class InvokeInstruction extends FieldOrMethod
- implements ExceptionThrower, TypedInstruction, StackConsumer, StackProducer {
- /**
- * Empty constructor needed for the Class.newInstance() statement in
- * Instruction.readInstruction(). Not to be used otherwise.
- */
- InvokeInstruction() {}
-
- /**
- * @param index to constant pool
- */
- protected InvokeInstruction(short opcode, int index) {
- super(opcode, index);
- }
-
- /**
- * @return mnemonic for instruction with symbolic references resolved
- */
- public String toString(ConstantPool cp) {
- Constant c = cp.getConstant(index);
- StringTokenizer tok = new StringTokenizer(cp.constantToString(c));
-
- return Constants.OPCODE_NAMES[opcode] + " " +
- tok.nextToken().replace('.', '/') + tok.nextToken();
- }
-
- /**
- * Also works for instructions whose stack effect depends on the
- * constant pool entry they reference.
- * @return Number of words consumed from stack by this instruction
- */
- public int consumeStack(ConstantPoolGen cpg) {
- String signature = getSignature(cpg);
- Type[] args = Type.getArgumentTypes(signature);
- int sum;
-
- if(opcode == Constants.INVOKESTATIC)
- sum = 0;
- else
- sum = 1; // this reference
-
- int n = args.length;
- for (int i = 0; i < n; i++)
- sum += args[i].getSize();
-
- return sum;
- }
-
- /**
- * Also works for instructions whose stack effect depends on the
- * constant pool entry they reference.
- * @return Number of words produced onto stack by this instruction
- */
- public int produceStack(ConstantPoolGen cpg) {
- return getReturnType(cpg).getSize();
- }
-
- /** @return return type of referenced method.
- */
- public Type getType(ConstantPoolGen cpg) {
- return getReturnType(cpg);
- }
-
- /** @return name of referenced method.
- */
- public String getMethodName(ConstantPoolGen cpg) {
- return getName(cpg);
- }
-
- /** @return return type of referenced method.
- */
- public Type getReturnType(ConstantPoolGen cpg) {
- return Type.getReturnType(getSignature(cpg));
- }
-
- /** @return argument types of referenced method.
- */
- public Type[] getArgumentTypes(ConstantPoolGen cpg) {
- return Type.getArgumentTypes(getSignature(cpg));
- }
+public abstract class InvokeInstruction extends FieldOrMethod implements ExceptionThrower,
+ TypedInstruction, StackConsumer, StackProducer {
+
+ /**
+ * Empty constructor needed for the Class.newInstance() statement in
+ * Instruction.readInstruction(). Not to be used otherwise.
+ */
+ InvokeInstruction() {
+ }
+
+
+ /**
+ * @param index to constant pool
+ */
+ protected InvokeInstruction(short opcode, int index) {
+ super(opcode, index);
+ }
+
+
+ /**
+ * @return mnemonic for instruction with symbolic references resolved
+ */
+ public String toString( ConstantPool cp ) {
+ Constant c = cp.getConstant(index);
+ StringTokenizer tok = new StringTokenizer(cp.constantToString(c));
+ return Constants.OPCODE_NAMES[opcode] + " " + tok.nextToken().replace('.', '/')
+ + tok.nextToken();
+ }
+
+
+ /**
+ * Also works for instructions whose stack effect depends on the
+ * constant pool entry they reference.
+ * @return Number of words consumed from stack by this instruction
+ */
+ public int consumeStack( ConstantPoolGen cpg ) {
+ String signature = getSignature(cpg);
+ Type[] args = Type.getArgumentTypes(signature);
+ int sum;
+ if (opcode == Constants.INVOKESTATIC) {
+ sum = 0;
+ } else {
+ sum = 1; // this reference
+ }
+ int n = args.length;
+ for (int i = 0; i < n; i++) {
+ sum += args[i].getSize();
+ }
+ return sum;
+ }
+
+
+ /**
+ * Also works for instructions whose stack effect depends on the
+ * constant pool entry they reference.
+ * @return Number of words produced onto stack by this instruction
+ */
+ public int produceStack( ConstantPoolGen cpg ) {
+ return getReturnType(cpg).getSize();
+ }
+
+
+ /** @return return type of referenced method.
+ */
+ public Type getType( ConstantPoolGen cpg ) {
+ return getReturnType(cpg);
+ }
+
+
+ /** @return name of referenced method.
+ */
+ public String getMethodName( ConstantPoolGen cpg ) {
+ return getName(cpg);
+ }
+
+
+ /** @return return type of referenced method.
+ */
+ public Type getReturnType( ConstantPoolGen cpg ) {
+ return Type.getReturnType(getSignature(cpg));
+ }
+
+
+ /** @return argument types of referenced method.
+ */
+ public Type[] getArgumentTypes( ConstantPoolGen cpg ) {
+ return Type.getArgumentTypes(getSignature(cpg));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: bcel-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: bcel-dev-help@jakarta.apache.org