    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 */
    017package org.apache.bcel.generic;
    018
    019import org.apache.bcel.Const;
    020
    021/**
    022 * Instances of this class may be used, e.g., to generate typed versions of instructions. Its main purpose is to be used
    023 * as the byte code generating backend of a compiler. You can subclass it to add your own create methods.
    024 * <p>
    025 * Note: The static createXXX methods return singleton instances from the {@link InstructionConst} class.
    026 * </p>
    027 *
    028 * @see Const
    029 * @see InstructionConst
    030 */
    031public class InstructionFactory implements InstructionConstants {
    032
    033    private static final class MethodObject {
    034
    035        final Type[] argTypes;
    036        final Type resultType;
    037        final String className;
    038        final String name;
    039
    040        MethodObject(final String c, final String n, final Type r, final Type[] a) {
    041            this.className = c;
    042            this.name = n;
    043            this.resultType = r;
    044            this.argTypes = a;
    045        }
    046    }
    047
    048    private static final String APPEND = "append";
    049
    050    private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer";
    051
    052    /**
    053     * These must agree with the order of Constants.T_CHAR through T_LONG.
    054     */
    055    private static final String[] SHORT_NAMES = {"C", "F", "D", "B", "S", "I", "L"};
    056
    057    private static final MethodObject[] APPEND_METHOD_OBJECTS = {
    058            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.STRING }),
    059            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.OBJECT }), null, null, // indices 2, 3
    060            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }),
    061            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.CHAR }),
    062            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.FLOAT }),
    063            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.DOUBLE }),
    064            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }),
    065            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), // No append(byte)
    066            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), // No append(short)
    067            new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.LONG })};
    068
    069    /**
    070     * @param type type of elements of array, i.e., array.getElementType()
    071     */
    072    public static ArrayInstruction createArrayLoad(final Type type) {
    073        switch (type.getType()) {
    074        case Const.T_BOOLEAN:
    075        case Const.T_BYTE:
    076            return InstructionConst.BALOAD;
    077        case Const.T_CHAR:
    078            return InstructionConst.CALOAD;
    079        case Const.T_SHORT:
    080            return InstructionConst.SALOAD;
    081        case Const.T_INT:
    082            return InstructionConst.IALOAD;
    083        case Const.T_FLOAT:
    084            return InstructionConst.FALOAD;
    085        case Const.T_DOUBLE:
    086            return InstructionConst.DALOAD;
    087        case Const.T_LONG:
    088            return InstructionConst.LALOAD;
    089        case Const.T_ARRAY:
    090        case Const.T_OBJECT:
    091            return InstructionConst.AALOAD;
    092        default:
    093            throw new IllegalArgumentException("Invalid type " + type);
    094        }
    095    }
    096
    097    /**
    098     * @param type type of elements of array, i.e., array.getElementType()
    099     */
    100    public static ArrayInstruction createArrayStore(final Type type) {
    101        switch (type.getType()) {
    102        case Const.T_BOOLEAN:
    103        case Const.T_BYTE:
    104            return InstructionConst.BASTORE;
    105        case Const.T_CHAR:
    106            return InstructionConst.CASTORE;
    107        case Const.T_SHORT:
    108            return InstructionConst.SASTORE;
    109        case Const.T_INT:
    110            return InstructionConst.IASTORE;
    111        case Const.T_FLOAT:
    112            return InstructionConst.FASTORE;
    113        case Const.T_DOUBLE:
    114            return InstructionConst.DASTORE;
    115        case Const.T_LONG:
    116            return InstructionConst.LASTORE;
    117        case Const.T_ARRAY:
    118        case Const.T_OBJECT:
    119            return InstructionConst.AASTORE;
    120        default:
    121            throw new IllegalArgumentException("Invalid type " + type);
    122        }
    123    }
    124
    125    private static ArithmeticInstruction createBinaryDoubleOp(final char op) {
    126        switch (op) {
    127        case '-':
    128            return InstructionConst.DSUB;
    129        case '+':
    130            return InstructionConst.DADD;
    131        case '*':
    132            return InstructionConst.DMUL;
    133        case '/':
    134            return InstructionConst.DDIV;
    135        case '%':
    136            return InstructionConst.DREM;
    137        default:
    138            throw new IllegalArgumentException("Invalid operand " + op);
    139        }
    140    }
    141
    142    private static ArithmeticInstruction createBinaryFloatOp(final char op) {
    143        switch (op) {
    144        case '-':
    145            return InstructionConst.FSUB;
    146        case '+':
    147            return InstructionConst.FADD;
    148        case '*':
    149            return InstructionConst.FMUL;
    150        case '/':
    151            return InstructionConst.FDIV;
    152        case '%':
    153            return InstructionConst.FREM;
    154        default:
    155            throw new IllegalArgumentException("Invalid operand " + op);
    156        }
    157    }
    158
    159    private static ArithmeticInstruction createBinaryIntOp(final char first, final String op) {
    160        switch (first) {
    161        case '-':
    162            return InstructionConst.ISUB;
    163        case '+':
    164            return InstructionConst.IADD;
    165        case '%':
    166            return InstructionConst.IREM;
    167        case '*':
    168            return InstructionConst.IMUL;
    169        case '/':
    170            return InstructionConst.IDIV;
    171        case '&':
    172            return InstructionConst.IAND;
    173        case '|':
    174            return InstructionConst.IOR;
    175        case '^':
    176            return InstructionConst.IXOR;
    177        case '<':
    178            return InstructionConst.ISHL;
    179        case '>':
    180            return op.equals(">>>") ? InstructionConst.IUSHR : InstructionConst.ISHR;
    181        default:
    182            throw new IllegalArgumentException("Invalid operand " + op);
    183        }
    184    }
    185
    186    /**
    187     * Create an invokedynamic instruction.
    188     *
    189     * @param bootstrap_index index into the bootstrap_methods array
    190     * @param name name of the called method
    191     * @param ret_type return type of method
    192     * @param argTypes argument types of method
    193     * @see Const
    194     */
    195
    196    /*
    197     * createInvokeDynamic only needed if instrumentation code wants to generate a new invokedynamic instruction. I don't
    198     * think we need.
    199     *
    200     * public InvokeInstruction createInvokeDynamic( int bootstrap_index, String name, Type ret_type, Type[] argTypes) {
    201     * int index; int nargs = 0; String signature = Type.getMethodSignature(ret_type, argTypes); for (int i = 0; i <
    202     * argTypes.length; i++) { nargs += argTypes[i].getSize(); } // UNDONE - needs to be added to ConstantPoolGen //index
    203     * = cp.addInvokeDynamic(bootstrap_index, name, signature); index = 0; return new INVOKEDYNAMIC(index); }
    204     */
    205
    206    private static ArithmeticInstruction createBinaryLongOp(final char first, final String op) {
    207        switch (first) {
    208        case '-':
    209            return InstructionConst.LSUB;
    210        case '+':
    211            return InstructionConst.LADD;
    212        case '%':
    213            return InstructionConst.LREM;
    214        case '*':
    215            return InstructionConst.LMUL;
    216        case '/':
    217            return InstructionConst.LDIV;
    218        case '&':
    219            return InstructionConst.LAND;
    220        case '|':
    221            return InstructionConst.LOR;
    222        case '^':
    223            return InstructionConst.LXOR;
    224        case '<':
    225            return InstructionConst.LSHL;
    226        case '>':
    227            return op.equals(">>>") ? InstructionConst.LUSHR : InstructionConst.LSHR;
    228        default:
    229            throw new IllegalArgumentException("Invalid operand " + op);
    230        }
    231    }
    232
    233    /**
    234     * Create binary operation for simple basic types, such as int and float.
    235     *
    236     * @param op operation, such as "+", "*", "&lt;&lt;", etc.
    237     */
    238    public static ArithmeticInstruction createBinaryOperation(final String op, final Type type) {
    239        final char first = op.charAt(0);
    240        switch (type.getType()) {
    241        case Const.T_BYTE:
    242        case Const.T_SHORT:
    243        case Const.T_INT:
    244        case Const.T_CHAR:
    245            return createBinaryIntOp(first, op);
    246        case Const.T_LONG:
    247            return createBinaryLongOp(first, op);
    248        case Const.T_FLOAT:
    249            return createBinaryFloatOp(first);
    250        case Const.T_DOUBLE:
    251            return createBinaryDoubleOp(first);
    252        default:
    253            throw new IllegalArgumentException("Invalid type " + type);
    254        }
    255    }
    256
    257    /**
    258     * Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH. For those you should use the SWITCH
    259     * compound instruction.
    260     */
    261    public static BranchInstruction createBranchInstruction(final short opcode, final InstructionHandle target) {
    262        switch (opcode) {
    263        case Const.IFEQ:
    264            return new IFEQ(target);
    265        case Const.IFNE:
    266            return new IFNE(target);
    267        case Const.IFLT:
    268            return new IFLT(target);
    269        case Const.IFGE:
    270            return new IFGE(target);
    271        case Const.IFGT:
    272            return new IFGT(target);
    273        case Const.IFLE:
    274            return new IFLE(target);
    275        case Const.IF_ICMPEQ:
    276            return new IF_ICMPEQ(target);
    277        case Const.IF_ICMPNE:
    278            return new IF_ICMPNE(target);
    279        case Const.IF_ICMPLT:
    280            return new IF_ICMPLT(target);
    281        case Const.IF_ICMPGE:
    282            return new IF_ICMPGE(target);
    283        case Const.IF_ICMPGT:
    284            return new IF_ICMPGT(target);
    285        case Const.IF_ICMPLE:
    286            return new IF_ICMPLE(target);
    287        case Const.IF_ACMPEQ:
    288            return new IF_ACMPEQ(target);
    289        case Const.IF_ACMPNE:
    290            return new IF_ACMPNE(target);
    291        case Const.GOTO:
    292            return new GOTO(target);
    293        case Const.JSR:
    294            return new JSR(target);
    295        case Const.IFNULL:
    296            return new IFNULL(target);
    297        case Const.IFNONNULL:
    298            return new IFNONNULL(target);
    299        case Const.GOTO_W:
    300            return new GOTO_W(target);
    301        case Const.JSR_W:
    302            return new JSR_W(target);
    303        default:
    304            throw new IllegalArgumentException("Invalid opcode: " + opcode);
    305        }
    306    }
    307
    308    /**
    309     * @param size size of operand, either 1 (int, e.g.) or 2 (double)
    310     */
    311    public static StackInstruction createDup(final int size) {
    312        return size == 2 ? InstructionConst.DUP2 : InstructionConst.DUP;
    313    }
    314
    315    /**
    316     * @param size size of operand, either 1 (int, e.g.) or 2 (double)
    317     */
    318    public static StackInstruction createDup_1(final int size) {
    319        return size == 2 ? InstructionConst.DUP2_X1 : InstructionConst.DUP_X1;
    320    }
    321
    322    /**
    323     * @param size size of operand, either 1 (int, e.g.) or 2 (double)
    324     */
    325    public static StackInstruction createDup_2(final int size) {
    326        return size == 2 ? InstructionConst.DUP2_X2 : InstructionConst.DUP_X2;
    327    }
    328
    329    /**
    330     * @param index index of local variable
    331     */
    332    public static LocalVariableInstruction createLoad(final Type type, final int index) {
    333        switch (type.getType()) {
    334        case Const.T_BOOLEAN:
    335        case Const.T_CHAR:
    336        case Const.T_BYTE:
    337        case Const.T_SHORT:
    338        case Const.T_INT:
    339            return new ILOAD(index);
    340        case Const.T_FLOAT:
    341            return new FLOAD(index);
    342        case Const.T_DOUBLE:
    343            return new DLOAD(index);
    344        case Const.T_LONG:
    345            return new LLOAD(index);
    346        case Const.T_ARRAY:
    347        case Const.T_OBJECT:
    348            return new ALOAD(index);
    349        default:
    350            throw new IllegalArgumentException("Invalid type " + type);
    351        }
    352    }
    353
    354    /**
    355     * Create "null" value for reference types, 0 for basic types like int
    356     */
    357    public static Instruction createNull(final Type type) {
    358        switch (type.getType()) {
    359        case Const.T_ARRAY:
    360        case Const.T_OBJECT:
    361            return InstructionConst.ACONST_NULL;
    362        case Const.T_INT:
    363        case Const.T_SHORT:
    364        case Const.T_BOOLEAN:
    365        case Const.T_CHAR:
    366        case Const.T_BYTE:
    367            return InstructionConst.ICONST_0;
    368        case Const.T_FLOAT:
    369            return InstructionConst.FCONST_0;
    370        case Const.T_DOUBLE:
    371            return InstructionConst.DCONST_0;
    372        case Const.T_LONG:
    373            return InstructionConst.LCONST_0;
    374        case Const.T_VOID:
    375            return InstructionConst.NOP;
    376        default:
    377            throw new IllegalArgumentException("Invalid type: " + type);
    378        }
    379    }
    380
    381    /**
    382     * @param size size of operand, either 1 (int, e.g.) or 2 (double)
    383     */
    384    public static StackInstruction createPop(final int size) {
    385        return size == 2 ? InstructionConst.POP2 : InstructionConst.POP;
    386    }
    387
    388    /**
    389     * Create typed return
    390     */
    391    public static ReturnInstruction createReturn(final Type type) {
    392        switch (type.getType()) {
    393        case Const.T_ARRAY:
    394        case Const.T_OBJECT:
    395            return InstructionConst.ARETURN;
    396        case Const.T_INT:
    397        case Const.T_SHORT:
    398        case Const.T_BOOLEAN:
    399        case Const.T_CHAR:
    400        case Const.T_BYTE:
    401            return InstructionConst.IRETURN;
    402        case Const.T_FLOAT:
    403            return InstructionConst.FRETURN;
    404        case Const.T_DOUBLE:
    405            return InstructionConst.DRETURN;
    406        case Const.T_LONG:
    407            return InstructionConst.LRETURN;
    408        case Const.T_VOID:
    409            return InstructionConst.RETURN;
    410        default:
    411            throw new IllegalArgumentException("Invalid type: " + type);
    412        }
    413    }
    414
    415    /**
    416     * @param index index of local variable
    417     */
    418    public static LocalVariableInstruction createStore(final Type type, final int index) {
    419        switch (type.getType()) {
    420        case Const.T_BOOLEAN:
    421        case Const.T_CHAR:
    422        case Const.T_BYTE:
    423        case Const.T_SHORT:
    424        case Const.T_INT:
    425            return new ISTORE(index);
    426        case Const.T_FLOAT:
    427            return new FSTORE(index);
    428        case Const.T_DOUBLE:
    429            return new DSTORE(index);
    430        case Const.T_LONG:
    431            return new LSTORE(index);
    432        case Const.T_ARRAY:
    433        case Const.T_OBJECT:
    434            return new ASTORE(index);
    435        default:
    436            throw new IllegalArgumentException("Invalid type " + type);
    437        }
    438    }
    439
    440    /**
    441     * Create reference to 'this'
    442     */
    443    public static Instruction createThis() {
    444        return new ALOAD(0);
    445    }
    446
    447    private static boolean isString(final Type type) {
    448        return type instanceof ObjectType && ((ObjectType) type).getClassName().equals("java.lang.String");
    449    }
    450
    451    /**
    452     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    453     */
    454    @Deprecated
    455    protected ClassGen cg;
    456
    457    /**
    458     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    459     */
    460    @Deprecated
    461    protected ConstantPoolGen cp;
    462
    463    /**
    464     * Initialize with ClassGen object
    465     */
    466    public InstructionFactory(final ClassGen cg) {
    467        this(cg, cg.getConstantPool());
    468    }
    469
    470    public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) {
    471        this.cg = cg;
    472        this.cp = cp;
    473    }
    474
    475    /**
    476     * Initialize just with ConstantPoolGen object
    477     */
    478    public InstructionFactory(final ConstantPoolGen cp) {
    479        this(null, cp);
    480    }
    481
    482    public Instruction createAppend(final Type type) {
    483        final byte t = type.getType();
    484        if (isString(type)) {
    485            return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL);
    486        }
    487        switch (t) {
    488        case Const.T_BOOLEAN:
    489        case Const.T_CHAR:
    490        case Const.T_FLOAT:
    491        case Const.T_DOUBLE:
    492        case Const.T_BYTE:
    493        case Const.T_SHORT:
    494        case Const.T_INT:
    495        case Const.T_LONG:
    496            return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL);
    497        case Const.T_ARRAY:
    498        case Const.T_OBJECT:
    499            return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL);
    500        default:
    501            throw new IllegalArgumentException("No append for this type? " + type);
    502        }
    503    }
    504
    505    /**
    506     * Create conversion operation for two stack operands, this may be an I2C, instruction, e.g., if the operands are basic
    507     * types and CHECKCAST if they are reference types.
    508     */
    509    public Instruction createCast(final Type srcType, final Type destType) {
    510        if (srcType instanceof BasicType && destType instanceof BasicType) {
    511            final byte dest = destType.getType();
    512            byte src = srcType.getType();
    513            if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) {
    514                src = Const.T_INT;
    515            }
    516            final String name = "org.apache.bcel.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR];
    517            Instruction i = null;
    518            try {
    519                i = (Instruction) Class.forName(name).getConstructor().newInstance();
    520            } catch (final Exception e) {
    521                throw new IllegalArgumentException("Could not find instruction: " + name, e);
    522            }
    523            return i;
    524        }
    525        if (!(srcType instanceof ReferenceType) || !(destType instanceof ReferenceType)) {
    526            throw new IllegalArgumentException("Cannot cast " + srcType + " to " + destType);
    527        }
    528        if (destType instanceof ArrayType) {
    529            return new CHECKCAST(cp.addArrayClass((ArrayType) destType));
    530        }
    531        return new CHECKCAST(cp.addClass(((ObjectType) destType).getClassName()));
    532    }
    533
    534    public CHECKCAST createCheckCast(final ReferenceType t) {
    535        if (t instanceof ArrayType) {
    536            return new CHECKCAST(cp.addArrayClass((ArrayType) t));
    537        }
    538        return new CHECKCAST(cp.addClass((ObjectType) t));
    539    }
    540
    541    /**
    542     * Uses PUSH to push a constant value onto the stack.
    543     *
    544     * @param value must be of type Number, Boolean, Character or String
    545     */
    546    public Instruction createConstant(final Object value) {
    547        PUSH push;
    548        if (value instanceof Number) {
    549            push = new PUSH(cp, (Number) value);
    550        } else if (value instanceof String) {
    551            push = new PUSH(cp, (String) value);
    552        } else if (value instanceof Boolean) {
    553            push = new PUSH(cp, (Boolean) value);
    554        } else if (value instanceof Character) {
    555            push = new PUSH(cp, (Character) value);
    556        } else {
    557            throw new ClassGenException("Illegal type: " + value.getClass());
    558        }
    559        return push.getInstruction();
    560    }
    561
    562    /**
    563     * Create a field instruction.
    564     *
    565     * @param className name of the accessed class
    566     * @param name name of the referenced field
    567     * @param type type of field
    568     * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC
    569     * @see Const
    570     */
    571    public FieldInstruction createFieldAccess(final String className, final String name, final Type type, final short kind) {
    572        int index;
    573        final String signature = type.getSignature();
    574        index = cp.addFieldref(className, name, signature);
    575        switch (kind) {
    576        case Const.GETFIELD:
    577            return new GETFIELD(index);
    578        case Const.PUTFIELD:
    579            return new PUTFIELD(index);
    580        case Const.GETSTATIC:
    581            return new GETSTATIC(index);
    582        case Const.PUTSTATIC:
    583            return new PUTSTATIC(index);
    584        default:
    585            throw new IllegalArgumentException("Unknown getfield kind:" + kind);
    586        }
    587    }
    588
    589    public GETFIELD createGetField(final String className, final String name, final Type t) {
    590        return new GETFIELD(cp.addFieldref(className, name, t.getSignature()));
    591    }
    592
    593    public GETSTATIC createGetStatic(final String className, final String name, final Type t) {
    594        return new GETSTATIC(cp.addFieldref(className, name, t.getSignature()));
    595    }
    596
    597    public INSTANCEOF createInstanceOf(final ReferenceType t) {
    598        if (t instanceof ArrayType) {
    599            return new INSTANCEOF(cp.addArrayClass((ArrayType) t));
    600        }
    601        return new INSTANCEOF(cp.addClass((ObjectType) t));
    602    }
    603
    604    private InvokeInstruction createInvoke(final MethodObject m, final short kind) {
    605        return createInvoke(m.className, m.name, m.resultType, m.argTypes, kind);
    606    }
    607
    608    /**
    609     * Create an invoke instruction. (Except for invokedynamic.)
    610     *
    611     * @param className name of the called class
    612     * @param name name of the called method
    613     * @param retType return type of method
    614     * @param argTypes argument types of method
    615     * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL
    616     * @see Const
    617     */
    618    public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind) {
    619        return createInvoke(className, name, retType, argTypes, kind, kind == Const.INVOKEINTERFACE);
    620    }
    621
    622    /**
    623     * Create an invoke instruction. (Except for invokedynamic.)
    624     *
    625     * @param className name of the called class
    626     * @param name name of the called method
    627     * @param retType return type of method
    628     * @param argTypes argument types of method
    629     * @param kind how to invoke: INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL
    630     * @param useInterface force use of InterfaceMethodref
    631     * @return A new InvokeInstruction.
    632     * @since 6.5.0
    633     */
    634    public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind,
    635        final boolean useInterface) {
    636        if (kind != Const.INVOKESPECIAL && kind != Const.INVOKEVIRTUAL && kind != Const.INVOKESTATIC && kind != Const.INVOKEINTERFACE
    637            && kind != Const.INVOKEDYNAMIC) {
    638            throw new IllegalArgumentException("Unknown invoke kind: " + kind);
    639        }
    640        int index;
    641        int nargs = 0;
    642        final String signature = Type.getMethodSignature(retType, argTypes);
    643        if (argTypes != null) {
    644            for (final Type argType : argTypes) {
    645                nargs += argType.getSize();
    646            }
    647        }
    648        if (useInterface) {
    649            index = cp.addInterfaceMethodref(className, name, signature);
    650        } else {
    651            index = cp.addMethodref(className, name, signature);
    652        }
    653        switch (kind) {
    654        case Const.INVOKESPECIAL:
    655            return new INVOKESPECIAL(index);
    656        case Const.INVOKEVIRTUAL:
    657            return new INVOKEVIRTUAL(index);
    658        case Const.INVOKESTATIC:
    659            return new INVOKESTATIC(index);
    660        case Const.INVOKEINTERFACE:
    661            return new INVOKEINTERFACE(index, nargs + 1);
    662        case Const.INVOKEDYNAMIC:
    663            return new INVOKEDYNAMIC(index);
    664        default:
    665            // Can't happen
    666            throw new IllegalStateException("Unknown invoke kind: " + kind);
    667        }
    668    }
    669
    670    public NEW createNew(final ObjectType t) {
    671        return new NEW(cp.addClass(t));
    672    }
    673
    674    public NEW createNew(final String s) {
    675        return createNew(ObjectType.getInstance(s));
    676    }
    677
    678    /**
    679     * Create new array of given size and type.
    680     *
    681     * @return an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction
    682     */
    683    public Instruction createNewArray(final Type t, final short dim) {
    684        if (dim == 1) {
    685            if (t instanceof ObjectType) {
    686                return new ANEWARRAY(cp.addClass((ObjectType) t));
    687            }
    688            if (t instanceof ArrayType) {
    689                return new ANEWARRAY(cp.addArrayClass((ArrayType) t));
    690            }
    691            return new NEWARRAY(t.getType());
    692        }
    693        ArrayType at;
    694        if (t instanceof ArrayType) {
    695            at = (ArrayType) t;
    696        } else {
    697            at = new ArrayType(t, dim);
    698        }
    699        return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
    700    }
    701
    702    /**
    703     * Create a call to the most popular System.out.println() method.
    704     *
    705     * @param s the string to print
    706     */
    707    public InstructionList createPrintln(final String s) {
    708        final InstructionList il = new InstructionList();
    709        il.append(createGetStatic("java.lang.System", "out", Type.getType("Ljava/io/PrintStream;")));
    710        il.append(new PUSH(cp, s));
    711        final MethodObject methodObject = new MethodObject("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.getType("Ljava/lang/String;") });
    712        il.append(createInvoke(methodObject, Const.INVOKEVIRTUAL));
    713        return il;
    714    }
    715
    716    public PUTFIELD createPutField(final String className, final String name, final Type t) {
    717        return new PUTFIELD(cp.addFieldref(className, name, t.getSignature()));
    718    }
    719
    720    public PUTSTATIC createPutStatic(final String className, final String name, final Type t) {
    721        return new PUTSTATIC(cp.addFieldref(className, name, t.getSignature()));
    722    }
    723
    724    public ClassGen getClassGen() {
    725        return cg;
    726    }
    727
    728    public ConstantPoolGen getConstantPool() {
    729        return cp;
    730    }
    731
    732    public void setClassGen(final ClassGen c) {
    733        cg = c;
    734    }
    735
    736    public void setConstantPool(final ConstantPoolGen c) {
    737        cp = c;
    738    }
    739}