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