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