View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.bcel.generic;
20  
21  import org.apache.bcel.Const;
22  
23  /**
24   * Instances of this class may be used, for example, to generate typed versions of instructions. Its main purpose is to be used
25   * as the byte code generating backend of a compiler. You can subclass it to add your own create methods.
26   * <p>
27   * Note: The static createXXX methods return singleton instances from the {@link InstructionConst} class.
28   * </p>
29   *
30   * @see Const
31   * @see InstructionConst
32   */
33  public class InstructionFactory implements InstructionConstants {
34  
35      private static final class MethodObject {
36  
37          final Type[] argTypes;
38          final Type resultType;
39          final String className;
40          final String name;
41  
42          MethodObject(final String c, final String n, final Type r, final Type[] a) {
43              this.className = c;
44              this.name = n;
45              this.resultType = r;
46              this.argTypes = a;
47          }
48      }
49  
50      private static final String APPEND = "append";
51  
52      private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer";
53  
54      /**
55       * These must agree with the order of Constants.T_CHAR through T_LONG.
56       */
57      private static final String[] SHORT_NAMES = {"C", "F", "D", "B", "S", "I", "L"};
58  
59      private static final MethodObject[] APPEND_METHOD_OBJECTS = {
60              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.STRING }),
61              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.OBJECT }), null, null, // indices 2, 3
62              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }),
63              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.CHAR }),
64              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.FLOAT }),
65              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.DOUBLE }),
66              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }),
67              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), // No append(byte)
68              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), // No append(short)
69              new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.LONG })};
70  
71      /**
72       * @param type type of elements of array, i.e., array.getElementType()
73       */
74      public static ArrayInstruction createArrayLoad(final Type type) {
75          switch (type.getType()) {
76          case Const.T_BOOLEAN:
77          case Const.T_BYTE:
78              return InstructionConst.BALOAD;
79          case Const.T_CHAR:
80              return InstructionConst.CALOAD;
81          case Const.T_SHORT:
82              return InstructionConst.SALOAD;
83          case Const.T_INT:
84              return InstructionConst.IALOAD;
85          case Const.T_FLOAT:
86              return InstructionConst.FALOAD;
87          case Const.T_DOUBLE:
88              return InstructionConst.DALOAD;
89          case Const.T_LONG:
90              return InstructionConst.LALOAD;
91          case Const.T_ARRAY:
92          case Const.T_OBJECT:
93              return InstructionConst.AALOAD;
94          default:
95              throw new IllegalArgumentException("Invalid type " + type);
96          }
97      }
98  
99      /**
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 }