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