From 11233625c4e591a76fb7283a31fc38457fe1f3ad Mon Sep 17 00:00:00 2001 From: aclement Date: Mon, 23 Aug 2010 20:44:10 +0000 Subject: [PATCH] 323438 --- .../bcel/generic/InstructionFactory.java | 1258 +++++++++-------- 1 file changed, 697 insertions(+), 561 deletions(-) diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionFactory.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionFactory.java index ee02524e2..c327af96c 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionFactory.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionFactory.java @@ -57,569 +57,705 @@ import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.ConstantPool; import org.aspectj.apache.bcel.classfile.Utility; -/** - * Instances of this class may be used, e.g., to generate typed - * versions of instructions. Its main purpose is to be used as the - * byte code generating backend of a compiler. You can subclass it to - * add your own create methods. - * - * @version $Id: InstructionFactory.java,v 1.6 2009/09/10 03:59:34 aclement Exp $ +/** + * Instances of this class may be used, e.g., to generate typed versions of instructions. Its main purpose is to be used as the byte + * code generating backend of a compiler. You can subclass it to add your own create methods. + * + * @version $Id: InstructionFactory.java,v 1.7 2010/08/23 20:44:10 aclement Exp $ * @author M. Dahm * @see Constants */ public class InstructionFactory implements InstructionConstants { - protected ClassGen cg; - protected ConstantPool cp; - - public InstructionFactory(ClassGen cg, ConstantPool cp) { - this.cg = cg; - this.cp = cp; - } - - public InstructionFactory(ClassGen cg) { - this(cg, cg.getConstantPool()); - } - - public InstructionFactory(ConstantPool 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) { - - String signature = Utility.toMethodSignature(ret_type, arg_types); - - int index; - 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 InvokeInstruction(Constants.INVOKESPECIAL,index); - case Constants.INVOKEVIRTUAL: return new InvokeInstruction(Constants.INVOKEVIRTUAL,index); - case Constants.INVOKESTATIC: return new InvokeInstruction(Constants.INVOKESTATIC,index); - case Constants.INVOKEINTERFACE: - int nargs = 0; - for(int i=0; i < arg_types.length; i++) // Count size of arguments - nargs += arg_types[i].getSize(); - return new INVOKEINTERFACE(index, nargs + 1,0); - default: - throw new RuntimeException("Oops: Unknown invoke kind:" + kind); - } - } - - public InvokeInstruction createInvoke(String class_name, String name, String signature, short kind) { - int index; - 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 InvokeInstruction(Constants.INVOKESPECIAL,index); - case Constants.INVOKEVIRTUAL: return new InvokeInstruction(Constants.INVOKEVIRTUAL,index); - case Constants.INVOKESTATIC: return new InvokeInstruction(Constants.INVOKESTATIC,index); - case Constants.INVOKEINTERFACE: - Type[] argumentTypes = Type.getArgumentTypes(signature); - int nargs = 0; - for(int i=0; i < argumentTypes.length; i++) {// Count size of arguments - nargs += argumentTypes[i].getSize(); - } - return new INVOKEINTERFACE(index, nargs + 1,0); - default: - throw new RuntimeException("Oops: Unknown invoke kind:" + kind); - } - } - - public static Instruction createALOAD(int n) { - if (n<4) { - return new InstructionLV((short)(Constants.ALOAD_0+n)); - } - return new InstructionLV(Constants.ALOAD,n); - } - - public static Instruction createASTORE(int n) { - if (n<4) { - return new InstructionLV((short)(Constants.ASTORE_0+n)); - } - return new InstructionLV(Constants.ASTORE,n); - } - - - /** Uses PUSH to push a constant value onto the stack. - * @param value must be of type Number, Boolean, Character or String - */ - // OPTIMIZE callers should use the PUSH methods where possible if they know the types - public Instruction createConstant(Object value) { - Instruction instruction; - - if(value instanceof Number) - instruction = InstructionFactory.PUSH(cp, (Number)value); - else if(value instanceof String) - instruction = InstructionFactory.PUSH(cp, (String)value); - else if(value instanceof Boolean) - instruction = InstructionFactory.PUSH(cp, (Boolean)value); - else if(value instanceof Character) - instruction = InstructionFactory.PUSH(cp, (Character)value); - else if (value instanceof ObjectType) - instruction = InstructionFactory.PUSH(cp, (ObjectType)value); - else - throw new ClassGenException("Illegal type: " + value.getClass()); - - return instruction; - } - - /** 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 FieldInstruction(Constants.GETFIELD,index); - case Constants.PUTFIELD: return new FieldInstruction(Constants.PUTFIELD,index); - case Constants.GETSTATIC: return new FieldInstruction(Constants.GETSTATIC,index); - case Constants.PUTSTATIC: return new FieldInstruction(Constants.PUTSTATIC,index); - - default: - throw new RuntimeException("Oops: Unknown getfield kind:" + kind); - } - } - - /** Create reference to `this' - */ - public static Instruction createThis() { - return new InstructionLV(Constants.ALOAD,0); - } - - /** Create typed return - */ - public static Instruction 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); - } - } - - /** - * @param size size of operand, either 1 (int, e.g.) or 2 (double) - */ - public static Instruction createPop(int size) { - return (size == 2)? POP2 : POP; - } - - /** - * @param size size of operand, either 1 (int, e.g.) or 2 (double) - */ - public static Instruction createDup(int size) { - return (size == 2)? DUP2:DUP; - } - - /** - * @param size size of operand, either 1 (int, e.g.) or 2 (double) - */ - public static Instruction createDup_2(int size) { - return (size == 2)? DUP2_X2 :DUP_X2; - } - - /** - * @param size size of operand, either 1 (int, e.g.) or 2 (double) - */ - public static Instruction createDup_1(int size) { - return (size == 2)? DUP2_X1 : DUP_X1; - } - - /** - * @param index index of local variable - */ - public static InstructionLV 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 InstructionLV(Constants.ISTORE,index); - case Constants.T_FLOAT: return new InstructionLV(Constants.FSTORE,index); - case Constants.T_DOUBLE: return new InstructionLV(Constants.DSTORE,index); - case Constants.T_LONG: return new InstructionLV(Constants.LSTORE,index); - case Constants.T_ARRAY: - case Constants.T_OBJECT: return new InstructionLV(Constants.ASTORE,index); - default: throw new RuntimeException("Invalid type " + type); - } - } - - /** - * @param index index of local variable - */ - public static InstructionLV 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 InstructionLV(Constants.ILOAD,index); - case Constants.T_FLOAT: return new InstructionLV(Constants.FLOAD,index); - case Constants.T_DOUBLE: return new InstructionLV(Constants.DLOAD,index); - case Constants.T_LONG: return new InstructionLV(Constants.LLOAD,index); - case Constants.T_ARRAY: - case Constants.T_OBJECT: return new InstructionLV(Constants.ALOAD,index); - default: throw new RuntimeException("Invalid type " + type); - } - } - - /** - * @param type type of elements of array, i.e., array.getElementType() - */ - public static Instruction 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 Instruction 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); - } - } - - private static final char[] shortNames = { 'C', 'F', 'D', 'B', 'S', 'I', 'L' }; - /** 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; - - if (src==Constants.T_DOUBLE) { - switch (dest) { - case Constants.T_FLOAT: return InstructionConstants.D2F; - case Constants.T_INT: return InstructionConstants.D2I; - case Constants.T_LONG: return InstructionConstants.D2L; - } - } else if (src==Constants.T_FLOAT) { - switch (dest) { - case Constants.T_DOUBLE: return InstructionConstants.F2D; - case Constants.T_INT: return InstructionConstants.F2I; - case Constants.T_LONG: return InstructionConstants.F2L; - } - } else if (src==Constants.T_INT) { - switch (dest) { - case Constants.T_BYTE: return InstructionConstants.I2B; - case Constants.T_CHAR: return InstructionConstants.I2C; - case Constants.T_DOUBLE: return InstructionConstants.I2D; - case Constants.T_FLOAT: return InstructionConstants.I2F; - case Constants.T_LONG: return InstructionConstants.I2L; - case Constants.T_SHORT: return InstructionConstants.I2S; - } - } else if (src==Constants.T_LONG) { - switch (dest) { - case Constants.T_DOUBLE: return InstructionConstants.L2D; - case Constants.T_FLOAT: return InstructionConstants.L2F; - case Constants.T_INT: return InstructionConstants.L2I; - } - } - -// String name = "org.aspectj.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 null; -// return i; - } else if((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) { - if(dest_type instanceof ArrayType) - return new InstructionCP(Constants.CHECKCAST,cp.addArrayClass((ArrayType)dest_type)); - else - return new InstructionCP(Constants.CHECKCAST,cp.addClass(((ObjectType)dest_type).getClassName())); - } - else - throw new RuntimeException("Can not cast " + src_type + " to " + dest_type); - } - - public FieldInstruction createGetField(String class_name, String name, Type t) { - return new FieldInstruction(Constants.GETFIELD,cp.addFieldref(class_name, name, t.getSignature())); - } - - public FieldInstruction createGetStatic(String class_name, String name, Type t) { - return new FieldInstruction(Constants.GETSTATIC,cp.addFieldref(class_name, name, t.getSignature())); - } - - public FieldInstruction createPutField(String class_name, String name, Type t) { - return new FieldInstruction(Constants.PUTFIELD,cp.addFieldref(class_name, name, t.getSignature())); - } - - public FieldInstruction createPutStatic(String class_name, String name, Type t) { - return new FieldInstruction(Constants.PUTSTATIC,cp.addFieldref(class_name, name, t.getSignature())); - } - - public Instruction createCheckCast(ReferenceType t) { - if(t instanceof ArrayType) - return new InstructionCP(Constants.CHECKCAST,cp.addArrayClass((ArrayType)t)); - else - return new InstructionCP(Constants.CHECKCAST,cp.addClass((ObjectType)t)); - } - - public Instruction createInstanceOf(ReferenceType t) { - if(t instanceof ArrayType) - return new InstructionCP(Constants.INSTANCEOF,cp.addArrayClass((ArrayType)t)); - else - return new InstructionCP(Constants.INSTANCEOF,cp.addClass((ObjectType)t)); - } - - public Instruction createNew(ObjectType t) { - return new InstructionCP(Constants.NEW,cp.addClass(t)); - } - - public Instruction 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 InstructionCP(Constants.ANEWARRAY,cp.addClass((ObjectType)t)); - else if(t instanceof ArrayType) - return new InstructionCP(Constants.ANEWARRAY,cp.addArrayClass((ArrayType)t)); - else - return new InstructionByte(Constants.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 InstructionBranch createBranchInstruction(short opcode, InstructionHandle target) { - switch(opcode) { - case Constants.IFEQ: return new InstructionBranch(Constants.IFEQ,target); - case Constants.IFNE: return new InstructionBranch(Constants.IFNE,target); - case Constants.IFLT: return new InstructionBranch(Constants.IFLT,target); - case Constants.IFGE: return new InstructionBranch(Constants.IFGE,target); - case Constants.IFGT: return new InstructionBranch(Constants.IFGT,target); - case Constants.IFLE: return new InstructionBranch(Constants.IFLE,target); - case Constants.IF_ICMPEQ: return new InstructionBranch(Constants.IF_ICMPEQ,target); - case Constants.IF_ICMPNE: return new InstructionBranch(Constants.IF_ICMPNE,target); - case Constants.IF_ICMPLT: return new InstructionBranch(Constants.IF_ICMPLT,target); - case Constants.IF_ICMPGE: return new InstructionBranch(Constants.IF_ICMPGE,target); - case Constants.IF_ICMPGT: return new InstructionBranch(Constants.IF_ICMPGT,target); - case Constants.IF_ICMPLE: return new InstructionBranch(Constants.IF_ICMPLE,target); - case Constants.IF_ACMPEQ: return new InstructionBranch(Constants.IF_ACMPEQ,target); - case Constants.IF_ACMPNE: return new InstructionBranch(Constants.IF_ACMPNE,target); - case Constants.GOTO: return new InstructionBranch(Constants.GOTO,target); - case Constants.JSR: return new InstructionBranch(Constants.JSR,target); - case Constants.IFNULL: return new InstructionBranch(Constants.IFNULL,target); - case Constants.IFNONNULL: return new InstructionBranch(Constants.IFNONNULL,target); - case Constants.GOTO_W: return new InstructionBranch(Constants.GOTO_W,target); - case Constants.JSR_W: return new InstructionBranch(Constants.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(ConstantPool c) { cp = c; } - public ConstantPool getConstantPool() { return cp; } - - - /** - * Returns the right instruction for putting whatever you want onto the stack - */ - public static Instruction PUSH(ConstantPool cp, int value) { - Instruction instruction = null; - if ((value >= -1) && (value <= 5)) { - return INSTRUCTIONS[Constants.ICONST_0 + value]; - } else if ((value >= -128) && (value <= 127)) // Use BIPUSH - instruction = new InstructionByte(Constants.BIPUSH,(byte)value); - else if((value >= -32768) && (value <= 32767)) // Use SIPUSH - instruction = new InstructionShort(Constants.SIPUSH,(short)value); - else // If everything fails create a Constant pool entry - { - int pos = cp.addInteger(value); - if (pos<=Constants.MAX_BYTE) { - instruction = new InstructionCP(Constants.LDC,pos); - } else { - instruction = new InstructionCP(Constants.LDC_W,pos); - } - } - return instruction; - } - - public static Instruction PUSH(ConstantPool cp, ObjectType t) { - return new InstructionCP(Constants.LDC_W,cp.addClass(t)); - } - - public static Instruction PUSH(ConstantPool cp, boolean value) { - return INSTRUCTIONS[Constants.ICONST_0 + (value? 1 : 0)]; - } - - public static Instruction PUSH(ConstantPool cp, float value) { - Instruction instruction = null; - if(value == 0.0) - instruction = FCONST_0; - else if(value == 1.0) - instruction = FCONST_1; - else if(value == 2.0) - instruction = FCONST_2; - else { - // Create a Constant pool entry - int i = cp.addFloat(value); - instruction = new InstructionCP(i<=Constants.MAX_BYTE?Constants.LDC:Constants.LDC_W,i); - } - return instruction; - } - - public static Instruction PUSH(ConstantPool cp, long value) { - Instruction instruction = null; - if(value == 0) - instruction = LCONST_0; - else if(value == 1) - instruction = LCONST_1; - else // Create a Constant pool entry - instruction = new InstructionCP(Constants.LDC2_W,cp.addLong(value)); - return instruction; - } - - public static Instruction PUSH(ConstantPool cp, double value) { - Instruction instruction = null; - if(value == 0.0) - instruction = DCONST_0; - else if(value == 1.0) - instruction = DCONST_1; - else { - // Create a Constant pool entry - instruction = new InstructionCP(Constants.LDC2_W,cp.addDouble(value)); - } - return instruction; - } - - public static Instruction PUSH(ConstantPool cp, String value) { - Instruction instruction = null; - if(value == null) - instruction = ACONST_NULL; - else { - int i = cp.addString(value); - instruction = new InstructionCP(i<=Constants.MAX_BYTE?Constants.LDC:Constants.LDC_W,i); - } - return instruction; - } - - public static Instruction PUSH(ConstantPool cp, Number value) { - Instruction instruction = null; - if((value instanceof Integer) || (value instanceof Short) || (value instanceof Byte)) - instruction = PUSH(cp, value.intValue()); - else if(value instanceof Double) - instruction = PUSH(cp, value.doubleValue()); - else if(value instanceof Float) - instruction = PUSH(cp, value.floatValue()); - else if(value instanceof Long) - instruction = PUSH(cp, value.longValue()); - else - throw new ClassGenException("What's this: " + value); - return instruction; - } - - public static Instruction PUSH(ConstantPool cp, Character value) { - return PUSH(cp, (int)value.charValue()); - } - - public static Instruction PUSH(ConstantPool cp, Boolean value) { - return PUSH(cp, value.booleanValue()); - } - + protected ClassGen cg; + protected ConstantPool cp; + + public InstructionFactory(ClassGen cg, ConstantPool cp) { + this.cg = cg; + this.cp = cp; + } + + public InstructionFactory(ClassGen cg) { + this(cg, cg.getConstantPool()); + } + + public InstructionFactory(ConstantPool 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) { + + String signature = Utility.toMethodSignature(ret_type, arg_types); + + int index; + 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 InvokeInstruction(Constants.INVOKESPECIAL, index); + case Constants.INVOKEVIRTUAL: + return new InvokeInstruction(Constants.INVOKEVIRTUAL, index); + case Constants.INVOKESTATIC: + return new InvokeInstruction(Constants.INVOKESTATIC, index); + case Constants.INVOKEINTERFACE: + int nargs = 0; + for (int i = 0; i < arg_types.length; i++) { + nargs += arg_types[i].getSize(); + } + return new INVOKEINTERFACE(index, nargs + 1, 0); + default: + throw new RuntimeException("Oops: Unknown invoke kind:" + kind); + } + } + + public InvokeInstruction createInvoke(String class_name, String name, String signature, short kind) { + int index; + 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 InvokeInstruction(Constants.INVOKESPECIAL, index); + case Constants.INVOKEVIRTUAL: + return new InvokeInstruction(Constants.INVOKEVIRTUAL, index); + case Constants.INVOKESTATIC: + return new InvokeInstruction(Constants.INVOKESTATIC, index); + case Constants.INVOKEINTERFACE: + Type[] argumentTypes = Type.getArgumentTypes(signature); + int nargs = 0; + for (int i = 0; i < argumentTypes.length; i++) {// Count size of arguments + nargs += argumentTypes[i].getSize(); + } + return new INVOKEINTERFACE(index, nargs + 1, 0); + default: + throw new RuntimeException("Oops: Unknown invoke kind:" + kind); + } + } + + public static Instruction createALOAD(int n) { + if (n < 4) { + return new InstructionLV((short) (Constants.ALOAD_0 + n)); + } + return new InstructionLV(Constants.ALOAD, n); + } + + public static Instruction createASTORE(int n) { + if (n < 4) { + return new InstructionLV((short) (Constants.ASTORE_0 + n)); + } + return new InstructionLV(Constants.ASTORE, n); + } + + /** + * Uses PUSH to push a constant value onto the stack. + * + * @param value must be of type Number, Boolean, Character or String + */ + // OPTIMIZE callers should use the PUSH methods where possible if they know the types + public Instruction createConstant(Object value) { + Instruction instruction; + + if (value instanceof Number) { + instruction = InstructionFactory.PUSH(cp, (Number) value); + } else if (value instanceof String) { + instruction = InstructionFactory.PUSH(cp, (String) value); + } else if (value instanceof Boolean) { + instruction = InstructionFactory.PUSH(cp, (Boolean) value); + } else if (value instanceof Character) { + instruction = InstructionFactory.PUSH(cp, (Character) value); + } else if (value instanceof ObjectType) { + instruction = InstructionFactory.PUSH(cp, (ObjectType) value); + } else { + throw new ClassGenException("Illegal type: " + value.getClass()); + } + + return instruction; + } + + /** + * 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 FieldInstruction(Constants.GETFIELD, index); + case Constants.PUTFIELD: + return new FieldInstruction(Constants.PUTFIELD, index); + case Constants.GETSTATIC: + return new FieldInstruction(Constants.GETSTATIC, index); + case Constants.PUTSTATIC: + return new FieldInstruction(Constants.PUTSTATIC, index); + + default: + throw new RuntimeException("Oops: Unknown getfield kind:" + kind); + } + } + + /** + * Create reference to `this' + */ + public static Instruction createThis() { + return new InstructionLV(Constants.ALOAD, 0); + } + + /** + * Create typed return + */ + public static Instruction 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); + } + } + + /** + * @param size size of operand, either 1 (int, e.g.) or 2 (double) + */ + public static Instruction createPop(int size) { + return (size == 2) ? POP2 : POP; + } + + /** + * @param size size of operand, either 1 (int, e.g.) or 2 (double) + */ + public static Instruction createDup(int size) { + return (size == 2) ? DUP2 : DUP; + } + + /** + * @param size size of operand, either 1 (int, e.g.) or 2 (double) + */ + public static Instruction createDup_2(int size) { + return (size == 2) ? DUP2_X2 : DUP_X2; + } + + /** + * @param size size of operand, either 1 (int, e.g.) or 2 (double) + */ + public static Instruction createDup_1(int size) { + return (size == 2) ? DUP2_X1 : DUP_X1; + } + + /** + * @param index index of local variable + */ + public static InstructionLV 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 InstructionLV(Constants.ISTORE, index); + case Constants.T_FLOAT: + return new InstructionLV(Constants.FSTORE, index); + case Constants.T_DOUBLE: + return new InstructionLV(Constants.DSTORE, index); + case Constants.T_LONG: + return new InstructionLV(Constants.LSTORE, index); + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return new InstructionLV(Constants.ASTORE, index); + default: + throw new RuntimeException("Invalid type " + type); + } + } + + /** + * @param index index of local variable + */ + public static InstructionLV 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 InstructionLV(Constants.ILOAD, index); + case Constants.T_FLOAT: + return new InstructionLV(Constants.FLOAD, index); + case Constants.T_DOUBLE: + return new InstructionLV(Constants.DLOAD, index); + case Constants.T_LONG: + return new InstructionLV(Constants.LLOAD, index); + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return new InstructionLV(Constants.ALOAD, index); + default: + throw new RuntimeException("Invalid type " + type); + } + } + + /** + * @param type type of elements of array, i.e., array.getElementType() + */ + public static Instruction 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 Instruction 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); + } + } + + private static final char[] shortNames = { 'C', 'F', 'D', 'B', 'S', 'I', 'L' }; + + /** + * 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; + } + + if (src == Constants.T_DOUBLE) { + switch (dest) { + case Constants.T_FLOAT: + return InstructionConstants.D2F; + case Constants.T_INT: + return InstructionConstants.D2I; + case Constants.T_LONG: + return InstructionConstants.D2L; + } + } else if (src == Constants.T_FLOAT) { + switch (dest) { + case Constants.T_DOUBLE: + return InstructionConstants.F2D; + case Constants.T_INT: + return InstructionConstants.F2I; + case Constants.T_LONG: + return InstructionConstants.F2L; + } + } else if (src == Constants.T_INT) { + switch (dest) { + case Constants.T_BYTE: + return InstructionConstants.I2B; + case Constants.T_CHAR: + return InstructionConstants.I2C; + case Constants.T_DOUBLE: + return InstructionConstants.I2D; + case Constants.T_FLOAT: + return InstructionConstants.I2F; + case Constants.T_LONG: + return InstructionConstants.I2L; + case Constants.T_SHORT: + return InstructionConstants.I2S; + } + } else if (src == Constants.T_LONG) { + switch (dest) { + case Constants.T_DOUBLE: + return InstructionConstants.L2D; + case Constants.T_FLOAT: + return InstructionConstants.L2F; + case Constants.T_INT: + return InstructionConstants.L2I; + } + } + + // String name = "org.aspectj.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 null; + // return i; + } else if ((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) { + if (dest_type instanceof ArrayType) { + return new InstructionCP(Constants.CHECKCAST, cp.addArrayClass((ArrayType) dest_type)); + } else { + return new InstructionCP(Constants.CHECKCAST, cp.addClass(((ObjectType) dest_type).getClassName())); + } + } else { + throw new RuntimeException("Can not cast " + src_type + " to " + dest_type); + } + } + + public FieldInstruction createGetField(String class_name, String name, Type t) { + return new FieldInstruction(Constants.GETFIELD, cp.addFieldref(class_name, name, t.getSignature())); + } + + public FieldInstruction createGetStatic(String class_name, String name, Type t) { + return new FieldInstruction(Constants.GETSTATIC, cp.addFieldref(class_name, name, t.getSignature())); + } + + public FieldInstruction createPutField(String class_name, String name, Type t) { + return new FieldInstruction(Constants.PUTFIELD, cp.addFieldref(class_name, name, t.getSignature())); + } + + public FieldInstruction createPutStatic(String class_name, String name, Type t) { + return new FieldInstruction(Constants.PUTSTATIC, cp.addFieldref(class_name, name, t.getSignature())); + } + + public Instruction createCheckCast(ReferenceType t) { + if (t instanceof ArrayType) { + return new InstructionCP(Constants.CHECKCAST, cp.addArrayClass((ArrayType) t)); + } else { + return new InstructionCP(Constants.CHECKCAST, cp.addClass((ObjectType) t)); + } + } + + public Instruction createInstanceOf(ReferenceType t) { + if (t instanceof ArrayType) { + return new InstructionCP(Constants.INSTANCEOF, cp.addArrayClass((ArrayType) t)); + } else { + return new InstructionCP(Constants.INSTANCEOF, cp.addClass((ObjectType) t)); + } + } + + public Instruction createNew(ObjectType t) { + return new InstructionCP(Constants.NEW, cp.addClass(t)); + } + + public Instruction 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 InstructionCP(Constants.ANEWARRAY, cp.addClass((ObjectType) t)); + } else if (t instanceof ArrayType) { + return new InstructionCP(Constants.ANEWARRAY, cp.addArrayClass((ArrayType) t)); + } else { + return new InstructionByte(Constants.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 InstructionBranch createBranchInstruction(short opcode, InstructionHandle target) { + switch (opcode) { + case Constants.IFEQ: + return new InstructionBranch(Constants.IFEQ, target); + case Constants.IFNE: + return new InstructionBranch(Constants.IFNE, target); + case Constants.IFLT: + return new InstructionBranch(Constants.IFLT, target); + case Constants.IFGE: + return new InstructionBranch(Constants.IFGE, target); + case Constants.IFGT: + return new InstructionBranch(Constants.IFGT, target); + case Constants.IFLE: + return new InstructionBranch(Constants.IFLE, target); + case Constants.IF_ICMPEQ: + return new InstructionBranch(Constants.IF_ICMPEQ, target); + case Constants.IF_ICMPNE: + return new InstructionBranch(Constants.IF_ICMPNE, target); + case Constants.IF_ICMPLT: + return new InstructionBranch(Constants.IF_ICMPLT, target); + case Constants.IF_ICMPGE: + return new InstructionBranch(Constants.IF_ICMPGE, target); + case Constants.IF_ICMPGT: + return new InstructionBranch(Constants.IF_ICMPGT, target); + case Constants.IF_ICMPLE: + return new InstructionBranch(Constants.IF_ICMPLE, target); + case Constants.IF_ACMPEQ: + return new InstructionBranch(Constants.IF_ACMPEQ, target); + case Constants.IF_ACMPNE: + return new InstructionBranch(Constants.IF_ACMPNE, target); + case Constants.GOTO: + return new InstructionBranch(Constants.GOTO, target); + case Constants.JSR: + return new InstructionBranch(Constants.JSR, target); + case Constants.IFNULL: + return new InstructionBranch(Constants.IFNULL, target); + case Constants.IFNONNULL: + return new InstructionBranch(Constants.IFNONNULL, target); + case Constants.GOTO_W: + return new InstructionBranch(Constants.GOTO_W, target); + case Constants.JSR_W: + return new InstructionBranch(Constants.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(ConstantPool c) { + cp = c; + } + + public ConstantPool getConstantPool() { + return cp; + } + + /** + * Returns the right instruction for putting whatever you want onto the stack + */ + public static Instruction PUSH(ConstantPool cp, int value) { + Instruction instruction = null; + if ((value >= -1) && (value <= 5)) { + return INSTRUCTIONS[Constants.ICONST_0 + value]; + } else if ((value >= -128) && (value <= 127)) { + instruction = new InstructionByte(Constants.BIPUSH, (byte) value); + } else if ((value >= -32768) && (value <= 32767)) { + instruction = new InstructionShort(Constants.SIPUSH, (short) value); + } else // If everything fails create a Constant pool entry + { + int pos = cp.addInteger(value); + if (pos <= Constants.MAX_BYTE) { + instruction = new InstructionCP(Constants.LDC, pos); + } else { + instruction = new InstructionCP(Constants.LDC_W, pos); + } + } + return instruction; + } + + public static Instruction PUSH(ConstantPool cp, ObjectType t) { + return new InstructionCP(Constants.LDC_W, cp.addClass(t)); + } + + public static Instruction PUSH(ConstantPool cp, boolean value) { + return INSTRUCTIONS[Constants.ICONST_0 + (value ? 1 : 0)]; + } + + public static Instruction PUSH(ConstantPool cp, float value) { + Instruction instruction = null; + if (value == 0.0) { + instruction = FCONST_0; + } else if (value == 1.0) { + instruction = FCONST_1; + } else if (value == 2.0) { + instruction = FCONST_2; + } else { + // Create a Constant pool entry + int i = cp.addFloat(value); + instruction = new InstructionCP(i <= Constants.MAX_BYTE ? Constants.LDC : Constants.LDC_W, i); + } + return instruction; + } + + public static Instruction PUSH(ConstantPool cp, long value) { + Instruction instruction = null; + if (value == 0) { + instruction = LCONST_0; + } else if (value == 1) { + instruction = LCONST_1; + } else { + instruction = new InstructionCP(Constants.LDC2_W, cp.addLong(value)); + } + return instruction; + } + + public static Instruction PUSH(ConstantPool cp, double value) { + Instruction instruction = null; + if (value == 0.0) { + instruction = DCONST_0; + } else if (value == 1.0) { + instruction = DCONST_1; + } else { + // Create a Constant pool entry + instruction = new InstructionCP(Constants.LDC2_W, cp.addDouble(value)); + } + return instruction; + } + + public static Instruction PUSH(ConstantPool cp, String value) { + Instruction instruction = null; + if (value == null) { + instruction = ACONST_NULL; + } else { + int i = cp.addString(value); + instruction = new InstructionCP(i <= Constants.MAX_BYTE ? Constants.LDC : Constants.LDC_W, i); + } + return instruction; + } + + public static Instruction PUSH(ConstantPool cp, Number value) { + Instruction instruction = null; + if ((value instanceof Integer) || (value instanceof Short) || (value instanceof Byte)) { + instruction = PUSH(cp, value.intValue()); + } else if (value instanceof Double) { + instruction = PUSH(cp, value.doubleValue()); + } else if (value instanceof Float) { + instruction = PUSH(cp, value.floatValue()); + } else if (value instanceof Long) { + instruction = PUSH(cp, value.longValue()); + } else { + throw new ClassGenException("What's this: " + value); + } + return instruction; + } + + public static Instruction PUSH(ConstantPool cp, Character value) { + return PUSH(cp, value.charValue()); + } + + public static Instruction PUSH(ConstantPool cp, Boolean value) { + return PUSH(cp, value.booleanValue()); + } + + /** + * Return a list that will load the Class object - on 1.5 or later use the class variant of ldc, whilst on earlier JVMs use the + * regular Class.forName. + */ + public InstructionList PUSHCLASS(ConstantPool cp, String className) { + InstructionList iList = new InstructionList(); + int classIndex = cp.addClass(className); + if (cg != null && cg.getMajor() >= Constants.MAJOR_1_5) { + if (classIndex <= Constants.MAX_BYTE) { + iList.append(new InstructionCP(Instruction.LDC, classIndex)); + } else { + iList.append(new InstructionCP(Instruction.LDC_W, classIndex)); + } + } else { + iList.append(InstructionFactory.PUSH(cp, className)); + iList.append(this.createInvoke("java.lang.Class", "forName", ObjectType.CLASS, Type.STRINGARRAY1, + Constants.INVOKESTATIC)); + } + return iList; + } } -- 2.39.5