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       * Creates an array load instruction for the given type.
73       *
74       * @param type type of elements of array, that is, array.getElementType().
75       * @return The array load instruction.
76       */
77      public static ArrayInstruction createArrayLoad(final Type type) {
78          switch (type.getType()) {
79          case Const.T_BOOLEAN:
80          case Const.T_BYTE:
81              return InstructionConst.BALOAD;
82          case Const.T_CHAR:
83              return InstructionConst.CALOAD;
84          case Const.T_SHORT:
85              return InstructionConst.SALOAD;
86          case Const.T_INT:
87              return InstructionConst.IALOAD;
88          case Const.T_FLOAT:
89              return InstructionConst.FALOAD;
90          case Const.T_DOUBLE:
91              return InstructionConst.DALOAD;
92          case Const.T_LONG:
93              return InstructionConst.LALOAD;
94          case Const.T_ARRAY:
95          case Const.T_OBJECT:
96              return InstructionConst.AALOAD;
97          default:
98              throw new IllegalArgumentException("Invalid type " + type);
99          }
100     }
101 
102     /**
103      * Creates an array store instruction for the given type.
104      *
105      * @param type type of elements of array, that is, array.getElementType().
106      * @return The array store instruction.
107      */
108     public static ArrayInstruction createArrayStore(final Type type) {
109         switch (type.getType()) {
110         case Const.T_BOOLEAN:
111         case Const.T_BYTE:
112             return InstructionConst.BASTORE;
113         case Const.T_CHAR:
114             return InstructionConst.CASTORE;
115         case Const.T_SHORT:
116             return InstructionConst.SASTORE;
117         case Const.T_INT:
118             return InstructionConst.IASTORE;
119         case Const.T_FLOAT:
120             return InstructionConst.FASTORE;
121         case Const.T_DOUBLE:
122             return InstructionConst.DASTORE;
123         case Const.T_LONG:
124             return InstructionConst.LASTORE;
125         case Const.T_ARRAY:
126         case Const.T_OBJECT:
127             return InstructionConst.AASTORE;
128         default:
129             throw new IllegalArgumentException("Invalid type " + type);
130         }
131     }
132 
133     private static ArithmeticInstruction createBinaryDoubleOp(final char op) {
134         switch (op) {
135         case '-':
136             return InstructionConst.DSUB;
137         case '+':
138             return InstructionConst.DADD;
139         case '*':
140             return InstructionConst.DMUL;
141         case '/':
142             return InstructionConst.DDIV;
143         case '%':
144             return InstructionConst.DREM;
145         default:
146             throw new IllegalArgumentException("Invalid operand " + op);
147         }
148     }
149 
150     private static ArithmeticInstruction createBinaryFloatOp(final char op) {
151         switch (op) {
152         case '-':
153             return InstructionConst.FSUB;
154         case '+':
155             return InstructionConst.FADD;
156         case '*':
157             return InstructionConst.FMUL;
158         case '/':
159             return InstructionConst.FDIV;
160         case '%':
161             return InstructionConst.FREM;
162         default:
163             throw new IllegalArgumentException("Invalid operand " + op);
164         }
165     }
166 
167     private static ArithmeticInstruction createBinaryIntOp(final char first, final String op) {
168         switch (first) {
169         case '-':
170             return InstructionConst.ISUB;
171         case '+':
172             return InstructionConst.IADD;
173         case '%':
174             return InstructionConst.IREM;
175         case '*':
176             return InstructionConst.IMUL;
177         case '/':
178             return InstructionConst.IDIV;
179         case '&':
180             return InstructionConst.IAND;
181         case '|':
182             return InstructionConst.IOR;
183         case '^':
184             return InstructionConst.IXOR;
185         case '<':
186             return InstructionConst.ISHL;
187         case '>':
188             return op.equals(">>>") ? InstructionConst.IUSHR : InstructionConst.ISHR;
189         default:
190             throw new IllegalArgumentException("Invalid operand " + op);
191         }
192     }
193 
194     /**
195      * Create an invokedynamic instruction.
196      *
197      * @param bootstrap_index index into the bootstrap_methods array.
198      * @param name name of the called method.
199      * @param ret_type return type of method.
200      * @param argTypes argument types of method.
201      * @see Const
202      */
203 
204     /*
205      * createInvokeDynamic only needed if instrumentation code wants to generate a new invokedynamic instruction. I don't
206      * think we need.
207      *
208      * public InvokeInstruction createInvokeDynamic( int bootstrap_index, String name, Type ret_type, Type[] argTypes) {
209      * int index; int nargs = 0; String signature = Type.getMethodSignature(ret_type, argTypes); for (int i = 0; i <
210      * argTypes.length; i++) { nargs += argTypes[i].getSize(); } // UNDONE - needs to be added to ConstantPoolGen //index
211      * = cp.addInvokeDynamic(bootstrap_index, name, signature); index = 0; return new INVOKEDYNAMIC(index); }
212      */
213 
214     private static ArithmeticInstruction createBinaryLongOp(final char first, final String op) {
215         switch (first) {
216         case '-':
217             return InstructionConst.LSUB;
218         case '+':
219             return InstructionConst.LADD;
220         case '%':
221             return InstructionConst.LREM;
222         case '*':
223             return InstructionConst.LMUL;
224         case '/':
225             return InstructionConst.LDIV;
226         case '&':
227             return InstructionConst.LAND;
228         case '|':
229             return InstructionConst.LOR;
230         case '^':
231             return InstructionConst.LXOR;
232         case '<':
233             return InstructionConst.LSHL;
234         case '>':
235             return op.equals(">>>") ? InstructionConst.LUSHR : InstructionConst.LSHR;
236         default:
237             throw new IllegalArgumentException("Invalid operand " + op);
238         }
239     }
240 
241     /**
242      * Create binary operation for simple basic types, such as int and float.
243      *
244      * @param op operation, such as "+", "*", "&lt;&lt;", etc.
245      * @param type The operand type.
246      * @return The binary arithmetic instruction.
247      */
248     public static ArithmeticInstruction createBinaryOperation(final String op, final Type type) {
249         final char first = op.charAt(0);
250         switch (type.getType()) {
251         case Const.T_BYTE:
252         case Const.T_SHORT:
253         case Const.T_INT:
254         case Const.T_CHAR:
255             return createBinaryIntOp(first, op);
256         case Const.T_LONG:
257             return createBinaryLongOp(first, op);
258         case Const.T_FLOAT:
259             return createBinaryFloatOp(first);
260         case Const.T_DOUBLE:
261             return createBinaryDoubleOp(first);
262         default:
263             throw new IllegalArgumentException("Invalid type " + type);
264         }
265     }
266 
267     /**
268      * Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH. For those you should use the SWITCH
269      * compound instruction.
270      *
271      * @param opcode The branch opcode.
272      * @param target The target instruction handle.
273      * @return The branch instruction.
274      */
275     public static BranchInstruction createBranchInstruction(final short opcode, final InstructionHandle target) {
276         switch (opcode) {
277         case Const.IFEQ:
278             return new IFEQ(target);
279         case Const.IFNE:
280             return new IFNE(target);
281         case Const.IFLT:
282             return new IFLT(target);
283         case Const.IFGE:
284             return new IFGE(target);
285         case Const.IFGT:
286             return new IFGT(target);
287         case Const.IFLE:
288             return new IFLE(target);
289         case Const.IF_ICMPEQ:
290             return new IF_ICMPEQ(target);
291         case Const.IF_ICMPNE:
292             return new IF_ICMPNE(target);
293         case Const.IF_ICMPLT:
294             return new IF_ICMPLT(target);
295         case Const.IF_ICMPGE:
296             return new IF_ICMPGE(target);
297         case Const.IF_ICMPGT:
298             return new IF_ICMPGT(target);
299         case Const.IF_ICMPLE:
300             return new IF_ICMPLE(target);
301         case Const.IF_ACMPEQ:
302             return new IF_ACMPEQ(target);
303         case Const.IF_ACMPNE:
304             return new IF_ACMPNE(target);
305         case Const.GOTO:
306             return new GOTO(target);
307         case Const.JSR:
308             return new JSR(target);
309         case Const.IFNULL:
310             return new IFNULL(target);
311         case Const.IFNONNULL:
312             return new IFNONNULL(target);
313         case Const.GOTO_W:
314             return new GOTO_W(target);
315         case Const.JSR_W:
316             return new JSR_W(target);
317         default:
318             throw new IllegalArgumentException("Invalid opcode: " + opcode);
319         }
320     }
321 
322     /**
323      * Creates a DUP instruction.
324      *
325      * @param size size of operand, either 1 (int, for example) or 2 (double).
326      * @return The DUP instruction.
327      */
328     public static StackInstruction createDup(final int size) {
329         return size == 2 ? InstructionConst.DUP2 : InstructionConst.DUP;
330     }
331 
332     /**
333      * Creates a DUP_X1 instruction.
334      *
335      * @param size size of operand, either 1 (int, for example) or 2 (double).
336      * @return The DUP instruction.
337      */
338     public static StackInstruction createDup_1(final int size) {
339         return size == 2 ? InstructionConst.DUP2_X1 : InstructionConst.DUP_X1;
340     }
341 
342     /**
343      * Creates a DUP_X2 instruction.
344      *
345      * @param size size of operand, either 1 (int, for example) or 2 (double).
346      * @return The DUP instruction.
347      */
348     public static StackInstruction createDup_2(final int size) {
349         return size == 2 ? InstructionConst.DUP2_X2 : InstructionConst.DUP_X2;
350     }
351 
352     /**
353      * Creates a load instruction for the given type.
354      *
355      * @param type The variable type.
356      * @param index index of local variable.
357      * @return The load instruction.
358      */
359     public static LocalVariableInstruction createLoad(final Type type, final int index) {
360         switch (type.getType()) {
361         case Const.T_BOOLEAN:
362         case Const.T_CHAR:
363         case Const.T_BYTE:
364         case Const.T_SHORT:
365         case Const.T_INT:
366             return new ILOAD(index);
367         case Const.T_FLOAT:
368             return new FLOAD(index);
369         case Const.T_DOUBLE:
370             return new DLOAD(index);
371         case Const.T_LONG:
372             return new LLOAD(index);
373         case Const.T_ARRAY:
374         case Const.T_OBJECT:
375             return new ALOAD(index);
376         default:
377             throw new IllegalArgumentException("Invalid type " + type);
378         }
379     }
380 
381     /**
382      * Create "null" value for reference types, 0 for basic types like int.
383      *
384      * @param type The type.
385      * @return The null or zero instruction.
386      */
387     public static Instruction createNull(final Type type) {
388         switch (type.getType()) {
389         case Const.T_ARRAY:
390         case Const.T_OBJECT:
391             return InstructionConst.ACONST_NULL;
392         case Const.T_INT:
393         case Const.T_SHORT:
394         case Const.T_BOOLEAN:
395         case Const.T_CHAR:
396         case Const.T_BYTE:
397             return InstructionConst.ICONST_0;
398         case Const.T_FLOAT:
399             return InstructionConst.FCONST_0;
400         case Const.T_DOUBLE:
401             return InstructionConst.DCONST_0;
402         case Const.T_LONG:
403             return InstructionConst.LCONST_0;
404         case Const.T_VOID:
405             return InstructionConst.NOP;
406         default:
407             throw new IllegalArgumentException("Invalid type: " + type);
408         }
409     }
410 
411     /**
412      * Creates a pop instruction.
413      *
414      * @param size size of operand, either 1 (int, for example) or 2 (double).
415      * @return The pop instruction.
416      */
417     public static StackInstruction createPop(final int size) {
418         return size == 2 ? InstructionConst.POP2 : InstructionConst.POP;
419     }
420 
421     /**
422      * Create typed return.
423      *
424      * @param type The return type.
425      * @return The return instruction.
426      */
427     public static ReturnInstruction createReturn(final Type type) {
428         switch (type.getType()) {
429         case Const.T_ARRAY:
430         case Const.T_OBJECT:
431             return InstructionConst.ARETURN;
432         case Const.T_INT:
433         case Const.T_SHORT:
434         case Const.T_BOOLEAN:
435         case Const.T_CHAR:
436         case Const.T_BYTE:
437             return InstructionConst.IRETURN;
438         case Const.T_FLOAT:
439             return InstructionConst.FRETURN;
440         case Const.T_DOUBLE:
441             return InstructionConst.DRETURN;
442         case Const.T_LONG:
443             return InstructionConst.LRETURN;
444         case Const.T_VOID:
445             return InstructionConst.RETURN;
446         default:
447             throw new IllegalArgumentException("Invalid type: " + type);
448         }
449     }
450 
451     /**
452      * Creates a store instruction.
453      *
454      * @param type The variable type.
455      * @param index index of local variable.
456      * @return The store instruction.
457      */
458     public static LocalVariableInstruction createStore(final Type type, final int index) {
459         switch (type.getType()) {
460         case Const.T_BOOLEAN:
461         case Const.T_CHAR:
462         case Const.T_BYTE:
463         case Const.T_SHORT:
464         case Const.T_INT:
465             return new ISTORE(index);
466         case Const.T_FLOAT:
467             return new FSTORE(index);
468         case Const.T_DOUBLE:
469             return new DSTORE(index);
470         case Const.T_LONG:
471             return new LSTORE(index);
472         case Const.T_ARRAY:
473         case Const.T_OBJECT:
474             return new ASTORE(index);
475         default:
476             throw new IllegalArgumentException("Invalid type " + type);
477         }
478     }
479 
480     /**
481      * Create reference to 'this'.
482      *
483      * @return reference to 'this'.
484      */
485     public static Instruction createThis() {
486         return new ALOAD(0);
487     }
488 
489     private static boolean isString(final Type type) {
490         return type instanceof ObjectType && ((ObjectType) type).getClassName().equals("java.lang.String");
491     }
492 
493     /**
494      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
495      */
496     @Deprecated
497     protected ClassGen cg;
498 
499     /**
500      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
501      */
502     @Deprecated
503     protected ConstantPoolGen cp;
504 
505     /**
506      * Initialize with ClassGen object.
507      *
508      * @param cg The class generator.
509      */
510     public InstructionFactory(final ClassGen cg) {
511         this(cg, cg.getConstantPool());
512     }
513 
514     /**
515      * Constructs an InstructionFactory.
516      *
517      * @param cg The class generator.
518      * @param cp The constant pool generator.
519      */
520     public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) {
521         this.cg = cg;
522         this.cp = cp;
523     }
524 
525     /**
526      * Initialize just with ConstantPoolGen object.
527      *
528      * @param cp The constant pool generator.
529      */
530     public InstructionFactory(final ConstantPoolGen cp) {
531         this(null, cp);
532     }
533 
534     /**
535      * Creates an append instruction for the given type.
536      *
537      * @param type The type to append.
538      * @return The append instruction.
539      */
540     public Instruction createAppend(final Type type) {
541         final byte t = type.getType();
542         if (isString(type)) {
543             return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL);
544         }
545         switch (t) {
546         case Const.T_BOOLEAN:
547         case Const.T_CHAR:
548         case Const.T_FLOAT:
549         case Const.T_DOUBLE:
550         case Const.T_BYTE:
551         case Const.T_SHORT:
552         case Const.T_INT:
553         case Const.T_LONG:
554             return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL);
555         case Const.T_ARRAY:
556         case Const.T_OBJECT:
557             return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL);
558         default:
559             throw new IllegalArgumentException("No append for this type? " + type);
560         }
561     }
562 
563     /**
564      * Create conversion operation for two stack operands, this may be an I2C, instruction, for example, if the operands are basic
565      * types and CHECKCAST if they are reference types.
566      *
567      * @param srcType The source type.
568      * @param destType The destination type.
569      * @return The conversion instruction.
570      */
571     public Instruction createCast(final Type srcType, final Type destType) {
572         if (srcType instanceof BasicType && destType instanceof BasicType) {
573             final byte dest = destType.getType();
574             byte src = srcType.getType();
575             if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) {
576                 src = Const.T_INT;
577             }
578             final String name = "org.apache.bcel.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR];
579             Instruction i = null;
580             try {
581                 i = (Instruction) Class.forName(name).getConstructor().newInstance();
582             } catch (final Exception e) {
583                 throw new IllegalArgumentException("Could not find instruction: " + name, e);
584             }
585             return i;
586         }
587         if (!(srcType instanceof ReferenceType) || !(destType instanceof ReferenceType)) {
588             throw new IllegalArgumentException("Cannot cast " + srcType + " to " + destType);
589         }
590         if (destType instanceof ArrayType) {
591             return new CHECKCAST(cp.addArrayClass((ArrayType) destType));
592         }
593         return new CHECKCAST(cp.addClass(((ObjectType) destType).getClassName()));
594     }
595 
596     /**
597      * Creates a CHECKCAST instruction.
598      *
599      * @param t The reference type.
600      * @return The CHECKCAST instruction.
601      */
602     public CHECKCAST createCheckCast(final ReferenceType t) {
603         if (t instanceof ArrayType) {
604             return new CHECKCAST(cp.addArrayClass((ArrayType) t));
605         }
606         return new CHECKCAST(cp.addClass((ObjectType) t));
607     }
608 
609     /**
610      * Uses PUSH to push a constant value onto the stack.
611      *
612      * @param value must be of type Number, Boolean, Character or String.
613      * @return The instruction.
614      */
615     public Instruction createConstant(final Object value) {
616         final PUSH push;
617         if (value instanceof Number) {
618             push = new PUSH(cp, (Number) value);
619         } else if (value instanceof String) {
620             push = new PUSH(cp, (String) value);
621         } else if (value instanceof Boolean) {
622             push = new PUSH(cp, (Boolean) value);
623         } else if (value instanceof Character) {
624             push = new PUSH(cp, (Character) value);
625         } else {
626             throw new ClassGenException("Illegal type: " + value.getClass());
627         }
628         return push.getInstruction();
629     }
630 
631     /**
632      * Create a field instruction.
633      *
634      * @param className class name containing the field.
635      * @param name name of the referenced field.
636      * @param type type of field.
637      * @param kind how to access, that is, GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC.
638      * @return A field instruction.
639      * @see Const
640      */
641     public FieldInstruction createFieldAccess(final String className, final String name, final Type type, final short kind) {
642         final String signature = type.getSignature();
643         final int index = cp.addFieldref(className, name, signature);
644         switch (kind) {
645         case Const.GETFIELD:
646             return new GETFIELD(index);
647         case Const.PUTFIELD:
648             return new PUTFIELD(index);
649         case Const.GETSTATIC:
650             return new GETSTATIC(index);
651         case Const.PUTSTATIC:
652             return new PUTSTATIC(index);
653         default:
654             throw new IllegalArgumentException("Unknown getfield kind:" + kind);
655         }
656     }
657 
658     /**
659      * Creates a GETFIELD instruction.
660      *
661      * @param className The class name.
662      * @param name The field name.
663      * @param t The field type.
664      * @return The GETFIELD instruction.
665      */
666     public GETFIELD createGetField(final String className, final String name, final Type t) {
667         return new GETFIELD(cp.addFieldref(className, name, t.getSignature()));
668     }
669 
670     /**
671      * Creates a GETSTATIC instruction.
672      *
673      * @param className The class name.
674      * @param name The field name.
675      * @param t The field type.
676      * @return The GETSTATIC instruction.
677      */
678     public GETSTATIC createGetStatic(final String className, final String name, final Type t) {
679         return new GETSTATIC(cp.addFieldref(className, name, t.getSignature()));
680     }
681 
682     /**
683      * Creates an INSTANCEOF instruction.
684      *
685      * @param t The reference type.
686      * @return The INSTANCEOF instruction.
687      */
688     public INSTANCEOF createInstanceOf(final ReferenceType t) {
689         if (t instanceof ArrayType) {
690             return new INSTANCEOF(cp.addArrayClass((ArrayType) t));
691         }
692         return new INSTANCEOF(cp.addClass((ObjectType) t));
693     }
694 
695     private InvokeInstruction createInvoke(final MethodObject m, final short kind) {
696         return createInvoke(m.className, m.name, m.resultType, m.argTypes, kind);
697     }
698 
699     /**
700      * Create an invoke instruction. (Except for invokedynamic.)
701      *
702      * @param className name of the called class.
703      * @param name name of the called method.
704      * @param retType return type of method.
705      * @param argTypes argument types of method.
706      * @param kind how to invoke, that is, INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL.
707      * @return The invoke instruction.
708      * @see Const
709      */
710     public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind) {
711         return createInvoke(className, name, retType, argTypes, kind, kind == Const.INVOKEINTERFACE);
712     }
713 
714     /**
715      * Create an invoke instruction. (Except for invokedynamic.)
716      *
717      * @param className name of the called class.
718      * @param name name of the called method.
719      * @param retType return type of method.
720      * @param argTypes argument types of method.
721      * @param kind how to invoke: INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL.
722      * @param useInterface force use of InterfaceMethodref.
723      * @return A new InvokeInstruction.
724      * @since 6.5.0
725      */
726     public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind,
727         final boolean useInterface) {
728         if (kind != Const.INVOKESPECIAL && kind != Const.INVOKEVIRTUAL && kind != Const.INVOKESTATIC && kind != Const.INVOKEINTERFACE
729             && kind != Const.INVOKEDYNAMIC) {
730             throw new IllegalArgumentException("Unknown invoke kind: " + kind);
731         }
732         final int index;
733         int nargs = 0;
734         final String signature = Type.getMethodSignature(retType, argTypes);
735         if (argTypes != null) {
736             for (final Type argType : argTypes) {
737                 nargs += argType.getSize();
738             }
739         }
740         if (useInterface) {
741             index = cp.addInterfaceMethodref(className, name, signature);
742         } else {
743             index = cp.addMethodref(className, name, signature);
744         }
745         switch (kind) {
746         case Const.INVOKESPECIAL:
747             return new INVOKESPECIAL(index);
748         case Const.INVOKEVIRTUAL:
749             return new INVOKEVIRTUAL(index);
750         case Const.INVOKESTATIC:
751             return new INVOKESTATIC(index);
752         case Const.INVOKEINTERFACE:
753             return new INVOKEINTERFACE(index, nargs + 1);
754         case Const.INVOKEDYNAMIC:
755             return new INVOKEDYNAMIC(index);
756         default:
757             // Can't happen
758             throw new IllegalStateException("Unknown invoke kind: " + kind);
759         }
760     }
761 
762     /**
763      * Creates a NEW instruction.
764      *
765      * @param t The object type.
766      * @return The NEW instruction.
767      */
768     public NEW createNew(final ObjectType t) {
769         return new NEW(cp.addClass(t));
770     }
771 
772     /**
773      * Creates a NEW instruction.
774      *
775      * @param s The class name.
776      * @return The NEW instruction.
777      */
778     public NEW createNew(final String s) {
779         return createNew(ObjectType.getInstance(s));
780     }
781 
782     /**
783      * Create new array of given size and type.
784      *
785      * @param t The array element type.
786      * @param dim The array dimensions.
787      * @return An instruction that creates the corresponding array at runtime, for example is an AllocationInstruction.
788      */
789     public Instruction createNewArray(final Type t, final short dim) {
790         if (dim == 1) {
791             if (t instanceof ObjectType) {
792                 return new ANEWARRAY(cp.addClass((ObjectType) t));
793             }
794             if (t instanceof ArrayType) {
795                 return new ANEWARRAY(cp.addArrayClass((ArrayType) t));
796             }
797             return new NEWARRAY(t.getType());
798         }
799         final ArrayType at;
800         if (t instanceof ArrayType) {
801             at = (ArrayType) t;
802         } else {
803             at = new ArrayType(t, dim);
804         }
805         return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
806     }
807 
808     /**
809      * Create a call to the most popular System.out.println() method.
810      *
811      * @param s The string to print.
812      * @return The instruction list.
813      */
814     public InstructionList createPrintln(final String s) {
815         final InstructionList il = new InstructionList();
816         il.append(createGetStatic("java.lang.System", "out", Type.getType("Ljava/io/PrintStream;")));
817         il.append(new PUSH(cp, s));
818         final MethodObject methodObject = new MethodObject("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.getType("Ljava/lang/String;") });
819         il.append(createInvoke(methodObject, Const.INVOKEVIRTUAL));
820         return il;
821     }
822 
823     /**
824      * Creates a PUTFIELD instruction.
825      *
826      * @param className The class name.
827      * @param name The field name.
828      * @param t The field type.
829      * @return The PUTFIELD instruction.
830      */
831     public PUTFIELD createPutField(final String className, final String name, final Type t) {
832         return new PUTFIELD(cp.addFieldref(className, name, t.getSignature()));
833     }
834 
835     /**
836      * Creates a PUTSTATIC instruction.
837      *
838      * @param className The class name.
839      * @param name The field name.
840      * @param t The field type.
841      * @return The PUTSTATIC instruction.
842      */
843     public PUTSTATIC createPutStatic(final String className, final String name, final Type t) {
844         return new PUTSTATIC(cp.addFieldref(className, name, t.getSignature()));
845     }
846 
847     /**
848      * Gets the class generator.
849      *
850      * @return The class generator.
851      */
852     public ClassGen getClassGen() {
853         return cg;
854     }
855 
856     /**
857      * Gets the constant pool generator.
858      *
859      * @return The constant pool generator.
860      */
861     public ConstantPoolGen getConstantPool() {
862         return cp;
863     }
864 
865     /**
866      * Sets the class generator.
867      *
868      * @param c The class generator.
869      */
870     public void setClassGen(final ClassGen c) {
871         cg = c;
872     }
873 
874     /**
875      * Sets the constant pool generator.
876      *
877      * @param c The constant pool generator.
878      */
879     public void setConstantPool(final ConstantPoolGen c) {
880         cp = c;
881     }
882 }
883