1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * This file is available under and governed by the GNU General Public
27  * License version 2 only, as published by the Free Software Foundation.
28  * However, the following notice accompanied the original version of this
29  * file:
30  *
31  * ASM: a very small and fast Java bytecode manipulation framework
32  * Copyright (c) 2000-2011 INRIA, France Telecom
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  * 3. Neither the name of the copyright holders nor the names of its
44  *    contributors may be used to endorse or promote products derived from
45  *    this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57  * THE POSSIBILITY OF SUCH DAMAGE.
58  */
59 package jdk.internal.org.objectweb.asm.commons;
60 
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.List;
64 import jdk.internal.org.objectweb.asm.ClassVisitor;
65 import jdk.internal.org.objectweb.asm.ConstantDynamic;
66 import jdk.internal.org.objectweb.asm.Handle;
67 import jdk.internal.org.objectweb.asm.Label;
68 import jdk.internal.org.objectweb.asm.MethodVisitor;
69 import jdk.internal.org.objectweb.asm.Opcodes;
70 import jdk.internal.org.objectweb.asm.Type;
71 
72 /**
73  * A {@link MethodVisitor} with convenient methods to generate code. For example, using this
74  * adapter, the class below
75  *
76  * <pre>
77  * public class Example {
78  *   public static void main(String[] args) {
79  *     System.out.println(&quot;Hello world!&quot;);
80  *   }
81  * }
82  * </pre>
83  *
84  * <p>can be generated as follows:
85  *
86  * <pre>
87  * ClassWriter cw = new ClassWriter(0);
88  * cw.visit(V1_1, ACC_PUBLIC, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
89  *
90  * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
91  * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
92  * mg.loadThis();
93  * mg.invokeConstructor(Type.getType(Object.class), m);
94  * mg.returnValue();
95  * mg.endMethod();
96  *
97  * m = Method.getMethod(&quot;void main (String[])&quot;);
98  * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
99  * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));
100  * mg.push(&quot;Hello world!&quot;);
101  * mg.invokeVirtual(Type.getType(PrintStream.class),
102  *         Method.getMethod(&quot;void println (String)&quot;));
103  * mg.returnValue();
104  * mg.endMethod();
105  *
106  * cw.visitEnd();
107  * </pre>
108  *
109  * @author Juozas Baliuka
110  * @author Chris Nokleberg
111  * @author Eric Bruneton
112  * @author Prashant Deva
113  */
114 public class GeneratorAdapter extends LocalVariablesSorter {
115 
116     private static final String CLASS_DESCRIPTOR = "Ljava/lang/Class;";
117 
118     private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
119 
120     private static final Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
121 
122     private static final Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
123 
124     private static final Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
125 
126     private static final Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
127 
128     private static final Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
129 
130     private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
131 
132     private static final Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
133 
134     private static final Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
135 
136     private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
137 
138     private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
139 
140     private static final Method CHAR_VALUE = Method.getMethod("char charValue()");
141 
142     private static final Method INT_VALUE = Method.getMethod("int intValue()");
143 
144     private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()");
145 
146     private static final Method LONG_VALUE = Method.getMethod("long longValue()");
147 
148     private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
149 
150     /** Constant for the {@link #math} method. */
151     public static final int ADD = Opcodes.IADD;
152 
153     /** Constant for the {@link #math} method. */
154     public static final int SUB = Opcodes.ISUB;
155 
156     /** Constant for the {@link #math} method. */
157     public static final int MUL = Opcodes.IMUL;
158 
159     /** Constant for the {@link #math} method. */
160     public static final int DIV = Opcodes.IDIV;
161 
162     /** Constant for the {@link #math} method. */
163     public static final int REM = Opcodes.IREM;
164 
165     /** Constant for the {@link #math} method. */
166     public static final int NEG = Opcodes.INEG;
167 
168     /** Constant for the {@link #math} method. */
169     public static final int SHL = Opcodes.ISHL;
170 
171     /** Constant for the {@link #math} method. */
172     public static final int SHR = Opcodes.ISHR;
173 
174     /** Constant for the {@link #math} method. */
175     public static final int USHR = Opcodes.IUSHR;
176 
177     /** Constant for the {@link #math} method. */
178     public static final int AND = Opcodes.IAND;
179 
180     /** Constant for the {@link #math} method. */
181     public static final int OR = Opcodes.IOR;
182 
183     /** Constant for the {@link #math} method. */
184     public static final int XOR = Opcodes.IXOR;
185 
186     /** Constant for the {@link #ifCmp} method. */
187     public static final int EQ = Opcodes.IFEQ;
188 
189     /** Constant for the {@link #ifCmp} method. */
190     public static final int NE = Opcodes.IFNE;
191 
192     /** Constant for the {@link #ifCmp} method. */
193     public static final int LT = Opcodes.IFLT;
194 
195     /** Constant for the {@link #ifCmp} method. */
196     public static final int GE = Opcodes.IFGE;
197 
198     /** Constant for the {@link #ifCmp} method. */
199     public static final int GT = Opcodes.IFGT;
200 
201     /** Constant for the {@link #ifCmp} method. */
202     public static final int LE = Opcodes.IFLE;
203 
204     /** The access flags of the visited method. */
205     private final int access;
206 
207     /** The name of the visited method. */
208     private final String name;
209 
210     /** The return type of the visited method. */
211     private final Type returnType;
212 
213     /** The argument types of the visited method. */
214     private final Type[] argumentTypes;
215 
216     /** The types of the local variables of the visited method. */
217     private final List<Type> localTypes = new ArrayList<>();
218 
219     /**
220       * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
221       * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
222       * version.
223       *
224       * @param methodVisitor the method visitor to which this adapter delegates calls.
225       * @param access the method's access flags (see {@link Opcodes}).
226       * @param name the method's name.
227       * @param descriptor the method's descriptor (see {@link Type}).
228       * @throws IllegalStateException if a subclass calls this constructor.
229       */
GeneratorAdapter( final MethodVisitor methodVisitor, final int access, final String name, final String descriptor)230     public GeneratorAdapter(
231             final MethodVisitor methodVisitor,
232             final int access,
233             final String name,
234             final String descriptor) {
235         this(/* latest api = */ Opcodes.ASM8, methodVisitor, access, name, descriptor);
236         if (getClass() != GeneratorAdapter.class) {
237             throw new IllegalStateException();
238         }
239     }
240 
241     /**
242       * Constructs a new {@link GeneratorAdapter}.
243       *
244       * @param api the ASM API version implemented by this visitor. Must be one of {@link
245       *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
246       *     Opcodes#ASM8}.
247       * @param methodVisitor the method visitor to which this adapter delegates calls.
248       * @param access the method's access flags (see {@link Opcodes}).
249       * @param name the method's name.
250       * @param descriptor the method's descriptor (see {@link Type}).
251       */
GeneratorAdapter( final int api, final MethodVisitor methodVisitor, final int access, final String name, final String descriptor)252     protected GeneratorAdapter(
253             final int api,
254             final MethodVisitor methodVisitor,
255             final int access,
256             final String name,
257             final String descriptor) {
258         super(api, access, descriptor, methodVisitor);
259         this.access = access;
260         this.name = name;
261         this.returnType = Type.getReturnType(descriptor);
262         this.argumentTypes = Type.getArgumentTypes(descriptor);
263     }
264 
265     /**
266       * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
267       * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
268       * version.
269       *
270       * @param access access flags of the adapted method.
271       * @param method the adapted method.
272       * @param methodVisitor the method visitor to which this adapter delegates calls.
273       */
GeneratorAdapter( final int access, final Method method, final MethodVisitor methodVisitor)274     public GeneratorAdapter(
275             final int access, final Method method, final MethodVisitor methodVisitor) {
276         this(methodVisitor, access, method.getName(), method.getDescriptor());
277     }
278 
279     /**
280       * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
281       * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
282       * version.
283       *
284       * @param access access flags of the adapted method.
285       * @param method the adapted method.
286       * @param signature the signature of the adapted method (may be {@literal null}).
287       * @param exceptions the exceptions thrown by the adapted method (may be {@literal null}).
288       * @param classVisitor the class visitor to which this adapter delegates calls.
289       */
GeneratorAdapter( final int access, final Method method, final String signature, final Type[] exceptions, final ClassVisitor classVisitor)290     public GeneratorAdapter(
291             final int access,
292             final Method method,
293             final String signature,
294             final Type[] exceptions,
295             final ClassVisitor classVisitor) {
296         this(
297                 access,
298                 method,
299                 classVisitor.visitMethod(
300                         access,
301                         method.getName(),
302                         method.getDescriptor(),
303                         signature,
304                         exceptions == null ? null : getInternalNames(exceptions)));
305     }
306 
307     /**
308       * Returns the internal names of the given types.
309       *
310       * @param types a set of types.
311       * @return the internal names of the given types.
312       */
getInternalNames(final Type[] types)313     private static String[] getInternalNames(final Type[] types) {
314         String[] names = new String[types.length];
315         for (int i = 0; i < names.length; ++i) {
316             names[i] = types[i].getInternalName();
317         }
318         return names;
319     }
320 
getAccess()321     public int getAccess() {
322         return access;
323     }
324 
getName()325     public String getName() {
326         return name;
327     }
328 
getReturnType()329     public Type getReturnType() {
330         return returnType;
331     }
332 
getArgumentTypes()333     public Type[] getArgumentTypes() {
334         return argumentTypes.clone();
335     }
336 
337     // -----------------------------------------------------------------------------------------------
338     // Instructions to push constants on the stack
339     // -----------------------------------------------------------------------------------------------
340 
341     /**
342       * Generates the instruction to push the given value on the stack.
343       *
344       * @param value the value to be pushed on the stack.
345       */
push(final boolean value)346     public void push(final boolean value) {
347         push(value ? 1 : 0);
348     }
349 
350     /**
351       * Generates the instruction to push the given value on the stack.
352       *
353       * @param value the value to be pushed on the stack.
354       */
push(final int value)355     public void push(final int value) {
356         if (value >= -1 && value <= 5) {
357             mv.visitInsn(Opcodes.ICONST_0 + value);
358         } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
359             mv.visitIntInsn(Opcodes.BIPUSH, value);
360         } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
361             mv.visitIntInsn(Opcodes.SIPUSH, value);
362         } else {
363             mv.visitLdcInsn(value);
364         }
365     }
366 
367     /**
368       * Generates the instruction to push the given value on the stack.
369       *
370       * @param value the value to be pushed on the stack.
371       */
push(final long value)372     public void push(final long value) {
373         if (value == 0L || value == 1L) {
374             mv.visitInsn(Opcodes.LCONST_0 + (int) value);
375         } else {
376             mv.visitLdcInsn(value);
377         }
378     }
379 
380     /**
381       * Generates the instruction to push the given value on the stack.
382       *
383       * @param value the value to be pushed on the stack.
384       */
push(final float value)385     public void push(final float value) {
386         int bits = Float.floatToIntBits(value);
387         if (bits == 0L || bits == 0x3F800000 || bits == 0x40000000) { // 0..2
388             mv.visitInsn(Opcodes.FCONST_0 + (int) value);
389         } else {
390             mv.visitLdcInsn(value);
391         }
392     }
393 
394     /**
395       * Generates the instruction to push the given value on the stack.
396       *
397       * @param value the value to be pushed on the stack.
398       */
push(final double value)399     public void push(final double value) {
400         long bits = Double.doubleToLongBits(value);
401         if (bits == 0L || bits == 0x3FF0000000000000L) { // +0.0d and 1.0d
402             mv.visitInsn(Opcodes.DCONST_0 + (int) value);
403         } else {
404             mv.visitLdcInsn(value);
405         }
406     }
407 
408     /**
409       * Generates the instruction to push the given value on the stack.
410       *
411       * @param value the value to be pushed on the stack. May be {@literal null}.
412       */
push(final String value)413     public void push(final String value) {
414         if (value == null) {
415             mv.visitInsn(Opcodes.ACONST_NULL);
416         } else {
417             mv.visitLdcInsn(value);
418         }
419     }
420 
421     /**
422       * Generates the instruction to push the given value on the stack.
423       *
424       * @param value the value to be pushed on the stack.
425       */
push(final Type value)426     public void push(final Type value) {
427         if (value == null) {
428             mv.visitInsn(Opcodes.ACONST_NULL);
429         } else {
430             switch (value.getSort()) {
431                 case Type.BOOLEAN:
432                     mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", CLASS_DESCRIPTOR);
433                     break;
434                 case Type.CHAR:
435                     mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", CLASS_DESCRIPTOR);
436                     break;
437                 case Type.BYTE:
438                     mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", CLASS_DESCRIPTOR);
439                     break;
440                 case Type.SHORT:
441                     mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", CLASS_DESCRIPTOR);
442                     break;
443                 case Type.INT:
444                     mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", CLASS_DESCRIPTOR);
445                     break;
446                 case Type.FLOAT:
447                     mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", CLASS_DESCRIPTOR);
448                     break;
449                 case Type.LONG:
450                     mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", CLASS_DESCRIPTOR);
451                     break;
452                 case Type.DOUBLE:
453                     mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", CLASS_DESCRIPTOR);
454                     break;
455                 default:
456                     mv.visitLdcInsn(value);
457                     break;
458             }
459         }
460     }
461 
462     /**
463       * Generates the instruction to push a handle on the stack.
464       *
465       * @param handle the handle to be pushed on the stack.
466       */
push(final Handle handle)467     public void push(final Handle handle) {
468         if (handle == null) {
469             mv.visitInsn(Opcodes.ACONST_NULL);
470         } else {
471             mv.visitLdcInsn(handle);
472         }
473     }
474 
475     /**
476       * Generates the instruction to push a constant dynamic on the stack.
477       *
478       * @param constantDynamic the constant dynamic to be pushed on the stack.
479       */
push(final ConstantDynamic constantDynamic)480     public void push(final ConstantDynamic constantDynamic) {
481         if (constantDynamic == null) {
482             mv.visitInsn(Opcodes.ACONST_NULL);
483         } else {
484             mv.visitLdcInsn(constantDynamic);
485         }
486     }
487 
488     // -----------------------------------------------------------------------------------------------
489     // Instructions to load and store method arguments
490     // -----------------------------------------------------------------------------------------------
491 
492     /**
493       * Returns the index of the given method argument in the frame's local variables array.
494       *
495       * @param arg the index of a method argument.
496       * @return the index of the given method argument in the frame's local variables array.
497       */
getArgIndex(final int arg)498     private int getArgIndex(final int arg) {
499         int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
500         for (int i = 0; i < arg; i++) {
501             index += argumentTypes[i].getSize();
502         }
503         return index;
504     }
505 
506     /**
507       * Generates the instruction to push a local variable on the stack.
508       *
509       * @param type the type of the local variable to be loaded.
510       * @param index an index in the frame's local variables array.
511       */
loadInsn(final Type type, final int index)512     private void loadInsn(final Type type, final int index) {
513         mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
514     }
515 
516     /**
517       * Generates the instruction to store the top stack value in a local variable.
518       *
519       * @param type the type of the local variable to be stored.
520       * @param index an index in the frame's local variables array.
521       */
storeInsn(final Type type, final int index)522     private void storeInsn(final Type type, final int index) {
523         mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
524     }
525 
526     /** Generates the instruction to load 'this' on the stack. */
loadThis()527     public void loadThis() {
528         if ((access & Opcodes.ACC_STATIC) != 0) {
529             throw new IllegalStateException("no 'this' pointer within static method");
530         }
531         mv.visitVarInsn(Opcodes.ALOAD, 0);
532     }
533 
534     /**
535       * Generates the instruction to load the given method argument on the stack.
536       *
537       * @param arg the index of a method argument.
538       */
loadArg(final int arg)539     public void loadArg(final int arg) {
540         loadInsn(argumentTypes[arg], getArgIndex(arg));
541     }
542 
543     /**
544       * Generates the instructions to load the given method arguments on the stack.
545       *
546       * @param arg the index of the first method argument to be loaded.
547       * @param count the number of method arguments to be loaded.
548       */
loadArgs(final int arg, final int count)549     public void loadArgs(final int arg, final int count) {
550         int index = getArgIndex(arg);
551         for (int i = 0; i < count; ++i) {
552             Type argumentType = argumentTypes[arg + i];
553             loadInsn(argumentType, index);
554             index += argumentType.getSize();
555         }
556     }
557 
558     /** Generates the instructions to load all the method arguments on the stack. */
loadArgs()559     public void loadArgs() {
560         loadArgs(0, argumentTypes.length);
561     }
562 
563     /**
564       * Generates the instructions to load all the method arguments on the stack, as a single object
565       * array.
566       */
loadArgArray()567     public void loadArgArray() {
568         push(argumentTypes.length);
569         newArray(OBJECT_TYPE);
570         for (int i = 0; i < argumentTypes.length; i++) {
571             dup();
572             push(i);
573             loadArg(i);
574             box(argumentTypes[i]);
575             arrayStore(OBJECT_TYPE);
576         }
577     }
578 
579     /**
580       * Generates the instruction to store the top stack value in the given method argument.
581       *
582       * @param arg the index of a method argument.
583       */
storeArg(final int arg)584     public void storeArg(final int arg) {
585         storeInsn(argumentTypes[arg], getArgIndex(arg));
586     }
587 
588     // -----------------------------------------------------------------------------------------------
589     // Instructions to load and store local variables
590     // -----------------------------------------------------------------------------------------------
591 
592     /**
593       * Returns the type of the given local variable.
594       *
595       * @param local a local variable identifier, as returned by {@link
596       *     LocalVariablesSorter#newLocal(Type)}.
597       * @return the type of the given local variable.
598       */
getLocalType(final int local)599     public Type getLocalType(final int local) {
600         return localTypes.get(local - firstLocal);
601     }
602 
603     @Override
setLocalType(final int local, final Type type)604     protected void setLocalType(final int local, final Type type) {
605         int index = local - firstLocal;
606         while (localTypes.size() < index + 1) {
607             localTypes.add(null);
608         }
609         localTypes.set(index, type);
610     }
611 
612     /**
613       * Generates the instruction to load the given local variable on the stack.
614       *
615       * @param local a local variable identifier, as returned by {@link
616       *     LocalVariablesSorter#newLocal(Type)}.
617       */
loadLocal(final int local)618     public void loadLocal(final int local) {
619         loadInsn(getLocalType(local), local);
620     }
621 
622     /**
623       * Generates the instruction to load the given local variable on the stack.
624       *
625       * @param local a local variable identifier, as returned by {@link
626       *     LocalVariablesSorter#newLocal(Type)}.
627       * @param type the type of this local variable.
628       */
loadLocal(final int local, final Type type)629     public void loadLocal(final int local, final Type type) {
630         setLocalType(local, type);
631         loadInsn(type, local);
632     }
633 
634     /**
635       * Generates the instruction to store the top stack value in the given local variable.
636       *
637       * @param local a local variable identifier, as returned by {@link
638       *     LocalVariablesSorter#newLocal(Type)}.
639       */
storeLocal(final int local)640     public void storeLocal(final int local) {
641         storeInsn(getLocalType(local), local);
642     }
643 
644     /**
645       * Generates the instruction to store the top stack value in the given local variable.
646       *
647       * @param local a local variable identifier, as returned by {@link
648       *     LocalVariablesSorter#newLocal(Type)}.
649       * @param type the type of this local variable.
650       */
storeLocal(final int local, final Type type)651     public void storeLocal(final int local, final Type type) {
652         setLocalType(local, type);
653         storeInsn(type, local);
654     }
655 
656     /**
657       * Generates the instruction to load an element from an array.
658       *
659       * @param type the type of the array element to be loaded.
660       */
arrayLoad(final Type type)661     public void arrayLoad(final Type type) {
662         mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
663     }
664 
665     /**
666       * Generates the instruction to store an element in an array.
667       *
668       * @param type the type of the array element to be stored.
669       */
arrayStore(final Type type)670     public void arrayStore(final Type type) {
671         mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
672     }
673 
674     // -----------------------------------------------------------------------------------------------
675     // Instructions to manage the stack
676     // -----------------------------------------------------------------------------------------------
677 
678     /** Generates a POP instruction. */
pop()679     public void pop() {
680         mv.visitInsn(Opcodes.POP);
681     }
682 
683     /** Generates a POP2 instruction. */
pop2()684     public void pop2() {
685         mv.visitInsn(Opcodes.POP2);
686     }
687 
688     /** Generates a DUP instruction. */
dup()689     public void dup() {
690         mv.visitInsn(Opcodes.DUP);
691     }
692 
693     /** Generates a DUP2 instruction. */
dup2()694     public void dup2() {
695         mv.visitInsn(Opcodes.DUP2);
696     }
697 
698     /** Generates a DUP_X1 instruction. */
dupX1()699     public void dupX1() {
700         mv.visitInsn(Opcodes.DUP_X1);
701     }
702 
703     /** Generates a DUP_X2 instruction. */
dupX2()704     public void dupX2() {
705         mv.visitInsn(Opcodes.DUP_X2);
706     }
707 
708     /** Generates a DUP2_X1 instruction. */
dup2X1()709     public void dup2X1() {
710         mv.visitInsn(Opcodes.DUP2_X1);
711     }
712 
713     /** Generates a DUP2_X2 instruction. */
dup2X2()714     public void dup2X2() {
715         mv.visitInsn(Opcodes.DUP2_X2);
716     }
717 
718     /** Generates a SWAP instruction. */
swap()719     public void swap() {
720         mv.visitInsn(Opcodes.SWAP);
721     }
722 
723     /**
724       * Generates the instructions to swap the top two stack values.
725       *
726       * @param prev type of the top - 1 stack value.
727       * @param type type of the top stack value.
728       */
swap(final Type prev, final Type type)729     public void swap(final Type prev, final Type type) {
730         if (type.getSize() == 1) {
731             if (prev.getSize() == 1) {
732                 swap(); // Same as dupX1 pop.
733             } else {
734                 dupX2();
735                 pop();
736             }
737         } else {
738             if (prev.getSize() == 1) {
739                 dup2X1();
740                 pop2();
741             } else {
742                 dup2X2();
743                 pop2();
744             }
745         }
746     }
747 
748     // -----------------------------------------------------------------------------------------------
749     // Instructions to do mathematical and logical operations
750     // -----------------------------------------------------------------------------------------------
751 
752     /**
753       * Generates the instruction to do the specified mathematical or logical operation.
754       *
755       * @param op a mathematical or logical operation. Must be one of ADD, SUB, MUL, DIV, REM, NEG,
756       *     SHL, SHR, USHR, AND, OR, XOR.
757       * @param type the type of the operand(s) for this operation.
758       */
math(final int op, final Type type)759     public void math(final int op, final Type type) {
760         mv.visitInsn(type.getOpcode(op));
761     }
762 
763     /** Generates the instructions to compute the bitwise negation of the top stack value. */
not()764     public void not() {
765         mv.visitInsn(Opcodes.ICONST_1);
766         mv.visitInsn(Opcodes.IXOR);
767     }
768 
769     /**
770       * Generates the instruction to increment the given local variable.
771       *
772       * @param local the local variable to be incremented.
773       * @param amount the amount by which the local variable must be incremented.
774       */
iinc(final int local, final int amount)775     public void iinc(final int local, final int amount) {
776         mv.visitIincInsn(local, amount);
777     }
778 
779     /**
780       * Generates the instructions to cast a numerical value from one type to another.
781       *
782       * @param from the type of the top stack value
783       * @param to the type into which this value must be cast.
784       */
cast(final Type from, final Type to)785     public void cast(final Type from, final Type to) {
786         if (from != to) {
787             if (from.getSort() < Type.BOOLEAN
788                     || from.getSort() > Type.DOUBLE
789                     || to.getSort() < Type.BOOLEAN
790                     || to.getSort() > Type.DOUBLE) {
791                 throw new IllegalArgumentException("Cannot cast from " + from + " to " + to);
792             }
793             InstructionAdapter.cast(mv, from, to);
794         }
795     }
796 
797     // -----------------------------------------------------------------------------------------------
798     // Instructions to do boxing and unboxing operations
799     // -----------------------------------------------------------------------------------------------
800 
getBoxedType(final Type type)801     private static Type getBoxedType(final Type type) {
802         switch (type.getSort()) {
803             case Type.BYTE:
804                 return BYTE_TYPE;
805             case Type.BOOLEAN:
806                 return BOOLEAN_TYPE;
807             case Type.SHORT:
808                 return SHORT_TYPE;
809             case Type.CHAR:
810                 return CHARACTER_TYPE;
811             case Type.INT:
812                 return INTEGER_TYPE;
813             case Type.FLOAT:
814                 return FLOAT_TYPE;
815             case Type.LONG:
816                 return LONG_TYPE;
817             case Type.DOUBLE:
818                 return DOUBLE_TYPE;
819             default:
820                 return type;
821         }
822     }
823 
824     /**
825       * Generates the instructions to box the top stack value. This value is replaced by its boxed
826       * equivalent on top of the stack.
827       *
828       * @param type the type of the top stack value.
829       */
box(final Type type)830     public void box(final Type type) {
831         if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
832             return;
833         }
834         if (type == Type.VOID_TYPE) {
835             push((String) null);
836         } else {
837             Type boxedType = getBoxedType(type);
838             newInstance(boxedType);
839             if (type.getSize() == 2) {
840                 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
841                 dupX2();
842                 dupX2();
843                 pop();
844             } else {
845                 // p -> po -> opo -> oop -> o
846                 dupX1();
847                 swap();
848             }
849             invokeConstructor(boxedType, new Method("<init>", Type.VOID_TYPE, new Type[] {type}));
850         }
851     }
852 
853     /**
854       * Generates the instructions to box the top stack value using Java 5's valueOf() method. This
855       * value is replaced by its boxed equivalent on top of the stack.
856       *
857       * @param type the type of the top stack value.
858       */
valueOf(final Type type)859     public void valueOf(final Type type) {
860         if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
861             return;
862         }
863         if (type == Type.VOID_TYPE) {
864             push((String) null);
865         } else {
866             Type boxedType = getBoxedType(type);
867             invokeStatic(boxedType, new Method("valueOf", boxedType, new Type[] {type}));
868         }
869     }
870 
871     /**
872       * Generates the instructions to unbox the top stack value. This value is replaced by its unboxed
873       * equivalent on top of the stack.
874       *
875       * @param type the type of the top stack value.
876       */
unbox(final Type type)877     public void unbox(final Type type) {
878         Type boxedType = NUMBER_TYPE;
879         Method unboxMethod;
880         switch (type.getSort()) {
881             case Type.VOID:
882                 return;
883             case Type.CHAR:
884                 boxedType = CHARACTER_TYPE;
885                 unboxMethod = CHAR_VALUE;
886                 break;
887             case Type.BOOLEAN:
888                 boxedType = BOOLEAN_TYPE;
889                 unboxMethod = BOOLEAN_VALUE;
890                 break;
891             case Type.DOUBLE:
892                 unboxMethod = DOUBLE_VALUE;
893                 break;
894             case Type.FLOAT:
895                 unboxMethod = FLOAT_VALUE;
896                 break;
897             case Type.LONG:
898                 unboxMethod = LONG_VALUE;
899                 break;
900             case Type.INT:
901             case Type.SHORT:
902             case Type.BYTE:
903                 unboxMethod = INT_VALUE;
904                 break;
905             default:
906                 unboxMethod = null;
907                 break;
908         }
909         if (unboxMethod == null) {
910             checkCast(type);
911         } else {
912             checkCast(boxedType);
913             invokeVirtual(boxedType, unboxMethod);
914         }
915     }
916 
917     // -----------------------------------------------------------------------------------------------
918     // Instructions to jump to other instructions
919     // -----------------------------------------------------------------------------------------------
920 
921     /**
922       * Constructs a new {@link Label}.
923       *
924       * @return a new {@link Label}.
925       */
newLabel()926     public Label newLabel() {
927         return new Label();
928     }
929 
930     /**
931       * Marks the current code position with the given label.
932       *
933       * @param label a label.
934       */
mark(final Label label)935     public void mark(final Label label) {
936         mv.visitLabel(label);
937     }
938 
939     /**
940       * Marks the current code position with a new label.
941       *
942       * @return the label that was created to mark the current code position.
943       */
mark()944     public Label mark() {
945         Label label = new Label();
946         mv.visitLabel(label);
947         return label;
948     }
949 
950     /**
951       * Generates the instructions to jump to a label based on the comparison of the top two stack
952       * values.
953       *
954       * @param type the type of the top two stack values.
955       * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
956       * @param label where to jump if the comparison result is {@literal true}.
957       */
ifCmp(final Type type, final int mode, final Label label)958     public void ifCmp(final Type type, final int mode, final Label label) {
959         switch (type.getSort()) {
960             case Type.LONG:
961                 mv.visitInsn(Opcodes.LCMP);
962                 break;
963             case Type.DOUBLE:
964                 mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPL : Opcodes.DCMPG);
965                 break;
966             case Type.FLOAT:
967                 mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPL : Opcodes.FCMPG);
968                 break;
969             case Type.ARRAY:
970             case Type.OBJECT:
971                 if (mode == EQ) {
972                     mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
973                     return;
974                 } else if (mode == NE) {
975                     mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
976                     return;
977                 } else {
978                     throw new IllegalArgumentException("Bad comparison for type " + type);
979                 }
980             default:
981                 int intOp = -1;
982                 switch (mode) {
983                     case EQ:
984                         intOp = Opcodes.IF_ICMPEQ;
985                         break;
986                     case NE:
987                         intOp = Opcodes.IF_ICMPNE;
988                         break;
989                     case GE:
990                         intOp = Opcodes.IF_ICMPGE;
991                         break;
992                     case LT:
993                         intOp = Opcodes.IF_ICMPLT;
994                         break;
995                     case LE:
996                         intOp = Opcodes.IF_ICMPLE;
997                         break;
998                     case GT:
999                         intOp = Opcodes.IF_ICMPGT;
1000                         break;
1001                     default:
1002                         throw new IllegalArgumentException("Bad comparison mode " + mode);
1003                 }
1004                 mv.visitJumpInsn(intOp, label);
1005                 return;
1006         }
1007         mv.visitJumpInsn(mode, label);
1008     }
1009 
1010     /**
1011       * Generates the instructions to jump to a label based on the comparison of the top two integer
1012       * stack values.
1013       *
1014       * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
1015       * @param label where to jump if the comparison result is {@literal true}.
1016       */
ifICmp(final int mode, final Label label)1017     public void ifICmp(final int mode, final Label label) {
1018         ifCmp(Type.INT_TYPE, mode, label);
1019     }
1020 
1021     /**
1022       * Generates the instructions to jump to a label based on the comparison of the top integer stack
1023       * value with zero.
1024       *
1025       * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
1026       * @param label where to jump if the comparison result is {@literal true}.
1027       */
ifZCmp(final int mode, final Label label)1028     public void ifZCmp(final int mode, final Label label) {
1029         mv.visitJumpInsn(mode, label);
1030     }
1031 
1032     /**
1033       * Generates the instruction to jump to the given label if the top stack value is null.
1034       *
1035       * @param label where to jump if the condition is {@literal true}.
1036       */
ifNull(final Label label)1037     public void ifNull(final Label label) {
1038         mv.visitJumpInsn(Opcodes.IFNULL, label);
1039     }
1040 
1041     /**
1042       * Generates the instruction to jump to the given label if the top stack value is not null.
1043       *
1044       * @param label where to jump if the condition is {@literal true}.
1045       */
ifNonNull(final Label label)1046     public void ifNonNull(final Label label) {
1047         mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1048     }
1049 
1050     /**
1051       * Generates the instruction to jump to the given label.
1052       *
1053       * @param label where to jump if the condition is {@literal true}.
1054       */
goTo(final Label label)1055     public void goTo(final Label label) {
1056         mv.visitJumpInsn(Opcodes.GOTO, label);
1057     }
1058 
1059     /**
1060       * Generates a RET instruction.
1061       *
1062       * @param local a local variable identifier, as returned by {@link
1063       *     LocalVariablesSorter#newLocal(Type)}.
1064       */
ret(final int local)1065     public void ret(final int local) {
1066         mv.visitVarInsn(Opcodes.RET, local);
1067     }
1068 
1069     /**
1070       * Generates the instructions for a switch statement.
1071       *
1072       * @param keys the switch case keys.
1073       * @param generator a generator to generate the code for the switch cases.
1074       */
tableSwitch(final int[] keys, final TableSwitchGenerator generator)1075     public void tableSwitch(final int[] keys, final TableSwitchGenerator generator) {
1076         float density;
1077         if (keys.length == 0) {
1078             density = 0;
1079         } else {
1080             density = (float) keys.length / (keys[keys.length - 1] - keys[0] + 1);
1081         }
1082         tableSwitch(keys, generator, density >= 0.5f);
1083     }
1084 
1085     /**
1086       * Generates the instructions for a switch statement.
1087       *
1088       * @param keys the switch case keys.
1089       * @param generator a generator to generate the code for the switch cases.
1090       * @param useTable {@literal true} to use a TABLESWITCH instruction, or {@literal false} to use a
1091       *     LOOKUPSWITCH instruction.
1092       */
tableSwitch( final int[] keys, final TableSwitchGenerator generator, final boolean useTable)1093     public void tableSwitch(
1094             final int[] keys, final TableSwitchGenerator generator, final boolean useTable) {
1095         for (int i = 1; i < keys.length; ++i) {
1096             if (keys[i] < keys[i - 1]) {
1097                 throw new IllegalArgumentException("keys must be sorted in ascending order");
1098             }
1099         }
1100         Label defaultLabel = newLabel();
1101         Label endLabel = newLabel();
1102         if (keys.length > 0) {
1103             int numKeys = keys.length;
1104             if (useTable) {
1105                 int min = keys[0];
1106                 int max = keys[numKeys - 1];
1107                 int range = max - min + 1;
1108                 Label[] labels = new Label[range];
1109                 Arrays.fill(labels, defaultLabel);
1110                 for (int i = 0; i < numKeys; ++i) {
1111                     labels[keys[i] - min] = newLabel();
1112                 }
1113                 mv.visitTableSwitchInsn(min, max, defaultLabel, labels);
1114                 for (int i = 0; i < range; ++i) {
1115                     Label label = labels[i];
1116                     if (label != defaultLabel) {
1117                         mark(label);
1118                         generator.generateCase(i + min, endLabel);
1119                     }
1120                 }
1121             } else {
1122                 Label[] labels = new Label[numKeys];
1123                 for (int i = 0; i < numKeys; ++i) {
1124                     labels[i] = newLabel();
1125                 }
1126                 mv.visitLookupSwitchInsn(defaultLabel, keys, labels);
1127                 for (int i = 0; i < numKeys; ++i) {
1128                     mark(labels[i]);
1129                     generator.generateCase(keys[i], endLabel);
1130                 }
1131             }
1132         }
1133         mark(defaultLabel);
1134         generator.generateDefault();
1135         mark(endLabel);
1136     }
1137 
1138     /** Generates the instruction to return the top stack value to the caller. */
returnValue()1139     public void returnValue() {
1140         mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
1141     }
1142 
1143     // -----------------------------------------------------------------------------------------------
1144     // Instructions to load and store fields
1145     // -----------------------------------------------------------------------------------------------
1146 
1147     /**
1148       * Generates a get field or set field instruction.
1149       *
1150       * @param opcode the instruction's opcode.
1151       * @param ownerType the class in which the field is defined.
1152       * @param name the name of the field.
1153       * @param fieldType the type of the field.
1154       */
fieldInsn( final int opcode, final Type ownerType, final String name, final Type fieldType)1155     private void fieldInsn(
1156             final int opcode, final Type ownerType, final String name, final Type fieldType) {
1157         mv.visitFieldInsn(opcode, ownerType.getInternalName(), name, fieldType.getDescriptor());
1158     }
1159 
1160     /**
1161       * Generates the instruction to push the value of a static field on the stack.
1162       *
1163       * @param owner the class in which the field is defined.
1164       * @param name the name of the field.
1165       * @param type the type of the field.
1166       */
getStatic(final Type owner, final String name, final Type type)1167     public void getStatic(final Type owner, final String name, final Type type) {
1168         fieldInsn(Opcodes.GETSTATIC, owner, name, type);
1169     }
1170 
1171     /**
1172       * Generates the instruction to store the top stack value in a static field.
1173       *
1174       * @param owner the class in which the field is defined.
1175       * @param name the name of the field.
1176       * @param type the type of the field.
1177       */
putStatic(final Type owner, final String name, final Type type)1178     public void putStatic(final Type owner, final String name, final Type type) {
1179         fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
1180     }
1181 
1182     /**
1183       * Generates the instruction to push the value of a non static field on the stack.
1184       *
1185       * @param owner the class in which the field is defined.
1186       * @param name the name of the field.
1187       * @param type the type of the field.
1188       */
getField(final Type owner, final String name, final Type type)1189     public void getField(final Type owner, final String name, final Type type) {
1190         fieldInsn(Opcodes.GETFIELD, owner, name, type);
1191     }
1192 
1193     /**
1194       * Generates the instruction to store the top stack value in a non static field.
1195       *
1196       * @param owner the class in which the field is defined.
1197       * @param name the name of the field.
1198       * @param type the type of the field.
1199       */
putField(final Type owner, final String name, final Type type)1200     public void putField(final Type owner, final String name, final Type type) {
1201         fieldInsn(Opcodes.PUTFIELD, owner, name, type);
1202     }
1203 
1204     // -----------------------------------------------------------------------------------------------
1205     // Instructions to invoke methods
1206     // -----------------------------------------------------------------------------------------------
1207 
1208     /**
1209       * Generates an invoke method instruction.
1210       *
1211       * @param opcode the instruction's opcode.
1212       * @param type the class in which the method is defined.
1213       * @param method the method to be invoked.
1214       * @param isInterface whether the 'type' class is an interface or not.
1215       */
invokeInsn( final int opcode, final Type type, final Method method, final boolean isInterface)1216     private void invokeInsn(
1217             final int opcode, final Type type, final Method method, final boolean isInterface) {
1218         String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() : type.getInternalName();
1219         mv.visitMethodInsn(opcode, owner, method.getName(), method.getDescriptor(), isInterface);
1220     }
1221 
1222     /**
1223       * Generates the instruction to invoke a normal method.
1224       *
1225       * @param owner the class in which the method is defined.
1226       * @param method the method to be invoked.
1227       */
invokeVirtual(final Type owner, final Method method)1228     public void invokeVirtual(final Type owner, final Method method) {
1229         invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false);
1230     }
1231 
1232     /**
1233       * Generates the instruction to invoke a constructor.
1234       *
1235       * @param type the class in which the constructor is defined.
1236       * @param method the constructor to be invoked.
1237       */
invokeConstructor(final Type type, final Method method)1238     public void invokeConstructor(final Type type, final Method method) {
1239         invokeInsn(Opcodes.INVOKESPECIAL, type, method, false);
1240     }
1241 
1242     /**
1243       * Generates the instruction to invoke a static method.
1244       *
1245       * @param owner the class in which the method is defined.
1246       * @param method the method to be invoked.
1247       */
invokeStatic(final Type owner, final Method method)1248     public void invokeStatic(final Type owner, final Method method) {
1249         invokeInsn(Opcodes.INVOKESTATIC, owner, method, false);
1250     }
1251 
1252     /**
1253       * Generates the instruction to invoke an interface method.
1254       *
1255       * @param owner the class in which the method is defined.
1256       * @param method the method to be invoked.
1257       */
invokeInterface(final Type owner, final Method method)1258     public void invokeInterface(final Type owner, final Method method) {
1259         invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true);
1260     }
1261 
1262     /**
1263       * Generates an invokedynamic instruction.
1264       *
1265       * @param name the method's name.
1266       * @param descriptor the method's descriptor (see {@link Type}).
1267       * @param bootstrapMethodHandle the bootstrap method.
1268       * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
1269       *     an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
1270       *     Type} or {@link Handle} value. This method is allowed to modify the content of the array so
1271       *     a caller should expect that this array may change.
1272       */
invokeDynamic( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)1273     public void invokeDynamic(
1274             final String name,
1275             final String descriptor,
1276             final Handle bootstrapMethodHandle,
1277             final Object... bootstrapMethodArguments) {
1278         mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
1279     }
1280 
1281     // -----------------------------------------------------------------------------------------------
1282     // Instructions to create objects and arrays
1283     // -----------------------------------------------------------------------------------------------
1284 
1285     /**
1286       * Generates a type dependent instruction.
1287       *
1288       * @param opcode the instruction's opcode.
1289       * @param type the instruction's operand.
1290       */
typeInsn(final int opcode, final Type type)1291     private void typeInsn(final int opcode, final Type type) {
1292         mv.visitTypeInsn(opcode, type.getInternalName());
1293     }
1294 
1295     /**
1296       * Generates the instruction to create a new object.
1297       *
1298       * @param type the class of the object to be created.
1299       */
newInstance(final Type type)1300     public void newInstance(final Type type) {
1301         typeInsn(Opcodes.NEW, type);
1302     }
1303 
1304     /**
1305       * Generates the instruction to create a new array.
1306       *
1307       * @param type the type of the array elements.
1308       */
newArray(final Type type)1309     public void newArray(final Type type) {
1310         InstructionAdapter.newarray(mv, type);
1311     }
1312 
1313     // -----------------------------------------------------------------------------------------------
1314     // Miscellaneous instructions
1315     // -----------------------------------------------------------------------------------------------
1316 
1317     /** Generates the instruction to compute the length of an array. */
arrayLength()1318     public void arrayLength() {
1319         mv.visitInsn(Opcodes.ARRAYLENGTH);
1320     }
1321 
1322     /** Generates the instruction to throw an exception. */
throwException()1323     public void throwException() {
1324         mv.visitInsn(Opcodes.ATHROW);
1325     }
1326 
1327     /**
1328       * Generates the instructions to create and throw an exception. The exception class must have a
1329       * constructor with a single String argument.
1330       *
1331       * @param type the class of the exception to be thrown.
1332       * @param message the detailed message of the exception.
1333       */
throwException(final Type type, final String message)1334     public void throwException(final Type type, final String message) {
1335         newInstance(type);
1336         dup();
1337         push(message);
1338         invokeConstructor(type, Method.getMethod("void <init> (String)"));
1339         throwException();
1340     }
1341 
1342     /**
1343       * Generates the instruction to check that the top stack value is of the given type.
1344       *
1345       * @param type a class or interface type.
1346       */
checkCast(final Type type)1347     public void checkCast(final Type type) {
1348         if (!type.equals(OBJECT_TYPE)) {
1349             typeInsn(Opcodes.CHECKCAST, type);
1350         }
1351     }
1352 
1353     /**
1354       * Generates the instruction to test if the top stack value is of the given type.
1355       *
1356       * @param type a class or interface type.
1357       */
instanceOf(final Type type)1358     public void instanceOf(final Type type) {
1359         typeInsn(Opcodes.INSTANCEOF, type);
1360     }
1361 
1362     /** Generates the instruction to get the monitor of the top stack value. */
monitorEnter()1363     public void monitorEnter() {
1364         mv.visitInsn(Opcodes.MONITORENTER);
1365     }
1366 
1367     /** Generates the instruction to release the monitor of the top stack value. */
monitorExit()1368     public void monitorExit() {
1369         mv.visitInsn(Opcodes.MONITOREXIT);
1370     }
1371 
1372     // -----------------------------------------------------------------------------------------------
1373     // Non instructions
1374     // -----------------------------------------------------------------------------------------------
1375 
1376     /** Marks the end of the visited method. */
endMethod()1377     public void endMethod() {
1378         if ((access & Opcodes.ACC_ABSTRACT) == 0) {
1379             mv.visitMaxs(0, 0);
1380         }
1381         mv.visitEnd();
1382     }
1383 
1384     /**
1385       * Marks the start of an exception handler.
1386       *
1387       * @param start beginning of the exception handler's scope (inclusive).
1388       * @param end end of the exception handler's scope (exclusive).
1389       * @param exception internal name of the type of exceptions handled by the handler.
1390       */
catchException(final Label start, final Label end, final Type exception)1391     public void catchException(final Label start, final Label end, final Type exception) {
1392         Label catchLabel = new Label();
1393         if (exception == null) {
1394             mv.visitTryCatchBlock(start, end, catchLabel, null);
1395         } else {
1396             mv.visitTryCatchBlock(start, end, catchLabel, exception.getInternalName());
1397         }
1398         mark(catchLabel);
1399     }
1400 }
1401