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