]> source.dussan.org Git - aspectj.git/commitdiff
implemented equals/hashcode properly and fixed auto expansion to wide for big jumps
authoraclement <aclement>
Thu, 28 Aug 2008 00:03:03 +0000 (00:03 +0000)
committeraclement <aclement>
Thu, 28 Aug 2008 00:03:03 +0000 (00:03 +0000)
bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionBranch.java

index b63c2fe1dca809624a88af42ddb7bc1fc829fd7c..0a59122478d9a82c1d4e2463a32035461b159c1b 100644 (file)
@@ -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:
-   *
-   * &lt;position in byte code&gt;
-   * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" 
-   * "("&lt;length of instruction&gt;")"
-   * "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target offset&gt;
-   *
-   * @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;
        }
 }