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