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