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:[EMAIL PROTECTED]">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: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]