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 [17/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/InstructionFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionFactory.java?rev=386056&r1=386055&r2=386056&view=diff
==============================================================================
--- jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionFactory.java (original)
+++ jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionFactory.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 org.apache.bcel.Constants;
@@ -28,558 +28,716 @@
  * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
  * @see Constants
  */
-public class InstructionFactory
-  implements InstructionConstants, java.io.Serializable
-{
-  protected ClassGen        cg;
-  protected ConstantPoolGen cp;
-
-  public InstructionFactory(ClassGen cg, ConstantPoolGen cp) {
-    this.cg = cg;
-    this.cp = cp;
-  }
-
-  /** Initialize with ClassGen object
-   */
-  public InstructionFactory(ClassGen cg) {
-    this(cg, cg.getConstantPool());
-  }
-
-  /** Initialize just with ConstantPoolGen object
-   */
-  public InstructionFactory(ConstantPoolGen cp) {
-    this(null, cp);
-  }
-
-  /** Create an invoke instruction.
-   *
-   * @param class_name name of the called class
-   * @param name name of the called method
-   * @param ret_type return type of method
-   * @param arg_types argument types of method
-   * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL,
-   * or INVOKESPECIAL
-   * @see Constants
-   */
-  public InvokeInstruction createInvoke(String class_name, String name, Type ret_type,
-					Type[] arg_types, short kind) {
-    int    index;
-    int    nargs      = 0;
-    String signature  = Type.getMethodSignature(ret_type, arg_types);
-
-    for(int i=0; i < arg_types.length; i++) // Count size of arguments
-      nargs += arg_types[i].getSize();
-
-    if(kind == Constants.INVOKEINTERFACE)
-      index = cp.addInterfaceMethodref(class_name, name, signature);
-    else
-      index = cp.addMethodref(class_name, name, signature);
-
-    switch(kind) {
-    case Constants.INVOKESPECIAL:   return new INVOKESPECIAL(index);
-    case Constants.INVOKEVIRTUAL:   return new INVOKEVIRTUAL(index);
-    case Constants.INVOKESTATIC:    return new INVOKESTATIC(index);
-    case Constants.INVOKEINTERFACE: return new INVOKEINTERFACE(index, nargs + 1);
-    default:
-      throw new RuntimeException("Oops: Unknown invoke kind:" + kind);
-    }
-  }
-
-  /** Create a call to the most popular System.out.println() method.
-   *
-   * @param s the string to print
-   */
-  public InstructionList createPrintln(String s) {
-    InstructionList il      = new InstructionList();
-    int             out     = cp.addFieldref("java.lang.System", "out",
-					     "Ljava/io/PrintStream;");
-    int             println = cp.addMethodref("java.io.PrintStream", "println",
-					      "(Ljava/lang/String;)V");
-
-    il.append(new GETSTATIC(out));
-    il.append(new PUSH(cp, s));
-    il.append(new INVOKEVIRTUAL(println));
-
-    return il;
-  }
-
-  /** Uses PUSH to push a constant value onto the stack.
-   * @param value must be of type Number, Boolean, Character or String
-   */
-  public Instruction createConstant(Object value) {
-    PUSH push;
-
-    if(value instanceof Number)
-      push = new PUSH(cp, (Number)value);
-    else if(value instanceof String)
-      push = new PUSH(cp, (String)value);
-    else if(value instanceof Boolean)
-      push = new PUSH(cp, (Boolean)value);
-    else if(value instanceof Character)
-      push = new PUSH(cp, (Character)value);
-    else
-      throw new ClassGenException("Illegal type: " + value.getClass());
-
-    return push.getInstruction();
-  }
-
-  private static class MethodObject {
-    Type[]   arg_types;
-    Type     result_type;
-    String   class_name;
-    String   name;
-    int      access;
-
-    MethodObject(String c, String n, Type r, Type[] a, int acc) {
-      class_name  = c;
-      name        = n;
-      result_type = r;
-      arg_types   = a;
-      access      = acc;
-    }
-  }
-
-  private InvokeInstruction createInvoke(MethodObject m, short kind) {
-    return createInvoke(m.class_name, m.name, m.result_type, m.arg_types, kind);
-  }
-
-  private static MethodObject[] append_mos = {
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
-		     new Type[] { Type.STRING }, Constants.ACC_PUBLIC),
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
-		     new Type[] { Type.OBJECT }, Constants.ACC_PUBLIC),
-    null, null, // indices 2, 3
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
-		     new Type[] { Type.BOOLEAN }, Constants.ACC_PUBLIC),
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
-		     new Type[] { Type.CHAR }, Constants.ACC_PUBLIC),
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
-		     new Type[] { Type.FLOAT }, Constants.ACC_PUBLIC),
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
-		     new Type[] { Type.DOUBLE }, Constants.ACC_PUBLIC),
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
-		     new Type[] { Type.INT }, Constants.ACC_PUBLIC),
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(byte)
-		     new Type[] { Type.INT }, Constants.ACC_PUBLIC),
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(short)
-		     new Type[] { Type.INT }, Constants.ACC_PUBLIC),
-    new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
-		     new Type[] { Type.LONG }, Constants.ACC_PUBLIC)    
-  };
-
-  private static final boolean isString(Type type) {
-    return ((type instanceof ObjectType) && 
-            ((ObjectType)type).getClassName().equals("java.lang.String"));
-  }
-
-  public Instruction createAppend(Type type) {
-    byte t = type.getType();
-
-    if(isString(type))
-      return createInvoke(append_mos[0], Constants.INVOKEVIRTUAL);
-
-    switch(t) {
-    case Constants.T_BOOLEAN:
-    case Constants.T_CHAR: 
-    case Constants.T_FLOAT:
-    case Constants.T_DOUBLE:
-    case Constants.T_BYTE:
-    case Constants.T_SHORT:
-    case Constants.T_INT:
-    case Constants.T_LONG
-      :   return createInvoke(append_mos[t], Constants.INVOKEVIRTUAL);
-    case Constants.T_ARRAY:
-    case Constants.T_OBJECT:
-      return createInvoke(append_mos[1], Constants.INVOKEVIRTUAL);
-    default:
-      throw new RuntimeException("Oops: No append for this type? " + type);
-    }
-  }
-
-  /** Create a field instruction.
-   *
-   * @param class_name name of the accessed class
-   * @param name name of the referenced field
-   * @param type  type of field
-   * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC
-   * @see Constants
-   */
-  public FieldInstruction createFieldAccess(String class_name, String name, Type type, short kind) {
-    int    index;
-    String signature  = type.getSignature();
-
-    index = cp.addFieldref(class_name, name, signature);
-
-    switch(kind) {
-    case Constants.GETFIELD:  return new GETFIELD(index);
-    case Constants.PUTFIELD:  return new PUTFIELD(index);
-    case Constants.GETSTATIC: return new GETSTATIC(index);
-    case Constants.PUTSTATIC: return new PUTSTATIC(index);
-
-    default:
-      throw new RuntimeException("Oops: Unknown getfield kind:" + kind);
-    }
-  }
-
-  /** Create reference to `this'
-   */
-  public static Instruction createThis() {
-    return new ALOAD(0);
-  }
-
-  /** Create typed return
-   */
-  public static ReturnInstruction createReturn(Type type) {
-    switch(type.getType()) {
-    case Constants.T_ARRAY:
-    case Constants.T_OBJECT:  return ARETURN;
-    case Constants.T_INT:
-    case Constants.T_SHORT:
-    case Constants.T_BOOLEAN:
-    case Constants.T_CHAR: 
-    case Constants.T_BYTE:    return IRETURN;
-    case Constants.T_FLOAT:   return FRETURN;
-    case Constants.T_DOUBLE:  return DRETURN;
-    case Constants.T_LONG:    return LRETURN;
-    case Constants.T_VOID:    return RETURN;
-
-    default:
-      throw new RuntimeException("Invalid type: " + type);
-    }
-  }
-  
-  private static final ArithmeticInstruction createBinaryIntOp(char first, String op) {
-    switch(first) {
-    case '-' : return ISUB;
-    case '+' : return IADD;
-    case '%' : return IREM;
-    case '*' : return IMUL;
-    case '/' : return IDIV;
-    case '&' : return IAND;
-    case '|' : return IOR;
-    case '^' : return IXOR;
-    case '<' : return ISHL;
-    case '>' : return op.equals(">>>")? (ArithmeticInstruction)IUSHR :
-      (ArithmeticInstruction)ISHR;
-    default: throw new RuntimeException("Invalid operand " + op);
-    }
-  }
-
-  private static final ArithmeticInstruction createBinaryLongOp(char first, String op) {
-    switch(first) {
-    case '-' : return LSUB;
-    case '+' : return LADD;
-    case '%' : return LREM;
-    case '*' : return LMUL;
-    case '/' : return LDIV;
-    case '&' : return LAND;
-    case '|' : return LOR;
-    case '^' : return LXOR;
-    case '<' : return LSHL;
-    case '>' : return op.equals(">>>")? (ArithmeticInstruction)LUSHR :
-      (ArithmeticInstruction)LSHR;
-    default: throw new RuntimeException("Invalid operand " + op);
-    }
-  }
-
-  private static final ArithmeticInstruction createBinaryFloatOp(char op) {
-    switch(op) {
-    case '-' : return FSUB;
-    case '+' : return FADD;
-    case '*' : return FMUL;
-    case '/' : return FDIV;
-    default: throw new RuntimeException("Invalid operand " + op);
-    }
-  }
-
-  private static final ArithmeticInstruction createBinaryDoubleOp(char op) {
-    switch(op) {
-    case '-' : return DSUB;
-    case '+' : return DADD;
-    case '*' : return DMUL;
-    case '/' : return DDIV;
-    default: throw new RuntimeException("Invalid operand " + op);
-    }
-  }
-
-  /**
-   * Create binary operation for simple basic types, such as int and float.
-   *
-   * @param op operation, such as "+", "*", "<<", etc.
-   */
-  public static ArithmeticInstruction createBinaryOperation(String op, Type type) {
-    char first = op.toCharArray()[0];
-
-    switch(type.getType()) {
-    case Constants.T_BYTE:
-    case Constants.T_SHORT:
-    case Constants.T_INT:
-    case Constants.T_CHAR:    return createBinaryIntOp(first, op);
-    case Constants.T_LONG:    return createBinaryLongOp(first, op);
-    case Constants.T_FLOAT:   return createBinaryFloatOp(first);
-    case Constants.T_DOUBLE:  return createBinaryDoubleOp(first);
-    default:        throw new RuntimeException("Invalid type " + type);
-    }
-  }
-
-  /**
-   * @param size size of operand, either 1 (int, e.g.) or 2 (double)
-   */
-  public static StackInstruction createPop(int size) {
-    return (size == 2)? (StackInstruction)POP2 :
-      (StackInstruction)POP;
-  }
-
-  /**
-   * @param size size of operand, either 1 (int, e.g.) or 2 (double)
-   */
-  public static StackInstruction createDup(int size) {
-    return (size == 2)? (StackInstruction)DUP2 :
-      (StackInstruction)DUP;
-  }
-
-  /**
-   * @param size size of operand, either 1 (int, e.g.) or 2 (double)
-   */
-  public static StackInstruction createDup_2(int size) {
-    return (size == 2)? (StackInstruction)DUP2_X2 :
-      (StackInstruction)DUP_X2;
-  }
-
-  /**
-   * @param size size of operand, either 1 (int, e.g.) or 2 (double)
-   */
-  public static StackInstruction createDup_1(int size) {
-    return (size == 2)? (StackInstruction)DUP2_X1 :
-      (StackInstruction)DUP_X1;
-  }
-
-  /**
-   * @param index index of local variable
-   */
-  public static LocalVariableInstruction createStore(Type type, int index) {
-    switch(type.getType()) {
-    case Constants.T_BOOLEAN:
-    case Constants.T_CHAR:
-    case Constants.T_BYTE:
-    case Constants.T_SHORT:
-    case Constants.T_INT:    return new ISTORE(index);
-    case Constants.T_FLOAT:  return new FSTORE(index);
-    case Constants.T_DOUBLE: return new DSTORE(index);
-    case Constants.T_LONG:   return new LSTORE(index);
-    case Constants.T_ARRAY:
-    case Constants.T_OBJECT: return new ASTORE(index);
-    default:       throw new RuntimeException("Invalid type " + type);
-    }
-  }
-
-  /**
-   * @param index index of local variable
-   */
-  public static LocalVariableInstruction createLoad(Type type, int index) {
-    switch(type.getType()) {
-    case Constants.T_BOOLEAN:
-    case Constants.T_CHAR:
-    case Constants.T_BYTE:
-    case Constants.T_SHORT:
-    case Constants.T_INT:    return new ILOAD(index);
-    case Constants.T_FLOAT:  return new FLOAD(index);
-    case Constants.T_DOUBLE: return new DLOAD(index);
-    case Constants.T_LONG:   return new LLOAD(index);
-    case Constants.T_ARRAY:
-    case Constants.T_OBJECT: return new ALOAD(index);
-    default:       throw new RuntimeException("Invalid type " + type);
-    }
-  }
-
-  /**
-   * @param type type of elements of array, i.e., array.getElementType()
-   */
-  public static ArrayInstruction createArrayLoad(Type type) {
-    switch(type.getType()) {
-    case Constants.T_BOOLEAN:
-    case Constants.T_BYTE:   return BALOAD;
-    case Constants.T_CHAR:   return CALOAD;
-    case Constants.T_SHORT:  return SALOAD;
-    case Constants.T_INT:    return IALOAD;
-    case Constants.T_FLOAT:  return FALOAD;
-    case Constants.T_DOUBLE: return DALOAD;
-    case Constants.T_LONG:   return LALOAD;
-    case Constants.T_ARRAY:
-    case Constants.T_OBJECT: return AALOAD;
-    default:       throw new RuntimeException("Invalid type " + type);
-    }
-  }
-
-  /**
-   * @param type type of elements of array, i.e., array.getElementType()
-   */
-  public static ArrayInstruction createArrayStore(Type type) {
-    switch(type.getType()) {
-    case Constants.T_BOOLEAN:
-    case Constants.T_BYTE:   return BASTORE;
-    case Constants.T_CHAR:   return CASTORE;
-    case Constants.T_SHORT:  return SASTORE;
-    case Constants.T_INT:    return IASTORE;
-    case Constants.T_FLOAT:  return FASTORE;
-    case Constants.T_DOUBLE: return DASTORE;
-    case Constants.T_LONG:   return LASTORE;
-    case Constants.T_ARRAY:
-    case Constants.T_OBJECT: return AASTORE;
-    default:       throw new RuntimeException("Invalid type " + type);
-    }
-  }
-
-
-  /** Create conversion operation for two stack operands, this may be an I2C, instruction, e.g.,
-   * if the operands are basic types and CHECKCAST if they are reference types.
-   */
-  public Instruction createCast(Type src_type, Type dest_type) {
-    if((src_type instanceof BasicType) && (dest_type instanceof BasicType)) {
-      byte dest = dest_type.getType();
-      byte src  = src_type.getType();
-
-      if(dest == Constants.T_LONG && (src == Constants.T_CHAR || src == Constants.T_BYTE ||
-				      src == Constants.T_SHORT))
-	src = Constants.T_INT;
-
-      String[] short_names = { "C", "F", "D", "B", "S", "I", "L" };
-
-      String name = "org.apache.bcel.generic." + short_names[src - Constants.T_CHAR] +
-	"2" + short_names[dest - Constants.T_CHAR];
-      
-      Instruction i = null;
-      try {
-	i = (Instruction)java.lang.Class.forName(name).newInstance();
-      } catch(Exception e) {
-	throw new RuntimeException("Could not find instruction: " + name);
-      }
-
-      return i;
-    } else if((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) {
-      if(dest_type instanceof ArrayType)
-	return new CHECKCAST(cp.addArrayClass((ArrayType)dest_type));
-      else
-	return new CHECKCAST(cp.addClass(((ObjectType)dest_type).getClassName()));
-    }
-    else
-      throw new RuntimeException("Can not cast " + src_type + " to " + dest_type);
-  }
-
-  public GETFIELD createGetField(String class_name, String name, Type t) {
-    return new GETFIELD(cp.addFieldref(class_name, name, t.getSignature()));
-  }
-
-  public GETSTATIC createGetStatic(String class_name, String name, Type t) {
-    return new GETSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
-  }
-
-  public PUTFIELD createPutField(String class_name, String name, Type t) {
-    return new PUTFIELD(cp.addFieldref(class_name, name, t.getSignature()));
-  }
-
-  public PUTSTATIC createPutStatic(String class_name, String name, Type t) {
-    return new PUTSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
-  }
-
-  public CHECKCAST createCheckCast(ReferenceType t) {
-    if(t instanceof ArrayType)
-      return new CHECKCAST(cp.addArrayClass((ArrayType)t));
-    else
-      return new CHECKCAST(cp.addClass((ObjectType)t));
-  }
-
-  public INSTANCEOF createInstanceOf(ReferenceType t) {
-    if(t instanceof ArrayType)
-      return new INSTANCEOF(cp.addArrayClass((ArrayType)t));
-    else
-      return new INSTANCEOF(cp.addClass((ObjectType)t));
-  }
-
-  public NEW createNew(ObjectType t) {
-    return new NEW(cp.addClass(t));
-  }
-
-  public NEW createNew(String s) {
-    return createNew(new ObjectType(s));
-  }
-
-  /** Create new array of given size and type.
-   * @return an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction
-   */
-  public Instruction createNewArray(Type t, short dim) {
-    if(dim == 1) {
-      if(t instanceof ObjectType)
-	return new ANEWARRAY(cp.addClass((ObjectType)t));
-      else if(t instanceof ArrayType)
-	return new ANEWARRAY(cp.addArrayClass((ArrayType)t));
-      else
-	return new NEWARRAY(((BasicType)t).getType());
-    } else {
-      ArrayType at;
-
-      if(t instanceof ArrayType)
-	at = (ArrayType)t;
-      else
-	at = new ArrayType(t, dim);
-
-      return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
-    }
-  }
-
-  /** Create "null" value for reference types, 0 for basic types like int
-   */
-  public static Instruction createNull(Type type) {
-    switch(type.getType()) {
-    case Constants.T_ARRAY:
-    case Constants.T_OBJECT:  return ACONST_NULL;
-    case Constants.T_INT:
-    case Constants.T_SHORT:
-    case Constants.T_BOOLEAN:
-    case Constants.T_CHAR: 
-    case Constants.T_BYTE:    return ICONST_0;
-    case Constants.T_FLOAT:   return FCONST_0;
-    case Constants.T_DOUBLE:  return DCONST_0;
-    case Constants.T_LONG:    return LCONST_0;
-    case Constants.T_VOID:    return NOP;
-
-    default:
-      throw new RuntimeException("Invalid type: " + type);
-    }
-  }
-
-  /** Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH.
-   * For those you should use the SWITCH compound instruction.
-   */
-  public static BranchInstruction createBranchInstruction(short opcode, InstructionHandle target) {
-    switch(opcode) {
-    case Constants.IFEQ:      return new IFEQ(target);
-    case Constants.IFNE:      return new IFNE(target);
-    case Constants.IFLT:      return new IFLT(target);
-    case Constants.IFGE:      return new IFGE(target);
-    case Constants.IFGT:      return new IFGT(target);
-    case Constants.IFLE:      return new IFLE(target);
-    case Constants.IF_ICMPEQ: return new IF_ICMPEQ(target);
-    case Constants.IF_ICMPNE: return new IF_ICMPNE(target);
-    case Constants.IF_ICMPLT: return new IF_ICMPLT(target);
-    case Constants.IF_ICMPGE: return new IF_ICMPGE(target);
-    case Constants.IF_ICMPGT: return new IF_ICMPGT(target);
-    case Constants.IF_ICMPLE: return new IF_ICMPLE(target);
-    case Constants.IF_ACMPEQ: return new IF_ACMPEQ(target);
-    case Constants.IF_ACMPNE: return new IF_ACMPNE(target);
-    case Constants.GOTO:      return new GOTO(target);
-    case Constants.JSR:       return new JSR(target);
-    case Constants.IFNULL:    return new IFNULL(target);
-    case Constants.IFNONNULL: return new IFNONNULL(target);
-    case Constants.GOTO_W:    return new GOTO_W(target);
-    case Constants.JSR_W:     return new JSR_W(target);
-    default:
-	throw new RuntimeException("Invalid opcode: " + opcode);
-    }
-  }
-
-  public void            setClassGen(ClassGen c)            { cg = c; }
-  public ClassGen        getClassGen()                      { return cg; }
-  public void            setConstantPool(ConstantPoolGen c) { cp = c; }
-  public ConstantPoolGen getConstantPool()                  { return cp; }
+public class InstructionFactory implements InstructionConstants, java.io.Serializable {
+
+    protected ClassGen cg;
+    protected ConstantPoolGen cp;
+
+
+    public InstructionFactory(ClassGen cg, ConstantPoolGen cp) {
+        this.cg = cg;
+        this.cp = cp;
+    }
+
+
+    /** Initialize with ClassGen object
+     */
+    public InstructionFactory(ClassGen cg) {
+        this(cg, cg.getConstantPool());
+    }
+
+
+    /** Initialize just with ConstantPoolGen object
+     */
+    public InstructionFactory(ConstantPoolGen cp) {
+        this(null, cp);
+    }
+
+
+    /** Create an invoke instruction.
+     *
+     * @param class_name name of the called class
+     * @param name name of the called method
+     * @param ret_type return type of method
+     * @param arg_types argument types of method
+     * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL,
+     * or INVOKESPECIAL
+     * @see Constants
+     */
+    public InvokeInstruction createInvoke( String class_name, String name, Type ret_type,
+            Type[] arg_types, short kind ) {
+        int index;
+        int nargs = 0;
+        String signature = Type.getMethodSignature(ret_type, arg_types);
+        for (int i = 0; i < arg_types.length; i++) {
+            nargs += arg_types[i].getSize();
+        }
+        if (kind == Constants.INVOKEINTERFACE) {
+            index = cp.addInterfaceMethodref(class_name, name, signature);
+        } else {
+            index = cp.addMethodref(class_name, name, signature);
+        }
+        switch (kind) {
+            case Constants.INVOKESPECIAL:
+                return new INVOKESPECIAL(index);
+            case Constants.INVOKEVIRTUAL:
+                return new INVOKEVIRTUAL(index);
+            case Constants.INVOKESTATIC:
+                return new INVOKESTATIC(index);
+            case Constants.INVOKEINTERFACE:
+                return new INVOKEINTERFACE(index, nargs + 1);
+            default:
+                throw new RuntimeException("Oops: Unknown invoke kind:" + kind);
+        }
+    }
+
+
+    /** Create a call to the most popular System.out.println() method.
+     *
+     * @param s the string to print
+     */
+    public InstructionList createPrintln( String s ) {
+        InstructionList il = new InstructionList();
+        int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;");
+        int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V");
+        il.append(new GETSTATIC(out));
+        il.append(new PUSH(cp, s));
+        il.append(new INVOKEVIRTUAL(println));
+        return il;
+    }
+
+
+    /** Uses PUSH to push a constant value onto the stack.
+     * @param value must be of type Number, Boolean, Character or String
+     */
+    public Instruction createConstant( Object value ) {
+        PUSH push;
+        if (value instanceof Number) {
+            push = new PUSH(cp, (Number) value);
+        } else if (value instanceof String) {
+            push = new PUSH(cp, (String) value);
+        } else if (value instanceof Boolean) {
+            push = new PUSH(cp, (Boolean) value);
+        } else if (value instanceof Character) {
+            push = new PUSH(cp, (Character) value);
+        } else {
+            throw new ClassGenException("Illegal type: " + value.getClass());
+        }
+        return push.getInstruction();
+    }
+
+    private static class MethodObject {
+
+        Type[] arg_types;
+        Type result_type;
+        String class_name;
+        String name;
+        int access;
+
+
+        MethodObject(String c, String n, Type r, Type[] a, int acc) {
+            class_name = c;
+            name = n;
+            result_type = r;
+            arg_types = a;
+            access = acc;
+        }
+    }
+
+
+    private InvokeInstruction createInvoke( MethodObject m, short kind ) {
+        return createInvoke(m.class_name, m.name, m.result_type, m.arg_types, kind);
+    }
+
+    private static MethodObject[] append_mos = {
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
+                Type.STRING
+            }, Constants.ACC_PUBLIC),
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
+                Type.OBJECT
+            }, Constants.ACC_PUBLIC),
+            null,
+            null, // indices 2, 3
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
+                Type.BOOLEAN
+            }, Constants.ACC_PUBLIC),
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
+                Type.CHAR
+            }, Constants.ACC_PUBLIC),
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
+                Type.FLOAT
+            }, Constants.ACC_PUBLIC),
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
+                Type.DOUBLE
+            }, Constants.ACC_PUBLIC),
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
+                Type.INT
+            }, Constants.ACC_PUBLIC),
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(byte)
+                    new Type[] {
+                        Type.INT
+                    }, Constants.ACC_PUBLIC),
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(short)
+                    new Type[] {
+                        Type.INT
+                    }, Constants.ACC_PUBLIC),
+            new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
+                Type.LONG
+            }, Constants.ACC_PUBLIC)
+    };
+
+
+    private static final boolean isString( Type type ) {
+        return ((type instanceof ObjectType) && ((ObjectType) type).getClassName().equals(
+                "java.lang.String"));
+    }
+
+
+    public Instruction createAppend( Type type ) {
+        byte t = type.getType();
+        if (isString(type)) {
+            return createInvoke(append_mos[0], Constants.INVOKEVIRTUAL);
+        }
+        switch (t) {
+            case Constants.T_BOOLEAN:
+            case Constants.T_CHAR:
+            case Constants.T_FLOAT:
+            case Constants.T_DOUBLE:
+            case Constants.T_BYTE:
+            case Constants.T_SHORT:
+            case Constants.T_INT:
+            case Constants.T_LONG:
+                return createInvoke(append_mos[t], Constants.INVOKEVIRTUAL);
+            case Constants.T_ARRAY:
+            case Constants.T_OBJECT:
+                return createInvoke(append_mos[1], Constants.INVOKEVIRTUAL);
+            default:
+                throw new RuntimeException("Oops: No append for this type? " + type);
+        }
+    }
+
+
+    /** Create a field instruction.
+     *
+     * @param class_name name of the accessed class
+     * @param name name of the referenced field
+     * @param type  type of field
+     * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC
+     * @see Constants
+     */
+    public FieldInstruction createFieldAccess( String class_name, String name, Type type, short kind ) {
+        int index;
+        String signature = type.getSignature();
+        index = cp.addFieldref(class_name, name, signature);
+        switch (kind) {
+            case Constants.GETFIELD:
+                return new GETFIELD(index);
+            case Constants.PUTFIELD:
+                return new PUTFIELD(index);
+            case Constants.GETSTATIC:
+                return new GETSTATIC(index);
+            case Constants.PUTSTATIC:
+                return new PUTSTATIC(index);
+            default:
+                throw new RuntimeException("Oops: Unknown getfield kind:" + kind);
+        }
+    }
+
+
+    /** Create reference to `this'
+     */
+    public static Instruction createThis() {
+        return new ALOAD(0);
+    }
+
+
+    /** Create typed return
+     */
+    public static ReturnInstruction createReturn( Type type ) {
+        switch (type.getType()) {
+            case Constants.T_ARRAY:
+            case Constants.T_OBJECT:
+                return ARETURN;
+            case Constants.T_INT:
+            case Constants.T_SHORT:
+            case Constants.T_BOOLEAN:
+            case Constants.T_CHAR:
+            case Constants.T_BYTE:
+                return IRETURN;
+            case Constants.T_FLOAT:
+                return FRETURN;
+            case Constants.T_DOUBLE:
+                return DRETURN;
+            case Constants.T_LONG:
+                return LRETURN;
+            case Constants.T_VOID:
+                return RETURN;
+            default:
+                throw new RuntimeException("Invalid type: " + type);
+        }
+    }
+
+
+    private static final ArithmeticInstruction createBinaryIntOp( char first, String op ) {
+        switch (first) {
+            case '-':
+                return ISUB;
+            case '+':
+                return IADD;
+            case '%':
+                return IREM;
+            case '*':
+                return IMUL;
+            case '/':
+                return IDIV;
+            case '&':
+                return IAND;
+            case '|':
+                return IOR;
+            case '^':
+                return IXOR;
+            case '<':
+                return ISHL;
+            case '>':
+                return op.equals(">>>")
+                        ? (ArithmeticInstruction) IUSHR
+                        : (ArithmeticInstruction) ISHR;
+            default:
+                throw new RuntimeException("Invalid operand " + op);
+        }
+    }
+
+
+    private static final ArithmeticInstruction createBinaryLongOp( char first, String op ) {
+        switch (first) {
+            case '-':
+                return LSUB;
+            case '+':
+                return LADD;
+            case '%':
+                return LREM;
+            case '*':
+                return LMUL;
+            case '/':
+                return LDIV;
+            case '&':
+                return LAND;
+            case '|':
+                return LOR;
+            case '^':
+                return LXOR;
+            case '<':
+                return LSHL;
+            case '>':
+                return op.equals(">>>")
+                        ? (ArithmeticInstruction) LUSHR
+                        : (ArithmeticInstruction) LSHR;
+            default:
+                throw new RuntimeException("Invalid operand " + op);
+        }
+    }
+
+
+    private static final ArithmeticInstruction createBinaryFloatOp( char op ) {
+        switch (op) {
+            case '-':
+                return FSUB;
+            case '+':
+                return FADD;
+            case '*':
+                return FMUL;
+            case '/':
+                return FDIV;
+            default:
+                throw new RuntimeException("Invalid operand " + op);
+        }
+    }
+
+
+    private static final ArithmeticInstruction createBinaryDoubleOp( char op ) {
+        switch (op) {
+            case '-':
+                return DSUB;
+            case '+':
+                return DADD;
+            case '*':
+                return DMUL;
+            case '/':
+                return DDIV;
+            default:
+                throw new RuntimeException("Invalid operand " + op);
+        }
+    }
+
+
+    /**
+     * Create binary operation for simple basic types, such as int and float.
+     *
+     * @param op operation, such as "+", "*", "<<", etc.
+     */
+    public static ArithmeticInstruction createBinaryOperation( String op, Type type ) {
+        char first = op.toCharArray()[0];
+        switch (type.getType()) {
+            case Constants.T_BYTE:
+            case Constants.T_SHORT:
+            case Constants.T_INT:
+            case Constants.T_CHAR:
+                return createBinaryIntOp(first, op);
+            case Constants.T_LONG:
+                return createBinaryLongOp(first, op);
+            case Constants.T_FLOAT:
+                return createBinaryFloatOp(first);
+            case Constants.T_DOUBLE:
+                return createBinaryDoubleOp(first);
+            default:
+                throw new RuntimeException("Invalid type " + type);
+        }
+    }
+
+
+    /**
+     * @param size size of operand, either 1 (int, e.g.) or 2 (double)
+     */
+    public static StackInstruction createPop( int size ) {
+        return (size == 2) ? (StackInstruction) POP2 : (StackInstruction) POP;
+    }
+
+
+    /**
+     * @param size size of operand, either 1 (int, e.g.) or 2 (double)
+     */
+    public static StackInstruction createDup( int size ) {
+        return (size == 2) ? (StackInstruction) DUP2 : (StackInstruction) DUP;
+    }
+
+
+    /**
+     * @param size size of operand, either 1 (int, e.g.) or 2 (double)
+     */
+    public static StackInstruction createDup_2( int size ) {
+        return (size == 2) ? (StackInstruction) DUP2_X2 : (StackInstruction) DUP_X2;
+    }
+
+
+    /**
+     * @param size size of operand, either 1 (int, e.g.) or 2 (double)
+     */
+    public static StackInstruction createDup_1( int size ) {
+        return (size == 2) ? (StackInstruction) DUP2_X1 : (StackInstruction) DUP_X1;
+    }
+
+
+    /**
+     * @param index index of local variable
+     */
+    public static LocalVariableInstruction createStore( Type type, int index ) {
+        switch (type.getType()) {
+            case Constants.T_BOOLEAN:
+            case Constants.T_CHAR:
+            case Constants.T_BYTE:
+            case Constants.T_SHORT:
+            case Constants.T_INT:
+                return new ISTORE(index);
+            case Constants.T_FLOAT:
+                return new FSTORE(index);
+            case Constants.T_DOUBLE:
+                return new DSTORE(index);
+            case Constants.T_LONG:
+                return new LSTORE(index);
+            case Constants.T_ARRAY:
+            case Constants.T_OBJECT:
+                return new ASTORE(index);
+            default:
+                throw new RuntimeException("Invalid type " + type);
+        }
+    }
+
+
+    /**
+     * @param index index of local variable
+     */
+    public static LocalVariableInstruction createLoad( Type type, int index ) {
+        switch (type.getType()) {
+            case Constants.T_BOOLEAN:
+            case Constants.T_CHAR:
+            case Constants.T_BYTE:
+            case Constants.T_SHORT:
+            case Constants.T_INT:
+                return new ILOAD(index);
+            case Constants.T_FLOAT:
+                return new FLOAD(index);
+            case Constants.T_DOUBLE:
+                return new DLOAD(index);
+            case Constants.T_LONG:
+                return new LLOAD(index);
+            case Constants.T_ARRAY:
+            case Constants.T_OBJECT:
+                return new ALOAD(index);
+            default:
+                throw new RuntimeException("Invalid type " + type);
+        }
+    }
+
+
+    /**
+     * @param type type of elements of array, i.e., array.getElementType()
+     */
+    public static ArrayInstruction createArrayLoad( Type type ) {
+        switch (type.getType()) {
+            case Constants.T_BOOLEAN:
+            case Constants.T_BYTE:
+                return BALOAD;
+            case Constants.T_CHAR:
+                return CALOAD;
+            case Constants.T_SHORT:
+                return SALOAD;
+            case Constants.T_INT:
+                return IALOAD;
+            case Constants.T_FLOAT:
+                return FALOAD;
+            case Constants.T_DOUBLE:
+                return DALOAD;
+            case Constants.T_LONG:
+                return LALOAD;
+            case Constants.T_ARRAY:
+            case Constants.T_OBJECT:
+                return AALOAD;
+            default:
+                throw new RuntimeException("Invalid type " + type);
+        }
+    }
+
+
+    /**
+     * @param type type of elements of array, i.e., array.getElementType()
+     */
+    public static ArrayInstruction createArrayStore( Type type ) {
+        switch (type.getType()) {
+            case Constants.T_BOOLEAN:
+            case Constants.T_BYTE:
+                return BASTORE;
+            case Constants.T_CHAR:
+                return CASTORE;
+            case Constants.T_SHORT:
+                return SASTORE;
+            case Constants.T_INT:
+                return IASTORE;
+            case Constants.T_FLOAT:
+                return FASTORE;
+            case Constants.T_DOUBLE:
+                return DASTORE;
+            case Constants.T_LONG:
+                return LASTORE;
+            case Constants.T_ARRAY:
+            case Constants.T_OBJECT:
+                return AASTORE;
+            default:
+                throw new RuntimeException("Invalid type " + type);
+        }
+    }
+
+
+    /** Create conversion operation for two stack operands, this may be an I2C, instruction, e.g.,
+     * if the operands are basic types and CHECKCAST if they are reference types.
+     */
+    public Instruction createCast( Type src_type, Type dest_type ) {
+        if ((src_type instanceof BasicType) && (dest_type instanceof BasicType)) {
+            byte dest = dest_type.getType();
+            byte src = src_type.getType();
+            if (dest == Constants.T_LONG
+                    && (src == Constants.T_CHAR || src == Constants.T_BYTE || src == Constants.T_SHORT)) {
+                src = Constants.T_INT;
+            }
+            String[] short_names = {
+                    "C", "F", "D", "B", "S", "I", "L"
+            };
+            String name = "org.apache.bcel.generic." + short_names[src - Constants.T_CHAR] + "2"
+                    + short_names[dest - Constants.T_CHAR];
+            Instruction i = null;
+            try {
+                i = (Instruction) java.lang.Class.forName(name).newInstance();
+            } catch (Exception e) {
+                throw new RuntimeException("Could not find instruction: " + name);
+            }
+            return i;
+        } else if ((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) {
+            if (dest_type instanceof ArrayType) {
+                return new CHECKCAST(cp.addArrayClass((ArrayType) dest_type));
+            } else {
+                return new CHECKCAST(cp.addClass(((ObjectType) dest_type).getClassName()));
+            }
+        } else {
+            throw new RuntimeException("Can not cast " + src_type + " to " + dest_type);
+        }
+    }
+
+
+    public GETFIELD createGetField( String class_name, String name, Type t ) {
+        return new GETFIELD(cp.addFieldref(class_name, name, t.getSignature()));
+    }
+
+
+    public GETSTATIC createGetStatic( String class_name, String name, Type t ) {
+        return new GETSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
+    }
+
+
+    public PUTFIELD createPutField( String class_name, String name, Type t ) {
+        return new PUTFIELD(cp.addFieldref(class_name, name, t.getSignature()));
+    }
+
+
+    public PUTSTATIC createPutStatic( String class_name, String name, Type t ) {
+        return new PUTSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
+    }
+
+
+    public CHECKCAST createCheckCast( ReferenceType t ) {
+        if (t instanceof ArrayType) {
+            return new CHECKCAST(cp.addArrayClass((ArrayType) t));
+        } else {
+            return new CHECKCAST(cp.addClass((ObjectType) t));
+        }
+    }
+
+
+    public INSTANCEOF createInstanceOf( ReferenceType t ) {
+        if (t instanceof ArrayType) {
+            return new INSTANCEOF(cp.addArrayClass((ArrayType) t));
+        } else {
+            return new INSTANCEOF(cp.addClass((ObjectType) t));
+        }
+    }
+
+
+    public NEW createNew( ObjectType t ) {
+        return new NEW(cp.addClass(t));
+    }
+
+
+    public NEW createNew( String s ) {
+        return createNew(new ObjectType(s));
+    }
+
+
+    /** Create new array of given size and type.
+     * @return an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction
+     */
+    public Instruction createNewArray( Type t, short dim ) {
+        if (dim == 1) {
+            if (t instanceof ObjectType) {
+                return new ANEWARRAY(cp.addClass((ObjectType) t));
+            } else if (t instanceof ArrayType) {
+                return new ANEWARRAY(cp.addArrayClass((ArrayType) t));
+            } else {
+                return new NEWARRAY(((BasicType) t).getType());
+            }
+        } else {
+            ArrayType at;
+            if (t instanceof ArrayType) {
+                at = (ArrayType) t;
+            } else {
+                at = new ArrayType(t, dim);
+            }
+            return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
+        }
+    }
+
+
+    /** Create "null" value for reference types, 0 for basic types like int
+     */
+    public static Instruction createNull( Type type ) {
+        switch (type.getType()) {
+            case Constants.T_ARRAY:
+            case Constants.T_OBJECT:
+                return ACONST_NULL;
+            case Constants.T_INT:
+            case Constants.T_SHORT:
+            case Constants.T_BOOLEAN:
+            case Constants.T_CHAR:
+            case Constants.T_BYTE:
+                return ICONST_0;
+            case Constants.T_FLOAT:
+                return FCONST_0;
+            case Constants.T_DOUBLE:
+                return DCONST_0;
+            case Constants.T_LONG:
+                return LCONST_0;
+            case Constants.T_VOID:
+                return NOP;
+            default:
+                throw new RuntimeException("Invalid type: " + type);
+        }
+    }
+
+
+    /** Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH.
+     * For those you should use the SWITCH compound instruction.
+     */
+    public static BranchInstruction createBranchInstruction( short opcode, InstructionHandle target ) {
+        switch (opcode) {
+            case Constants.IFEQ:
+                return new IFEQ(target);
+            case Constants.IFNE:
+                return new IFNE(target);
+            case Constants.IFLT:
+                return new IFLT(target);
+            case Constants.IFGE:
+                return new IFGE(target);
+            case Constants.IFGT:
+                return new IFGT(target);
+            case Constants.IFLE:
+                return new IFLE(target);
+            case Constants.IF_ICMPEQ:
+                return new IF_ICMPEQ(target);
+            case Constants.IF_ICMPNE:
+                return new IF_ICMPNE(target);
+            case Constants.IF_ICMPLT:
+                return new IF_ICMPLT(target);
+            case Constants.IF_ICMPGE:
+                return new IF_ICMPGE(target);
+            case Constants.IF_ICMPGT:
+                return new IF_ICMPGT(target);
+            case Constants.IF_ICMPLE:
+                return new IF_ICMPLE(target);
+            case Constants.IF_ACMPEQ:
+                return new IF_ACMPEQ(target);
+            case Constants.IF_ACMPNE:
+                return new IF_ACMPNE(target);
+            case Constants.GOTO:
+                return new GOTO(target);
+            case Constants.JSR:
+                return new JSR(target);
+            case Constants.IFNULL:
+                return new IFNULL(target);
+            case Constants.IFNONNULL:
+                return new IFNONNULL(target);
+            case Constants.GOTO_W:
+                return new GOTO_W(target);
+            case Constants.JSR_W:
+                return new JSR_W(target);
+            default:
+                throw new RuntimeException("Invalid opcode: " + opcode);
+        }
+    }
+
+
+    public void setClassGen( ClassGen c ) {
+        cg = c;
+    }
+
+
+    public ClassGen getClassGen() {
+        return cg;
+    }
+
+
+    public void setConstantPool( ConstantPoolGen c ) {
+        cp = c;
+    }
+
+
+    public ConstantPoolGen getConstantPool() {
+        return cp;
+    }
 }

Modified: jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionHandle.java
URL: http://svn.apache.org/viewcvs/jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionHandle.java?rev=386056&r1=386055&r2=386056&view=diff
==============================================================================
--- jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionHandle.java (original)
+++ jakarta/bcel/trunk/src/java/org/apache/bcel/generic/InstructionHandle.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.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -43,212 +42,249 @@
  * @see InstructionList 
  */
 public class InstructionHandle implements java.io.Serializable {
-  InstructionHandle next, prev;  // Will be set from the outside
-  Instruction       instruction;
-  protected int     i_position = -1; // byte code offset of instruction
-  private Set       targeters;
-  private Map       attributes;
-
-  public final InstructionHandle getNext()        { return next; }
-  public final InstructionHandle getPrev()        { return prev; }
-  public final Instruction       getInstruction() { return instruction; }
-
-  /**
-   * Replace current instruction contained in this handle.
-   * Old instruction is disposed using Instruction.dispose().
-   */
-  public void setInstruction(Instruction i) { // Overridden in BranchHandle
-    if(i == null)
-      throw new ClassGenException("Assigning null to handle");
-
-    if((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction))
-      throw new ClassGenException("Assigning branch instruction " + i + " to plain handle");
-
-    if(instruction != null)
-      instruction.dispose();
-
-    instruction = i;
-  }
-
-  /**
-   * Temporarily swap the current instruction, without disturbing
-   * anything. Meant to be used by a debugger, implementing
-   * breakpoints. Current instruction is returned.
-   */
-  public Instruction swapInstruction(Instruction i) {
-    Instruction oldInstruction = instruction;
-    instruction = i;
-    return oldInstruction;
-  }
-
-  /*private*/ protected InstructionHandle(Instruction i) {
-    setInstruction(i);
-  }
-
-  private static InstructionHandle ih_list = null; // List of reusable handles
-
-  /** Factory method.
-   */
-  static final InstructionHandle getInstructionHandle(Instruction i) {
-    if(ih_list == null)
-      return new InstructionHandle(i);
-    else {
-      InstructionHandle ih = ih_list;
-      ih_list = ih.next;
-
-      ih.setInstruction(i);
-
-      return ih;
-    }
-  }
-
-  /**
-   * 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) {
-    i_position += offset;
-    return 0;
-  }
-
-  /** @return the position, i.e., the byte code offset of the contained
-   * instruction. This is accurate only after
-   * InstructionList.setPositions() has been called.
-   */
-  public int getPosition() { return i_position; }
-
-  /** Set the position, i.e., the byte code offset of the contained
-   * instruction.
-   */
-  void setPosition(int pos) { i_position = pos; }
-
-  /** Overridden in BranchHandle
-   */
-  protected void addHandle() {
-    next    = ih_list;
-    ih_list = this;
-  }
-
-  /**
-   * Delete contents, i.e., remove user access and make handle reusable.
-   */
-  void dispose() {
-    next = prev = null;
-    instruction.dispose();
-    instruction = null;
-    i_position = -1;
-    attributes = null;
-    removeAllTargeters();
-    addHandle();
-  }
-
-  /** Remove all targeters, if any.
-   */
-  public void removeAllTargeters() {
-    if(targeters != null)
-      targeters.clear();
-  }
-
-  /**
-   * Denote this handle isn't referenced anymore by t.
-   */
-  public void removeTargeter(InstructionTargeter t) {
-    if(targeters != null) {
-      targeters.remove(t);
-    }
-  }
-  
-  /**
-   * Denote this handle is being referenced by t.
-   */
-  public void addTargeter(InstructionTargeter t) {
-    if(targeters == null)
-      targeters = new HashSet();
-
-    //if(!targeters.contains(t))
-    targeters.add(t);
-  }
-
-  public boolean hasTargeters() {
-    return (targeters != null) && (targeters.size() > 0);
-  }
-
-  /**
-   * @return null, if there are no targeters
-   */
-  public InstructionTargeter[] getTargeters() {
-    if(!hasTargeters())
-      return null;
-    
-    InstructionTargeter[] t = new InstructionTargeter[targeters.size()];
-    targeters.toArray(t);
-    return t;
-  }
-
-  /** @return a (verbose) string representation of the contained instruction. 
-   */
-  public String toString(boolean verbose) {
-    return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose);
-  }
-
-  /** @return a string representation of the contained instruction. 
-   */
-  public String toString() {
-    return toString(true);
-  }
-
-  /** Add an attribute to an instruction handle.
-   *
-   * @param key the key object to store/retrieve the attribute
-   * @param attr the attribute to associate with this handle
-   */
-  public void addAttribute(Object key, Object attr) {
-    if(attributes == null)
-      attributes = new HashMap(3);
-    
-    attributes.put(key, attr);
-  }
-
-  /** Delete an attribute of an instruction handle.
-   *
-   * @param key the key object to retrieve the attribute
-   */
-  public void removeAttribute(Object key) {
-    if(attributes != null)
-      attributes.remove(key);
-  }
-
-  /** Get attribute of an instruction handle.
-   *
-   * @param key the key object to store/retrieve the attribute
-   */
-  public Object getAttribute(Object key) {
-    if(attributes != null)
-      return attributes.get(key);
-
-    return null;
-  }
-
-  /** @return all attributes associated with this handle
-   */
-  public Collection getAttributes() {
-    if(attributes == null) {
-        attributes = new HashMap(3);
-    }
-    return attributes.values();
-  }
-  
-  /** Convenience method, simply calls accept() on the contained instruction.
-   *
-   * @param v Visitor object
-   */
-  public void accept(Visitor v) {
-    instruction.accept(v);
-  }
+
+    InstructionHandle next, prev; // Will be set from the outside
+    Instruction instruction;
+    protected int i_position = -1; // byte code offset of instruction
+    private Set targeters;
+    private Map attributes;
+
+
+    public final InstructionHandle getNext() {
+        return next;
+    }
+
+
+    public final InstructionHandle getPrev() {
+        return prev;
+    }
+
+
+    public final Instruction getInstruction() {
+        return instruction;
+    }
+
+
+    /**
+     * Replace current instruction contained in this handle.
+     * Old instruction is disposed using Instruction.dispose().
+     */
+    public void setInstruction( Instruction i ) { // Overridden in BranchHandle
+        if (i == null) {
+            throw new ClassGenException("Assigning null to handle");
+        }
+        if ((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction)) {
+            throw new ClassGenException("Assigning branch instruction " + i + " to plain handle");
+        }
+        if (instruction != null) {
+            instruction.dispose();
+        }
+        instruction = i;
+    }
+
+
+    /**
+     * Temporarily swap the current instruction, without disturbing
+     * anything. Meant to be used by a debugger, implementing
+     * breakpoints. Current instruction is returned.
+     */
+    public Instruction swapInstruction( Instruction i ) {
+        Instruction oldInstruction = instruction;
+        instruction = i;
+        return oldInstruction;
+    }
+
+
+    /*private*/protected InstructionHandle(Instruction i) {
+        setInstruction(i);
+    }
+
+    private static InstructionHandle ih_list = null; // List of reusable handles
+
+
+    /** Factory method.
+     */
+    static final InstructionHandle getInstructionHandle( Instruction i ) {
+        if (ih_list == null) {
+            return new InstructionHandle(i);
+        } else {
+            InstructionHandle ih = ih_list;
+            ih_list = ih.next;
+            ih.setInstruction(i);
+            return ih;
+        }
+    }
+
+
+    /**
+     * 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 ) {
+        i_position += offset;
+        return 0;
+    }
+
+
+    /** @return the position, i.e., the byte code offset of the contained
+     * instruction. This is accurate only after
+     * InstructionList.setPositions() has been called.
+     */
+    public int getPosition() {
+        return i_position;
+    }
+
+
+    /** Set the position, i.e., the byte code offset of the contained
+     * instruction.
+     */
+    void setPosition( int pos ) {
+        i_position = pos;
+    }
+
+
+    /** Overridden in BranchHandle
+     */
+    protected void addHandle() {
+        next = ih_list;
+        ih_list = this;
+    }
+
+
+    /**
+     * Delete contents, i.e., remove user access and make handle reusable.
+     */
+    void dispose() {
+        next = prev = null;
+        instruction.dispose();
+        instruction = null;
+        i_position = -1;
+        attributes = null;
+        removeAllTargeters();
+        addHandle();
+    }
+
+
+    /** Remove all targeters, if any.
+     */
+    public void removeAllTargeters() {
+        if (targeters != null) {
+            targeters.clear();
+        }
+    }
+
+
+    /**
+     * Denote this handle isn't referenced anymore by t.
+     */
+    public void removeTargeter( InstructionTargeter t ) {
+        if (targeters != null) {
+            targeters.remove(t);
+        }
+    }
+
+
+    /**
+     * Denote this handle is being referenced by t.
+     */
+    public void addTargeter( InstructionTargeter t ) {
+        if (targeters == null) {
+            targeters = new HashSet();
+        }
+        //if(!targeters.contains(t))
+        targeters.add(t);
+    }
+
+
+    public boolean hasTargeters() {
+        return (targeters != null) && (targeters.size() > 0);
+    }
+
+
+    /**
+     * @return null, if there are no targeters
+     */
+    public InstructionTargeter[] getTargeters() {
+        if (!hasTargeters()) {
+            return null;
+        }
+        InstructionTargeter[] t = new InstructionTargeter[targeters.size()];
+        targeters.toArray(t);
+        return t;
+    }
+
+
+    /** @return a (verbose) string representation of the contained instruction. 
+     */
+    public String toString( boolean verbose ) {
+        return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose);
+    }
+
+
+    /** @return a string representation of the contained instruction. 
+     */
+    public String toString() {
+        return toString(true);
+    }
+
+
+    /** Add an attribute to an instruction handle.
+     *
+     * @param key the key object to store/retrieve the attribute
+     * @param attr the attribute to associate with this handle
+     */
+    public void addAttribute( Object key, Object attr ) {
+        if (attributes == null) {
+            attributes = new HashMap(3);
+        }
+        attributes.put(key, attr);
+    }
+
+
+    /** Delete an attribute of an instruction handle.
+     *
+     * @param key the key object to retrieve the attribute
+     */
+    public void removeAttribute( Object key ) {
+        if (attributes != null) {
+            attributes.remove(key);
+        }
+    }
+
+
+    /** Get attribute of an instruction handle.
+     *
+     * @param key the key object to store/retrieve the attribute
+     */
+    public Object getAttribute( Object key ) {
+        if (attributes != null) {
+            return attributes.get(key);
+        }
+        return null;
+    }
+
+
+    /** @return all attributes associated with this handle
+     */
+    public Collection getAttributes() {
+        if (attributes == null) {
+            attributes = new HashMap(3);
+        }
+        return attributes.values();
+    }
+
+
+    /** Convenience method, simply calls accept() on the contained instruction.
+     *
+     * @param v Visitor object
+     */
+    public void accept( Visitor v ) {
+        instruction.accept(v);
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: bcel-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: bcel-dev-help@jakarta.apache.org