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