InstructionFactory.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.bcel.generic;

  18. import org.apache.bcel.Const;

  19. /**
  20.  * Instances of this class may be used, e.g., to generate typed versions of instructions. Its main purpose is to be used
  21.  * as the byte code generating backend of a compiler. You can subclass it to add your own create methods.
  22.  * <p>
  23.  * Note: The static createXXX methods return singleton instances from the {@link InstructionConst} class.
  24.  * </p>
  25.  *
  26.  * @see Const
  27.  * @see InstructionConst
  28.  */
  29. public class InstructionFactory implements InstructionConstants {

  30.     private static final class MethodObject {

  31.         final Type[] argTypes;
  32.         final Type resultType;
  33.         final String className;
  34.         final String name;

  35.         MethodObject(final String c, final String n, final Type r, final Type[] a) {
  36.             this.className = c;
  37.             this.name = n;
  38.             this.resultType = r;
  39.             this.argTypes = a;
  40.         }
  41.     }

  42.     private static final String APPEND = "append";

  43.     private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer";

  44.     /**
  45.      * These must agree with the order of Constants.T_CHAR through T_LONG.
  46.      */
  47.     private static final String[] SHORT_NAMES = {"C", "F", "D", "B", "S", "I", "L"};

  48.     private static final MethodObject[] APPEND_METHOD_OBJECTS = {
  49.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.STRING }),
  50.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.OBJECT }), null, null, // indices 2, 3
  51.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }),
  52.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.CHAR }),
  53.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.FLOAT }),
  54.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.DOUBLE }),
  55.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }),
  56.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), // No append(byte)
  57.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), // No append(short)
  58.             new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.LONG })};

  59.     /**
  60.      * @param type type of elements of array, i.e., array.getElementType()
  61.      */
  62.     public static ArrayInstruction createArrayLoad(final Type type) {
  63.         switch (type.getType()) {
  64.         case Const.T_BOOLEAN:
  65.         case Const.T_BYTE:
  66.             return InstructionConst.BALOAD;
  67.         case Const.T_CHAR:
  68.             return InstructionConst.CALOAD;
  69.         case Const.T_SHORT:
  70.             return InstructionConst.SALOAD;
  71.         case Const.T_INT:
  72.             return InstructionConst.IALOAD;
  73.         case Const.T_FLOAT:
  74.             return InstructionConst.FALOAD;
  75.         case Const.T_DOUBLE:
  76.             return InstructionConst.DALOAD;
  77.         case Const.T_LONG:
  78.             return InstructionConst.LALOAD;
  79.         case Const.T_ARRAY:
  80.         case Const.T_OBJECT:
  81.             return InstructionConst.AALOAD;
  82.         default:
  83.             throw new IllegalArgumentException("Invalid type " + type);
  84.         }
  85.     }

  86.     /**
  87.      * @param type type of elements of array, i.e., array.getElementType()
  88.      */
  89.     public static ArrayInstruction createArrayStore(final Type type) {
  90.         switch (type.getType()) {
  91.         case Const.T_BOOLEAN:
  92.         case Const.T_BYTE:
  93.             return InstructionConst.BASTORE;
  94.         case Const.T_CHAR:
  95.             return InstructionConst.CASTORE;
  96.         case Const.T_SHORT:
  97.             return InstructionConst.SASTORE;
  98.         case Const.T_INT:
  99.             return InstructionConst.IASTORE;
  100.         case Const.T_FLOAT:
  101.             return InstructionConst.FASTORE;
  102.         case Const.T_DOUBLE:
  103.             return InstructionConst.DASTORE;
  104.         case Const.T_LONG:
  105.             return InstructionConst.LASTORE;
  106.         case Const.T_ARRAY:
  107.         case Const.T_OBJECT:
  108.             return InstructionConst.AASTORE;
  109.         default:
  110.             throw new IllegalArgumentException("Invalid type " + type);
  111.         }
  112.     }

  113.     private static ArithmeticInstruction createBinaryDoubleOp(final char op) {
  114.         switch (op) {
  115.         case '-':
  116.             return InstructionConst.DSUB;
  117.         case '+':
  118.             return InstructionConst.DADD;
  119.         case '*':
  120.             return InstructionConst.DMUL;
  121.         case '/':
  122.             return InstructionConst.DDIV;
  123.         case '%':
  124.             return InstructionConst.DREM;
  125.         default:
  126.             throw new IllegalArgumentException("Invalid operand " + op);
  127.         }
  128.     }

  129.     private static ArithmeticInstruction createBinaryFloatOp(final char op) {
  130.         switch (op) {
  131.         case '-':
  132.             return InstructionConst.FSUB;
  133.         case '+':
  134.             return InstructionConst.FADD;
  135.         case '*':
  136.             return InstructionConst.FMUL;
  137.         case '/':
  138.             return InstructionConst.FDIV;
  139.         case '%':
  140.             return InstructionConst.FREM;
  141.         default:
  142.             throw new IllegalArgumentException("Invalid operand " + op);
  143.         }
  144.     }

  145.     private static ArithmeticInstruction createBinaryIntOp(final char first, final String op) {
  146.         switch (first) {
  147.         case '-':
  148.             return InstructionConst.ISUB;
  149.         case '+':
  150.             return InstructionConst.IADD;
  151.         case '%':
  152.             return InstructionConst.IREM;
  153.         case '*':
  154.             return InstructionConst.IMUL;
  155.         case '/':
  156.             return InstructionConst.IDIV;
  157.         case '&':
  158.             return InstructionConst.IAND;
  159.         case '|':
  160.             return InstructionConst.IOR;
  161.         case '^':
  162.             return InstructionConst.IXOR;
  163.         case '<':
  164.             return InstructionConst.ISHL;
  165.         case '>':
  166.             return op.equals(">>>") ? InstructionConst.IUSHR : InstructionConst.ISHR;
  167.         default:
  168.             throw new IllegalArgumentException("Invalid operand " + op);
  169.         }
  170.     }

  171.     /**
  172.      * Create an invokedynamic instruction.
  173.      *
  174.      * @param bootstrap_index index into the bootstrap_methods array
  175.      * @param name name of the called method
  176.      * @param ret_type return type of method
  177.      * @param argTypes argument types of method
  178.      * @see Const
  179.      */

  180.     /*
  181.      * createInvokeDynamic only needed if instrumentation code wants to generate a new invokedynamic instruction. I don't
  182.      * think we need.
  183.      *
  184.      * public InvokeInstruction createInvokeDynamic( int bootstrap_index, String name, Type ret_type, Type[] argTypes) {
  185.      * int index; int nargs = 0; String signature = Type.getMethodSignature(ret_type, argTypes); for (int i = 0; i <
  186.      * argTypes.length; i++) { nargs += argTypes[i].getSize(); } // UNDONE - needs to be added to ConstantPoolGen //index
  187.      * = cp.addInvokeDynamic(bootstrap_index, name, signature); index = 0; return new INVOKEDYNAMIC(index); }
  188.      */

  189.     private static ArithmeticInstruction createBinaryLongOp(final char first, final String op) {
  190.         switch (first) {
  191.         case '-':
  192.             return InstructionConst.LSUB;
  193.         case '+':
  194.             return InstructionConst.LADD;
  195.         case '%':
  196.             return InstructionConst.LREM;
  197.         case '*':
  198.             return InstructionConst.LMUL;
  199.         case '/':
  200.             return InstructionConst.LDIV;
  201.         case '&':
  202.             return InstructionConst.LAND;
  203.         case '|':
  204.             return InstructionConst.LOR;
  205.         case '^':
  206.             return InstructionConst.LXOR;
  207.         case '<':
  208.             return InstructionConst.LSHL;
  209.         case '>':
  210.             return op.equals(">>>") ? InstructionConst.LUSHR : InstructionConst.LSHR;
  211.         default:
  212.             throw new IllegalArgumentException("Invalid operand " + op);
  213.         }
  214.     }

  215.     /**
  216.      * Create binary operation for simple basic types, such as int and float.
  217.      *
  218.      * @param op operation, such as "+", "*", "&lt;&lt;", etc.
  219.      */
  220.     public static ArithmeticInstruction createBinaryOperation(final String op, final Type type) {
  221.         final char first = op.charAt(0);
  222.         switch (type.getType()) {
  223.         case Const.T_BYTE:
  224.         case Const.T_SHORT:
  225.         case Const.T_INT:
  226.         case Const.T_CHAR:
  227.             return createBinaryIntOp(first, op);
  228.         case Const.T_LONG:
  229.             return createBinaryLongOp(first, op);
  230.         case Const.T_FLOAT:
  231.             return createBinaryFloatOp(first);
  232.         case Const.T_DOUBLE:
  233.             return createBinaryDoubleOp(first);
  234.         default:
  235.             throw new IllegalArgumentException("Invalid type " + type);
  236.         }
  237.     }

  238.     /**
  239.      * Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH. For those you should use the SWITCH
  240.      * compound instruction.
  241.      */
  242.     public static BranchInstruction createBranchInstruction(final short opcode, final InstructionHandle target) {
  243.         switch (opcode) {
  244.         case Const.IFEQ:
  245.             return new IFEQ(target);
  246.         case Const.IFNE:
  247.             return new IFNE(target);
  248.         case Const.IFLT:
  249.             return new IFLT(target);
  250.         case Const.IFGE:
  251.             return new IFGE(target);
  252.         case Const.IFGT:
  253.             return new IFGT(target);
  254.         case Const.IFLE:
  255.             return new IFLE(target);
  256.         case Const.IF_ICMPEQ:
  257.             return new IF_ICMPEQ(target);
  258.         case Const.IF_ICMPNE:
  259.             return new IF_ICMPNE(target);
  260.         case Const.IF_ICMPLT:
  261.             return new IF_ICMPLT(target);
  262.         case Const.IF_ICMPGE:
  263.             return new IF_ICMPGE(target);
  264.         case Const.IF_ICMPGT:
  265.             return new IF_ICMPGT(target);
  266.         case Const.IF_ICMPLE:
  267.             return new IF_ICMPLE(target);
  268.         case Const.IF_ACMPEQ:
  269.             return new IF_ACMPEQ(target);
  270.         case Const.IF_ACMPNE:
  271.             return new IF_ACMPNE(target);
  272.         case Const.GOTO:
  273.             return new GOTO(target);
  274.         case Const.JSR:
  275.             return new JSR(target);
  276.         case Const.IFNULL:
  277.             return new IFNULL(target);
  278.         case Const.IFNONNULL:
  279.             return new IFNONNULL(target);
  280.         case Const.GOTO_W:
  281.             return new GOTO_W(target);
  282.         case Const.JSR_W:
  283.             return new JSR_W(target);
  284.         default:
  285.             throw new IllegalArgumentException("Invalid opcode: " + opcode);
  286.         }
  287.     }

  288.     /**
  289.      * @param size size of operand, either 1 (int, e.g.) or 2 (double)
  290.      */
  291.     public static StackInstruction createDup(final int size) {
  292.         return size == 2 ? InstructionConst.DUP2 : InstructionConst.DUP;
  293.     }

  294.     /**
  295.      * @param size size of operand, either 1 (int, e.g.) or 2 (double)
  296.      */
  297.     public static StackInstruction createDup_1(final int size) {
  298.         return size == 2 ? InstructionConst.DUP2_X1 : InstructionConst.DUP_X1;
  299.     }

  300.     /**
  301.      * @param size size of operand, either 1 (int, e.g.) or 2 (double)
  302.      */
  303.     public static StackInstruction createDup_2(final int size) {
  304.         return size == 2 ? InstructionConst.DUP2_X2 : InstructionConst.DUP_X2;
  305.     }

  306.     /**
  307.      * @param index index of local variable
  308.      */
  309.     public static LocalVariableInstruction createLoad(final Type type, final int index) {
  310.         switch (type.getType()) {
  311.         case Const.T_BOOLEAN:
  312.         case Const.T_CHAR:
  313.         case Const.T_BYTE:
  314.         case Const.T_SHORT:
  315.         case Const.T_INT:
  316.             return new ILOAD(index);
  317.         case Const.T_FLOAT:
  318.             return new FLOAD(index);
  319.         case Const.T_DOUBLE:
  320.             return new DLOAD(index);
  321.         case Const.T_LONG:
  322.             return new LLOAD(index);
  323.         case Const.T_ARRAY:
  324.         case Const.T_OBJECT:
  325.             return new ALOAD(index);
  326.         default:
  327.             throw new IllegalArgumentException("Invalid type " + type);
  328.         }
  329.     }

  330.     /**
  331.      * Create "null" value for reference types, 0 for basic types like int
  332.      */
  333.     public static Instruction createNull(final Type type) {
  334.         switch (type.getType()) {
  335.         case Const.T_ARRAY:
  336.         case Const.T_OBJECT:
  337.             return InstructionConst.ACONST_NULL;
  338.         case Const.T_INT:
  339.         case Const.T_SHORT:
  340.         case Const.T_BOOLEAN:
  341.         case Const.T_CHAR:
  342.         case Const.T_BYTE:
  343.             return InstructionConst.ICONST_0;
  344.         case Const.T_FLOAT:
  345.             return InstructionConst.FCONST_0;
  346.         case Const.T_DOUBLE:
  347.             return InstructionConst.DCONST_0;
  348.         case Const.T_LONG:
  349.             return InstructionConst.LCONST_0;
  350.         case Const.T_VOID:
  351.             return InstructionConst.NOP;
  352.         default:
  353.             throw new IllegalArgumentException("Invalid type: " + type);
  354.         }
  355.     }

  356.     /**
  357.      * @param size size of operand, either 1 (int, e.g.) or 2 (double)
  358.      */
  359.     public static StackInstruction createPop(final int size) {
  360.         return size == 2 ? InstructionConst.POP2 : InstructionConst.POP;
  361.     }

  362.     /**
  363.      * Create typed return
  364.      */
  365.     public static ReturnInstruction createReturn(final Type type) {
  366.         switch (type.getType()) {
  367.         case Const.T_ARRAY:
  368.         case Const.T_OBJECT:
  369.             return InstructionConst.ARETURN;
  370.         case Const.T_INT:
  371.         case Const.T_SHORT:
  372.         case Const.T_BOOLEAN:
  373.         case Const.T_CHAR:
  374.         case Const.T_BYTE:
  375.             return InstructionConst.IRETURN;
  376.         case Const.T_FLOAT:
  377.             return InstructionConst.FRETURN;
  378.         case Const.T_DOUBLE:
  379.             return InstructionConst.DRETURN;
  380.         case Const.T_LONG:
  381.             return InstructionConst.LRETURN;
  382.         case Const.T_VOID:
  383.             return InstructionConst.RETURN;
  384.         default:
  385.             throw new IllegalArgumentException("Invalid type: " + type);
  386.         }
  387.     }

  388.     /**
  389.      * @param index index of local variable
  390.      */
  391.     public static LocalVariableInstruction createStore(final Type type, final int index) {
  392.         switch (type.getType()) {
  393.         case Const.T_BOOLEAN:
  394.         case Const.T_CHAR:
  395.         case Const.T_BYTE:
  396.         case Const.T_SHORT:
  397.         case Const.T_INT:
  398.             return new ISTORE(index);
  399.         case Const.T_FLOAT:
  400.             return new FSTORE(index);
  401.         case Const.T_DOUBLE:
  402.             return new DSTORE(index);
  403.         case Const.T_LONG:
  404.             return new LSTORE(index);
  405.         case Const.T_ARRAY:
  406.         case Const.T_OBJECT:
  407.             return new ASTORE(index);
  408.         default:
  409.             throw new IllegalArgumentException("Invalid type " + type);
  410.         }
  411.     }

  412.     /**
  413.      * Create reference to 'this'
  414.      */
  415.     public static Instruction createThis() {
  416.         return new ALOAD(0);
  417.     }

  418.     private static boolean isString(final Type type) {
  419.         return type instanceof ObjectType && ((ObjectType) type).getClassName().equals("java.lang.String");
  420.     }

  421.     /**
  422.      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
  423.      */
  424.     @Deprecated
  425.     protected ClassGen cg;

  426.     /**
  427.      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
  428.      */
  429.     @Deprecated
  430.     protected ConstantPoolGen cp;

  431.     /**
  432.      * Initialize with ClassGen object
  433.      */
  434.     public InstructionFactory(final ClassGen cg) {
  435.         this(cg, cg.getConstantPool());
  436.     }

  437.     public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) {
  438.         this.cg = cg;
  439.         this.cp = cp;
  440.     }

  441.     /**
  442.      * Initialize just with ConstantPoolGen object
  443.      */
  444.     public InstructionFactory(final ConstantPoolGen cp) {
  445.         this(null, cp);
  446.     }

  447.     public Instruction createAppend(final Type type) {
  448.         final byte t = type.getType();
  449.         if (isString(type)) {
  450.             return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL);
  451.         }
  452.         switch (t) {
  453.         case Const.T_BOOLEAN:
  454.         case Const.T_CHAR:
  455.         case Const.T_FLOAT:
  456.         case Const.T_DOUBLE:
  457.         case Const.T_BYTE:
  458.         case Const.T_SHORT:
  459.         case Const.T_INT:
  460.         case Const.T_LONG:
  461.             return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL);
  462.         case Const.T_ARRAY:
  463.         case Const.T_OBJECT:
  464.             return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL);
  465.         default:
  466.             throw new IllegalArgumentException("No append for this type? " + type);
  467.         }
  468.     }

  469.     /**
  470.      * Create conversion operation for two stack operands, this may be an I2C, instruction, e.g., if the operands are basic
  471.      * types and CHECKCAST if they are reference types.
  472.      */
  473.     public Instruction createCast(final Type srcType, final Type destType) {
  474.         if (srcType instanceof BasicType && destType instanceof BasicType) {
  475.             final byte dest = destType.getType();
  476.             byte src = srcType.getType();
  477.             if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) {
  478.                 src = Const.T_INT;
  479.             }
  480.             final String name = "org.apache.bcel.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR];
  481.             Instruction i = null;
  482.             try {
  483.                 i = (Instruction) Class.forName(name).getConstructor().newInstance();
  484.             } catch (final Exception e) {
  485.                 throw new IllegalArgumentException("Could not find instruction: " + name, e);
  486.             }
  487.             return i;
  488.         }
  489.         if (!(srcType instanceof ReferenceType) || !(destType instanceof ReferenceType)) {
  490.             throw new IllegalArgumentException("Cannot cast " + srcType + " to " + destType);
  491.         }
  492.         if (destType instanceof ArrayType) {
  493.             return new CHECKCAST(cp.addArrayClass((ArrayType) destType));
  494.         }
  495.         return new CHECKCAST(cp.addClass(((ObjectType) destType).getClassName()));
  496.     }

  497.     public CHECKCAST createCheckCast(final ReferenceType t) {
  498.         if (t instanceof ArrayType) {
  499.             return new CHECKCAST(cp.addArrayClass((ArrayType) t));
  500.         }
  501.         return new CHECKCAST(cp.addClass((ObjectType) t));
  502.     }

  503.     /**
  504.      * Uses PUSH to push a constant value onto the stack.
  505.      *
  506.      * @param value must be of type Number, Boolean, Character or String
  507.      */
  508.     public Instruction createConstant(final Object value) {
  509.         PUSH push;
  510.         if (value instanceof Number) {
  511.             push = new PUSH(cp, (Number) value);
  512.         } else if (value instanceof String) {
  513.             push = new PUSH(cp, (String) value);
  514.         } else if (value instanceof Boolean) {
  515.             push = new PUSH(cp, (Boolean) value);
  516.         } else if (value instanceof Character) {
  517.             push = new PUSH(cp, (Character) value);
  518.         } else {
  519.             throw new ClassGenException("Illegal type: " + value.getClass());
  520.         }
  521.         return push.getInstruction();
  522.     }

  523.     /**
  524.      * Create a field instruction.
  525.      *
  526.      * @param className name of the accessed class
  527.      * @param name name of the referenced field
  528.      * @param type type of field
  529.      * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC
  530.      * @see Const
  531.      */
  532.     public FieldInstruction createFieldAccess(final String className, final String name, final Type type, final short kind) {
  533.         int index;
  534.         final String signature = type.getSignature();
  535.         index = cp.addFieldref(className, name, signature);
  536.         switch (kind) {
  537.         case Const.GETFIELD:
  538.             return new GETFIELD(index);
  539.         case Const.PUTFIELD:
  540.             return new PUTFIELD(index);
  541.         case Const.GETSTATIC:
  542.             return new GETSTATIC(index);
  543.         case Const.PUTSTATIC:
  544.             return new PUTSTATIC(index);
  545.         default:
  546.             throw new IllegalArgumentException("Unknown getfield kind:" + kind);
  547.         }
  548.     }

  549.     public GETFIELD createGetField(final String className, final String name, final Type t) {
  550.         return new GETFIELD(cp.addFieldref(className, name, t.getSignature()));
  551.     }

  552.     public GETSTATIC createGetStatic(final String className, final String name, final Type t) {
  553.         return new GETSTATIC(cp.addFieldref(className, name, t.getSignature()));
  554.     }

  555.     public INSTANCEOF createInstanceOf(final ReferenceType t) {
  556.         if (t instanceof ArrayType) {
  557.             return new INSTANCEOF(cp.addArrayClass((ArrayType) t));
  558.         }
  559.         return new INSTANCEOF(cp.addClass((ObjectType) t));
  560.     }

  561.     private InvokeInstruction createInvoke(final MethodObject m, final short kind) {
  562.         return createInvoke(m.className, m.name, m.resultType, m.argTypes, kind);
  563.     }

  564.     /**
  565.      * Create an invoke instruction. (Except for invokedynamic.)
  566.      *
  567.      * @param className name of the called class
  568.      * @param name name of the called method
  569.      * @param retType return type of method
  570.      * @param argTypes argument types of method
  571.      * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL
  572.      * @see Const
  573.      */
  574.     public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind) {
  575.         return createInvoke(className, name, retType, argTypes, kind, kind == Const.INVOKEINTERFACE);
  576.     }

  577.     /**
  578.      * Create an invoke instruction. (Except for invokedynamic.)
  579.      *
  580.      * @param className name of the called class
  581.      * @param name name of the called method
  582.      * @param retType return type of method
  583.      * @param argTypes argument types of method
  584.      * @param kind how to invoke: INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL
  585.      * @param useInterface force use of InterfaceMethodref
  586.      * @return A new InvokeInstruction.
  587.      * @since 6.5.0
  588.      */
  589.     public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind,
  590.         final boolean useInterface) {
  591.         if (kind != Const.INVOKESPECIAL && kind != Const.INVOKEVIRTUAL && kind != Const.INVOKESTATIC && kind != Const.INVOKEINTERFACE
  592.             && kind != Const.INVOKEDYNAMIC) {
  593.             throw new IllegalArgumentException("Unknown invoke kind: " + kind);
  594.         }
  595.         int index;
  596.         int nargs = 0;
  597.         final String signature = Type.getMethodSignature(retType, argTypes);
  598.         if (argTypes != null) {
  599.             for (final Type argType : argTypes) {
  600.                 nargs += argType.getSize();
  601.             }
  602.         }
  603.         if (useInterface) {
  604.             index = cp.addInterfaceMethodref(className, name, signature);
  605.         } else {
  606.             index = cp.addMethodref(className, name, signature);
  607.         }
  608.         switch (kind) {
  609.         case Const.INVOKESPECIAL:
  610.             return new INVOKESPECIAL(index);
  611.         case Const.INVOKEVIRTUAL:
  612.             return new INVOKEVIRTUAL(index);
  613.         case Const.INVOKESTATIC:
  614.             return new INVOKESTATIC(index);
  615.         case Const.INVOKEINTERFACE:
  616.             return new INVOKEINTERFACE(index, nargs + 1);
  617.         case Const.INVOKEDYNAMIC:
  618.             return new INVOKEDYNAMIC(index);
  619.         default:
  620.             // Can't happen
  621.             throw new IllegalStateException("Unknown invoke kind: " + kind);
  622.         }
  623.     }

  624.     public NEW createNew(final ObjectType t) {
  625.         return new NEW(cp.addClass(t));
  626.     }

  627.     public NEW createNew(final String s) {
  628.         return createNew(ObjectType.getInstance(s));
  629.     }

  630.     /**
  631.      * Create new array of given size and type.
  632.      *
  633.      * @return an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction
  634.      */
  635.     public Instruction createNewArray(final Type t, final short dim) {
  636.         if (dim == 1) {
  637.             if (t instanceof ObjectType) {
  638.                 return new ANEWARRAY(cp.addClass((ObjectType) t));
  639.             }
  640.             if (t instanceof ArrayType) {
  641.                 return new ANEWARRAY(cp.addArrayClass((ArrayType) t));
  642.             }
  643.             return new NEWARRAY(t.getType());
  644.         }
  645.         ArrayType at;
  646.         if (t instanceof ArrayType) {
  647.             at = (ArrayType) t;
  648.         } else {
  649.             at = new ArrayType(t, dim);
  650.         }
  651.         return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
  652.     }

  653.     /**
  654.      * Create a call to the most popular System.out.println() method.
  655.      *
  656.      * @param s the string to print
  657.      */
  658.     public InstructionList createPrintln(final String s) {
  659.         final InstructionList il = new InstructionList();
  660.         il.append(createGetStatic("java.lang.System", "out", Type.getType("Ljava/io/PrintStream;")));
  661.         il.append(new PUSH(cp, s));
  662.         final MethodObject methodObject = new MethodObject("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.getType("Ljava/lang/String;") });
  663.         il.append(createInvoke(methodObject, Const.INVOKEVIRTUAL));
  664.         return il;
  665.     }

  666.     public PUTFIELD createPutField(final String className, final String name, final Type t) {
  667.         return new PUTFIELD(cp.addFieldref(className, name, t.getSignature()));
  668.     }

  669.     public PUTSTATIC createPutStatic(final String className, final String name, final Type t) {
  670.         return new PUTSTATIC(cp.addFieldref(className, name, t.getSignature()));
  671.     }

  672.     public ClassGen getClassGen() {
  673.         return cg;
  674.     }

  675.     public ConstantPoolGen getConstantPool() {
  676.         return cp;
  677.     }

  678.     public void setClassGen(final ClassGen c) {
  679.         cg = c;
  680.     }

  681.     public void setConstantPool(final ConstantPoolGen c) {
  682.         cp = c;
  683.     }
  684. }