diff options
Diffstat (limited to 'bcel-builder')
-rw-r--r-- | bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionBranch.java | 549 |
1 files changed, 273 insertions, 276 deletions
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionBranch.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionBranch.java index b63c2fe1d..0a5912247 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionBranch.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionBranch.java @@ -1,5 +1,3 @@ -package org.aspectj.apache.bcel.generic; - /* ==================================================================== * The Apache Software License, Version 1.1 * @@ -53,289 +51,288 @@ package org.aspectj.apache.bcel.generic; * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ +package org.aspectj.apache.bcel.generic; -import java.io.*; +import java.io.DataOutputStream; +import java.io.IOException; import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.ConstantPool; -/** - * Abstract super class for branching instructions like GOTO, IFEQ, etc.. - * Branch instructions may have a variable length, namely GOTO, JSR, - * LOOKUPSWITCH and TABLESWITCH. - * - * @see InstructionList - * @version $Id: InstructionBranch.java,v 1.4 2008/08/26 16:43:17 aclement Exp $ - * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> - */ /** - * A branch instruction may be talking in terms of absolute destination (targetIndex) or about an instruction it - * doesnt yet know the position if (targetInstruction). targetInstruction (if set) overrides targetIndex + * Abstract super class for branching instructions like GOTO, IFEQ, etc.. Branch instructions may have a variable length, namely + * GOTO, JSR, LOOKUPSWITCH and TABLESWITCH. A branch instruction may be talking in terms of absolute destination (targetIndex) or + * about an instruction it doesnt yet know the position if (targetInstruction). targetInstruction (if set) overrides targetIndex + * + * @see InstructionList + * @version $Id: InstructionBranch.java,v 1.5 2008/08/28 00:03:03 aclement Exp $ + * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> */ public class InstructionBranch extends Instruction implements InstructionTargeter { - private static final int UNSET = -1; - - protected int targetIndex = UNSET; // Branch target relative to this instruction - protected InstructionHandle targetInstruction; // Target object in instruction list - protected int positionOfThisInstruction; // for calculating relative branch destinations! - - - /** - * Constructor if building an instruction branch that targets a handle (ie. we don't need to actual targetIndex in the bytecode yet) - */ - public InstructionBranch(short opcode, InstructionHandle target) { -// if (opcode == GOTO ) System.err.println("building GOTO"); - this.opcode = opcode; - setTarget(target); - } - - public InstructionBranch(short opcode, int index) { -// if (opcode == GOTO ) System.err.println("targetIndex set to "+index); - this.opcode = opcode; - this.targetIndex = index; - } - - // used when we know nothing - public InstructionBranch(short opcode) { - this.opcode = opcode; - } - - public void dump(DataOutputStream out) throws IOException { - out.writeByte(opcode); - int target = getTargetOffset(); -// System.err.println("Writing out target for branch instruction "+getName()); - switch (opcode) { - case GOTO: -// System.err.println("Writing out target "+target); - out.writeShort(target); - break; - case GOTO_W: -// System.err.println("Writing out target "+target); - out.writeInt(target); - break; - - case IF_ACMPEQ: - case IF_ACMPNE: - case IF_ICMPEQ: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - case IF_ICMPLT: - case IF_ICMPNE: - case IFEQ: - case IFLE: - case IFLT: - case IFGT: - case IFNE: - case IFGE: - case IFNULL: - case IFNONNULL: - out.writeShort(target); - break; - - case JSR: - out.writeShort(target); - break; - case JSR_W: - out.writeInt(target); - break; - - default: - throw new IllegalStateException("Don't know how to write out "+getName().toUpperCase()); - } - - if(Math.abs(target) >= 32767) // too large for short - throw new ClassGenException("Branch target offset too large for short"); - } - - protected int getTargetOffset() { - if(targetInstruction == null && targetIndex==UNSET) - throw new ClassGenException("Target of " + super.toString(true) + " is unknown"); - - if (targetInstruction==null) { - return targetIndex; - } else { - return targetInstruction.getPosition()-positionOfThisInstruction; - } - } - - - /** - * Called by InstructionList.setPositions when setting the position for every - * instruction. In the presence of variable length instructions `setPositions' - * performs multiple passes over the instruction list to calculate the - * correct (byte) positions and offsets by calling this function. - * - * @param offset additional offset caused by preceding (variable length) instructions - * @param max_offset the maximum offset that may be caused by these instructions - * @return additional offset caused by possible change of this instruction's length - */ - protected int updatePosition(int offset, int max_offset) { - int i = getTargetOffset(); - - positionOfThisInstruction += offset; - - if (Math.abs(i)>=(32767-max_offset)) { // too large for short (we think) - throw new IllegalStateException("Unable to pack method, jump (with opcode="+opcode+") is too far: "+Math.abs(i)); - } - - return 0; - } - - /** - * Long output format: - * - * <position in byte code> - * <name of opcode> "["<opcode number>"]" - * "("<length of instruction>")" - * "<"<target instruction>">" "@"<branch target offset> - * - * @param verbose long/short format switch - * @return mnemonic for instruction - */ - public String toString(boolean verbose) { - String s = super.toString(verbose); - String t = "null"; - - if(verbose) { - if(targetInstruction != null) { - if(targetInstruction.getInstruction() == this) - t = "<points to itself>"; - else if(targetInstruction.getInstruction() == null) - t = "<null instruction!!!?>"; - else - t = targetInstruction.getInstruction().toString(false); // Avoid circles - } - } else { - if(targetInstruction != null) { - targetIndex = getTargetOffset(); - t = "" + (targetIndex + positionOfThisInstruction); - } - } - - return s + " -> " + t; - } - - - /** - * @return target offset in byte code - */ - public final int getIndex() { return targetIndex; } - - /** - * @return target of branch instruction - */ - public InstructionHandle getTarget() { return targetInstruction; } - - /** - * Set branch target - * @param target branch target - */ - public void setTarget(InstructionHandle target) { -// if (opcode==GOTO) System.err.println("Set target to "+target); - notifyTarget(this.targetInstruction, target, this); - this.targetInstruction = target; - } - - /** - * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen - */ - static final void notifyTarget(InstructionHandle old_ih, InstructionHandle new_ih, - InstructionTargeter t) { - if(old_ih != null) - old_ih.removeTargeter(t); - if(new_ih != null) - new_ih.addTargeter(t); - } - - /** - * @param old_ih old target - * @param new_ih new target - */ - public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { - if(targetInstruction == old_ih) - setTarget(new_ih); - else - throw new ClassGenException("Not targeting " + old_ih + ", but " + targetInstruction); - } - - /** - * @return true, if ih is target of this instruction - */ - public boolean containsTarget(InstructionHandle ih) { - return (targetInstruction == ih); - } - - /** - * Inform target that it's not targeted anymore. - */ - void dispose() { - setTarget(null); - targetIndex=-1; - positionOfThisInstruction=-1; - } - - // OPTIMIZE why bother with this? -// public InstructionBranch negate() { -// if ((Constants.instFlags[opcode]&Constants.NEGATABLE)==0) throw new IllegalStateException("Operation is not negatable"); -// switch (opcode) { -// case IFGT: return copy(Constants.IFNE); -// case IFLE: return copy(Constants.IFGT); -// default: -// throw new IllegalStateException("Dunno:"+opcode); -// } -// } -// -// private InstructionBranch copy(short opcode) { -// InstructionBranch ib = null; -// if (targetInstruction!=null) { -// ib = new InstructionBranch(opcode,targetInstruction); -// } else { -// ib = new InstructionBranch(opcode,targetIndex); -// } -// ib.positionOfThisInstruction = positionOfThisInstruction; -// return ib; -// } - public Type getType(ConstantPool cp) { - if ((Constants.instFlags[opcode]&Constants.JSR_INSTRUCTION)!=0) return new ReturnaddressType(physicalSuccessor()); - return super.getType(cp); - } - - /** - * Returns an InstructionHandle to the physical successor - * of this JsrInstruction. <B>For this method to work, - * this JsrInstruction object must not be shared between - * multiple InstructionHandle objects!</B> - * Formally, there must not be InstructionHandle objects - * i, j where i != j and i.getInstruction() == this == - * j.getInstruction(). - * @return an InstructionHandle to the "next" instruction that - * will be executed when RETurned from a subroutine. - */ - public InstructionHandle physicalSuccessor(){ - InstructionHandle ih = this.targetInstruction; - - // Rewind! - while(ih.getPrev() != null) - ih = ih.getPrev(); - - // Find the handle for "this" JsrInstruction object. - while(ih.getInstruction() != this) - ih = ih.getNext(); - - InstructionHandle toThis = ih; - - while(ih != null){ - ih = ih.getNext(); - if ((ih != null) && (ih.getInstruction() == this)) - throw new RuntimeException("physicalSuccessor() called on a shared JsrInstruction."); - } - - // Return the physical successor - return toThis.getNext(); - } + private static final int UNSET = -1; + + protected int targetIndex = UNSET; // Branch target relative to this + // instruction + protected InstructionHandle targetInstruction; // Target object in + // instruction list + protected int positionOfThisInstruction; // for calculating relative branch + + // destinations! + + public InstructionBranch(short opcode, InstructionHandle target) { + super(opcode); + setTarget(target); + } + + public InstructionBranch(short opcode, int index) { + super(opcode); + this.targetIndex = index; + } + + public InstructionBranch(short opcode) { + super(opcode); + } + + public void dump(DataOutputStream out) throws IOException { + int target = getTargetOffset(); + + if (Math.abs(target) >= 32767 && opcode != GOTO_W && opcode != JSR_W) { + throw new ClassGenException("Branch target offset too large for short. Instruction: " + getName().toUpperCase() + "(" + + opcode + ")"); + } + + out.writeByte(opcode); + + switch (opcode) { + + case GOTO_W: + case JSR_W: + out.writeInt(target); + break; + + case IF_ACMPEQ: + case IF_ACMPNE: + case IF_ICMPEQ: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ICMPLT: + case IF_ICMPNE: + case IFEQ: + case IFLE: + case IFLT: + case IFGT: + case IFNE: + case IFGE: + case IFNULL: + case IFNONNULL: + case GOTO: + case JSR: + out.writeShort(target); + break; + + default: + throw new IllegalStateException("Don't know how to write out " + getName().toUpperCase()); + } + + } + + protected int getTargetOffset() { + if (targetInstruction == null && targetIndex == UNSET) { + throw new ClassGenException("Target of " + super.toString(true) + " is unknown"); + } + + if (targetInstruction == null) { + return targetIndex; + } else { + return targetInstruction.getPosition() - positionOfThisInstruction; + } + } + + /** + * Called by InstructionList.setPositions when setting the position for every instruction. In the presence of variable length + * instructions `setPositions' performs multiple passes over the instruction list to calculate the correct (byte) positions and + * offsets by calling this function. + * + * @param offset additional offset caused by preceding (variable length) instructions + * @param max_offset the maximum offset that may be caused by these instructions + * @return additional offset caused by possible change of this instruction's length + */ + protected int updatePosition(int offset, int max_offset) { + int i = getTargetOffset(); + + positionOfThisInstruction += offset; + + if (Math.abs(i) >= 32767 - max_offset && opcode != JSR_W && opcode != GOTO_W) { + // Try and promote it to wide if we can + if (opcode == JSR || opcode == GOTO) { + if (opcode == JSR) { + opcode = JSR_W; + } else { + opcode = GOTO_W; + } + return 2; + } else { + throw new IllegalStateException("Unable to pack method, jump (with opcode=" + opcode + ") is too far: " + + Math.abs(i)); + } + } + + return 0; + } + + /** + * Long output format: + * + * @param verbose long/short format switch + * @return mnemonic for instruction + */ + public String toString(boolean verbose) { + String s = super.toString(verbose); + String t = "null"; + + if (verbose) { + if (targetInstruction != null) { + if (targetInstruction.getInstruction() == this) { + t = "<points to itself>"; + } else if (targetInstruction.getInstruction() == null) { + t = "<null destination>"; + } else { + t = targetInstruction.getInstruction().toString(false); + } + } + } else { + if (targetInstruction != null) { + targetIndex = getTargetOffset(); + t = "" + (targetIndex + positionOfThisInstruction); + } + } + + return s + " -> " + t; + } + + /** + * @return target offset in byte code + */ + public final int getIndex() { + return targetIndex; + } + + /** + * @return target of branch instruction + */ + public InstructionHandle getTarget() { + return targetInstruction; + } + + /** + * Set branch target + * + * @param target branch target + */ + public void setTarget(InstructionHandle target) { + notifyTarget(this.targetInstruction, target, this); + this.targetInstruction = target; + } + + /** + * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen + */ + static final void notifyTarget(InstructionHandle oldHandle, InstructionHandle newHandle, InstructionTargeter t) { + if (oldHandle != null) { + oldHandle.removeTargeter(t); + } + if (newHandle != null) { + newHandle.addTargeter(t); + } + } + + /** + * Update the target destination for this instruction. If an oldHandle is provided it is checked to verify that is where the + * target currently points to before changing it. + * + * @param oldHandle old target + * @param newHandle new target + */ + public void updateTarget(InstructionHandle oldHandle, InstructionHandle newHandle) { + if (targetInstruction == oldHandle) { + setTarget(newHandle); + } else { + throw new ClassGenException("Not targeting " + oldHandle + ", but " + targetInstruction); + } + } + + /** + * @return true, if ih is target of this instruction + */ + public boolean containsTarget(InstructionHandle ih) { + return targetInstruction == ih; + } + + /** + * Inform target that it's not targeted anymore. + */ + void dispose() { + setTarget(null); + targetIndex = -1; + positionOfThisInstruction = -1; + } + + public Type getType(ConstantPool cp) { + if ((Constants.instFlags[opcode] & Constants.JSR_INSTRUCTION) != 0) { + return new ReturnaddressType(physicalSuccessor()); + } + return super.getType(cp); + } + + /** + * Returns an InstructionHandle to the physical successor of this JsrInstruction. <B>For this method to work, this + * JsrInstruction object must not be shared between multiple InstructionHandle objects!</B> Formally, there must not be + * InstructionHandle objects i, j where i != j and i.getInstruction() == this == j.getInstruction(). + * + * @return an InstructionHandle to the "next" instruction that will be executed when RETurned from a subroutine. + */ + public InstructionHandle physicalSuccessor() { + InstructionHandle ih = this.targetInstruction; + + // Rewind! + while (ih.getPrev() != null) { + ih = ih.getPrev(); + } + + // Find the handle for "this" JsrInstruction object. + while (ih.getInstruction() != this) { + ih = ih.getNext(); + } + + InstructionHandle toThis = ih; + + while (ih != null) { + ih = ih.getNext(); + if (ih != null && ih.getInstruction() == this) { + throw new RuntimeException("physicalSuccessor() called on a shared JsrInstruction."); + } + } + + // Return the physical successor + return toThis.getNext(); + } public boolean isIfInstruction() { - return ((Constants.instFlags[opcode]&Constants.IF_INST)!=0); + return (Constants.instFlags[opcode] & Constants.IF_INST) != 0; + } + + /** + * Only equal if they are the same branch instruction - otherwise too risky as the targets may only temporarily be pointing at + * the same destination. + */ + public boolean equals(Object other) { + return this == other; + } + + public int hashCode() { + int result = 17; + result = opcode * 37 + result; + return result; } } |