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