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 
65 import jdk.internal.org.objectweb.asm.ClassVisitor;
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 jdk.internal.org.objectweb.asm.MethodVisitor} with convenient methods to generate
74  * code. For example, using this 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  * can be generated as follows:
85  *
86  * <pre>
87  * ClassWriter cw = new ClassWriter(true);
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 CLDESC = "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
121             .getObjectType("java/lang/Boolean");
122 
123     private static final Type SHORT_TYPE = Type
124             .getObjectType("java/lang/Short");
125 
126     private static final Type CHARACTER_TYPE = Type
127             .getObjectType("java/lang/Character");
128 
129     private static final Type INTEGER_TYPE = Type
130             .getObjectType("java/lang/Integer");
131 
132     private static final Type FLOAT_TYPE = Type
133             .getObjectType("java/lang/Float");
134 
135     private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
136 
137     private static final Type DOUBLE_TYPE = Type
138             .getObjectType("java/lang/Double");
139 
140     private static final Type NUMBER_TYPE = Type
141             .getObjectType("java/lang/Number");
142 
143     private static final Type OBJECT_TYPE = Type
144             .getObjectType("java/lang/Object");
145 
146     private static final Method BOOLEAN_VALUE = Method
147             .getMethod("boolean booleanValue()");
148 
149     private static final Method CHAR_VALUE = Method
150             .getMethod("char charValue()");
151 
152     private static final Method INT_VALUE = Method.getMethod("int intValue()");
153 
154     private static final Method FLOAT_VALUE = Method
155             .getMethod("float floatValue()");
156 
157     private static final Method LONG_VALUE = Method
158             .getMethod("long longValue()");
159 
160     private static final Method DOUBLE_VALUE = Method
161             .getMethod("double doubleValue()");
162 
163     /**
164      * Constant for the {@link #math math} method.
165      */
166     public static final int ADD = Opcodes.IADD;
167 
168     /**
169      * Constant for the {@link #math math} method.
170      */
171     public static final int SUB = Opcodes.ISUB;
172 
173     /**
174      * Constant for the {@link #math math} method.
175      */
176     public static final int MUL = Opcodes.IMUL;
177 
178     /**
179      * Constant for the {@link #math math} method.
180      */
181     public static final int DIV = Opcodes.IDIV;
182 
183     /**
184      * Constant for the {@link #math math} method.
185      */
186     public static final int REM = Opcodes.IREM;
187 
188     /**
189      * Constant for the {@link #math math} method.
190      */
191     public static final int NEG = Opcodes.INEG;
192 
193     /**
194      * Constant for the {@link #math math} method.
195      */
196     public static final int SHL = Opcodes.ISHL;
197 
198     /**
199      * Constant for the {@link #math math} method.
200      */
201     public static final int SHR = Opcodes.ISHR;
202 
203     /**
204      * Constant for the {@link #math math} method.
205      */
206     public static final int USHR = Opcodes.IUSHR;
207 
208     /**
209      * Constant for the {@link #math math} method.
210      */
211     public static final int AND = Opcodes.IAND;
212 
213     /**
214      * Constant for the {@link #math math} method.
215      */
216     public static final int OR = Opcodes.IOR;
217 
218     /**
219      * Constant for the {@link #math math} method.
220      */
221     public static final int XOR = Opcodes.IXOR;
222 
223     /**
224      * Constant for the {@link #ifCmp ifCmp} method.
225      */
226     public static final int EQ = Opcodes.IFEQ;
227 
228     /**
229      * Constant for the {@link #ifCmp ifCmp} method.
230      */
231     public static final int NE = Opcodes.IFNE;
232 
233     /**
234      * Constant for the {@link #ifCmp ifCmp} method.
235      */
236     public static final int LT = Opcodes.IFLT;
237 
238     /**
239      * Constant for the {@link #ifCmp ifCmp} method.
240      */
241     public static final int GE = Opcodes.IFGE;
242 
243     /**
244      * Constant for the {@link #ifCmp ifCmp} method.
245      */
246     public static final int GT = Opcodes.IFGT;
247 
248     /**
249      * Constant for the {@link #ifCmp ifCmp} method.
250      */
251     public static final int LE = Opcodes.IFLE;
252 
253     /**
254      * Access flags of the method visited by this adapter.
255      */
256     private final int access;
257 
258     /**
259      * Return type of the method visited by this adapter.
260      */
261     private final Type returnType;
262 
263     /**
264      * Argument types of the method visited by this adapter.
265      */
266     private final Type[] argumentTypes;
267 
268     /**
269      * Types of the local variables of the method visited by this adapter.
270      */
271     private final List<Type> localTypes = new ArrayList<Type>();
272 
273     /**
274      * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
275      * constructor</i>. Instead, they must use the
276      * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
277      * version.
278      *
279      * @param mv
280      *            the method visitor to which this adapter delegates calls.
281      * @param access
282      *            the method's access flags (see {@link Opcodes}).
283      * @param name
284      *            the method's name.
285      * @param desc
286      *            the method's descriptor (see {@link Type Type}).
287      * @throws IllegalStateException
288      *             If a subclass calls this constructor.
289      */
GeneratorAdapter(final MethodVisitor mv, final int access, final String name, final String desc)290     public GeneratorAdapter(final MethodVisitor mv, final int access,
291             final String name, final String desc) {
292         this(Opcodes.ASM5, mv, access, name, desc);
293         if (getClass() != GeneratorAdapter.class) {
294             throw new IllegalStateException();
295         }
296     }
297 
298     /**
299      * Creates a new {@link GeneratorAdapter}.
300      *
301      * @param api
302      *            the ASM API version implemented by this visitor. Must be one
303      *            of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
304      * @param mv
305      *            the method visitor to which this adapter delegates calls.
306      * @param access
307      *            the method's access flags (see {@link Opcodes}).
308      * @param name
309      *            the method's name.
310      * @param desc
311      *            the method's descriptor (see {@link Type Type}).
312      */
GeneratorAdapter(final int api, final MethodVisitor mv, final int access, final String name, final String desc)313     protected GeneratorAdapter(final int api, final MethodVisitor mv,
314             final int access, final String name, final String desc) {
315         super(api, access, desc, mv);
316         this.access = access;
317         this.returnType = Type.getReturnType(desc);
318         this.argumentTypes = Type.getArgumentTypes(desc);
319     }
320 
321     /**
322      * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
323      * constructor</i>. Instead, they must use the
324      * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
325      * version.
326      *
327      * @param access
328      *            access flags of the adapted method.
329      * @param method
330      *            the adapted method.
331      * @param mv
332      *            the method visitor to which this adapter delegates calls.
333      */
GeneratorAdapter(final int access, final Method method, final MethodVisitor mv)334     public GeneratorAdapter(final int access, final Method method,
335             final MethodVisitor mv) {
336         this(mv, access, null, method.getDescriptor());
337     }
338 
339     /**
340      * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
341      * constructor</i>. Instead, they must use the
342      * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
343      * version.
344      *
345      * @param access
346      *            access flags of the adapted method.
347      * @param method
348      *            the adapted method.
349      * @param signature
350      *            the signature of the adapted method (may be <tt>null</tt>).
351      * @param exceptions
352      *            the exceptions thrown by the adapted method (may be
353      *            <tt>null</tt>).
354      * @param cv
355      *            the class visitor to which this adapter delegates calls.
356      */
GeneratorAdapter(final int access, final Method method, final String signature, final Type[] exceptions, final ClassVisitor cv)357     public GeneratorAdapter(final int access, final Method method,
358             final String signature, final Type[] exceptions,
359             final ClassVisitor cv) {
360         this(access, method, cv
361                 .visitMethod(access, method.getName(), method.getDescriptor(),
362                         signature, getInternalNames(exceptions)));
363     }
364 
365     /**
366      * Returns the internal names of the given types.
367      *
368      * @param types
369      *            a set of types.
370      * @return the internal names of the given types.
371      */
getInternalNames(final Type[] types)372     private static String[] getInternalNames(final Type[] types) {
373         if (types == null) {
374             return null;
375         }
376         String[] names = new String[types.length];
377         for (int i = 0; i < names.length; ++i) {
378             names[i] = types[i].getInternalName();
379         }
380         return names;
381     }
382 
383     // ------------------------------------------------------------------------
384     // Instructions to push constants on the stack
385     // ------------------------------------------------------------------------
386 
387     /**
388      * Generates the instruction to push the given value on the stack.
389      *
390      * @param value
391      *            the value to be pushed on the stack.
392      */
push(final boolean value)393     public void push(final boolean value) {
394         push(value ? 1 : 0);
395     }
396 
397     /**
398      * Generates the instruction to push the given value on the stack.
399      *
400      * @param value
401      *            the value to be pushed on the stack.
402      */
push(final int value)403     public void push(final int value) {
404         if (value >= -1 && value <= 5) {
405             mv.visitInsn(Opcodes.ICONST_0 + value);
406         } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
407             mv.visitIntInsn(Opcodes.BIPUSH, value);
408         } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
409             mv.visitIntInsn(Opcodes.SIPUSH, value);
410         } else {
411             mv.visitLdcInsn(value);
412         }
413     }
414 
415     /**
416      * Generates the instruction to push the given value on the stack.
417      *
418      * @param value
419      *            the value to be pushed on the stack.
420      */
push(final long value)421     public void push(final long value) {
422         if (value == 0L || value == 1L) {
423             mv.visitInsn(Opcodes.LCONST_0 + (int) value);
424         } else {
425             mv.visitLdcInsn(value);
426         }
427     }
428 
429     /**
430      * Generates the instruction to push the given value on the stack.
431      *
432      * @param value
433      *            the value to be pushed on the stack.
434      */
push(final float value)435     public void push(final float value) {
436         int bits = Float.floatToIntBits(value);
437         if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
438             mv.visitInsn(Opcodes.FCONST_0 + (int) value);
439         } else {
440             mv.visitLdcInsn(value);
441         }
442     }
443 
444     /**
445      * Generates the instruction to push the given value on the stack.
446      *
447      * @param value
448      *            the value to be pushed on the stack.
449      */
push(final double value)450     public void push(final double value) {
451         long bits = Double.doubleToLongBits(value);
452         if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
453             mv.visitInsn(Opcodes.DCONST_0 + (int) value);
454         } else {
455             mv.visitLdcInsn(value);
456         }
457     }
458 
459     /**
460      * Generates the instruction to push the given value on the stack.
461      *
462      * @param value
463      *            the value to be pushed on the stack. May be <tt>null</tt>.
464      */
push(final String value)465     public void push(final String value) {
466         if (value == null) {
467             mv.visitInsn(Opcodes.ACONST_NULL);
468         } else {
469             mv.visitLdcInsn(value);
470         }
471     }
472 
473     /**
474      * Generates the instruction to push the given value on the stack.
475      *
476      * @param value
477      *            the value to be pushed on the stack.
478      */
push(final Type value)479     public void push(final Type value) {
480         if (value == null) {
481             mv.visitInsn(Opcodes.ACONST_NULL);
482         } else {
483             switch (value.getSort()) {
484             case Type.BOOLEAN:
485                 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean",
486                         "TYPE", CLDESC);
487                 break;
488             case Type.CHAR:
489                 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character",
490                         "TYPE", CLDESC);
491                 break;
492             case Type.BYTE:
493                 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE",
494                         CLDESC);
495                 break;
496             case Type.SHORT:
497                 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE",
498                         CLDESC);
499                 break;
500             case Type.INT:
501                 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer",
502                         "TYPE", CLDESC);
503                 break;
504             case Type.FLOAT:
505                 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE",
506                         CLDESC);
507                 break;
508             case Type.LONG:
509                 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE",
510                         CLDESC);
511                 break;
512             case Type.DOUBLE:
513                 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double",
514                         "TYPE", CLDESC);
515                 break;
516             default:
517                 mv.visitLdcInsn(value);
518             }
519         }
520     }
521 
522     /**
523      * Generates the instruction to push a handle on the stack.
524      *
525      * @param handle
526      *            the handle to be pushed on the stack.
527      */
push(final Handle handle)528     public void push(final Handle handle) {
529         mv.visitLdcInsn(handle);
530     }
531 
532     // ------------------------------------------------------------------------
533     // Instructions to load and store method arguments
534     // ------------------------------------------------------------------------
535 
536     /**
537      * Returns the index of the given method argument in the frame's local
538      * variables array.
539      *
540      * @param arg
541      *            the index of a method argument.
542      * @return the index of the given method argument in the frame's local
543      *         variables array.
544      */
getArgIndex(final int arg)545     private int getArgIndex(final int arg) {
546         int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
547         for (int i = 0; i < arg; i++) {
548             index += argumentTypes[i].getSize();
549         }
550         return index;
551     }
552 
553     /**
554      * Generates the instruction to push a local variable on the stack.
555      *
556      * @param type
557      *            the type of the local variable to be loaded.
558      * @param index
559      *            an index in the frame's local variables array.
560      */
loadInsn(final Type type, final int index)561     private void loadInsn(final Type type, final int index) {
562         mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
563     }
564 
565     /**
566      * Generates the instruction to store the top stack value in a local
567      * variable.
568      *
569      * @param type
570      *            the type of the local variable to be stored.
571      * @param index
572      *            an index in the frame's local variables array.
573      */
storeInsn(final Type type, final int index)574     private void storeInsn(final Type type, final int index) {
575         mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
576     }
577 
578     /**
579      * Generates the instruction to load 'this' on the stack.
580      */
loadThis()581     public void loadThis() {
582         if ((access & Opcodes.ACC_STATIC) != 0) {
583             throw new IllegalStateException(
584                     "no 'this' pointer within static method");
585         }
586         mv.visitVarInsn(Opcodes.ALOAD, 0);
587     }
588 
589     /**
590      * Generates the instruction to load the given method argument on the stack.
591      *
592      * @param arg
593      *            the index of a method argument.
594      */
loadArg(final int arg)595     public void loadArg(final int arg) {
596         loadInsn(argumentTypes[arg], getArgIndex(arg));
597     }
598 
599     /**
600      * Generates the instructions to load the given method arguments on the
601      * stack.
602      *
603      * @param arg
604      *            the index of the first method argument to be loaded.
605      * @param count
606      *            the number of method arguments to be loaded.
607      */
loadArgs(final int arg, final int count)608     public void loadArgs(final int arg, final int count) {
609         int index = getArgIndex(arg);
610         for (int i = 0; i < count; ++i) {
611             Type t = argumentTypes[arg + i];
612             loadInsn(t, index);
613             index += t.getSize();
614         }
615     }
616 
617     /**
618      * Generates the instructions to load all the method arguments on the stack.
619      */
loadArgs()620     public void loadArgs() {
621         loadArgs(0, argumentTypes.length);
622     }
623 
624     /**
625      * Generates the instructions to load all the method arguments on the stack,
626      * as a single object array.
627      */
loadArgArray()628     public void loadArgArray() {
629         push(argumentTypes.length);
630         newArray(OBJECT_TYPE);
631         for (int i = 0; i < argumentTypes.length; i++) {
632             dup();
633             push(i);
634             loadArg(i);
635             box(argumentTypes[i]);
636             arrayStore(OBJECT_TYPE);
637         }
638     }
639 
640     /**
641      * Generates the instruction to store the top stack value in the given
642      * method argument.
643      *
644      * @param arg
645      *            the index of a method argument.
646      */
storeArg(final int arg)647     public void storeArg(final int arg) {
648         storeInsn(argumentTypes[arg], getArgIndex(arg));
649     }
650 
651     // ------------------------------------------------------------------------
652     // Instructions to load and store local variables
653     // ------------------------------------------------------------------------
654 
655     /**
656      * Returns the type of the given local variable.
657      *
658      * @param local
659      *            a local variable identifier, as returned by
660      *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
661      * @return the type of the given local variable.
662      */
getLocalType(final int local)663     public Type getLocalType(final int local) {
664         return localTypes.get(local - firstLocal);
665     }
666 
667     @Override
setLocalType(final int local, final Type type)668     protected void setLocalType(final int local, final Type type) {
669         int index = local - firstLocal;
670         while (localTypes.size() < index + 1) {
671             localTypes.add(null);
672         }
673         localTypes.set(index, type);
674     }
675 
676     /**
677      * Generates the instruction to load the given local variable on the stack.
678      *
679      * @param local
680      *            a local variable identifier, as returned by
681      *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
682      */
loadLocal(final int local)683     public void loadLocal(final int local) {
684         loadInsn(getLocalType(local), local);
685     }
686 
687     /**
688      * Generates the instruction to load the given local variable on the stack.
689      *
690      * @param local
691      *            a local variable identifier, as returned by
692      *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
693      * @param type
694      *            the type of this local variable.
695      */
loadLocal(final int local, final Type type)696     public void loadLocal(final int local, final Type type) {
697         setLocalType(local, type);
698         loadInsn(type, local);
699     }
700 
701     /**
702      * Generates the instruction to store the top stack value in the given local
703      * variable.
704      *
705      * @param local
706      *            a local variable identifier, as returned by
707      *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
708      */
storeLocal(final int local)709     public void storeLocal(final int local) {
710         storeInsn(getLocalType(local), local);
711     }
712 
713     /**
714      * Generates the instruction to store the top stack value in the given local
715      * variable.
716      *
717      * @param local
718      *            a local variable identifier, as returned by
719      *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
720      * @param type
721      *            the type of this local variable.
722      */
storeLocal(final int local, final Type type)723     public void storeLocal(final int local, final Type type) {
724         setLocalType(local, type);
725         storeInsn(type, local);
726     }
727 
728     /**
729      * Generates the instruction to load an element from an array.
730      *
731      * @param type
732      *            the type of the array element to be loaded.
733      */
arrayLoad(final Type type)734     public void arrayLoad(final Type type) {
735         mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
736     }
737 
738     /**
739      * Generates the instruction to store an element in an array.
740      *
741      * @param type
742      *            the type of the array element to be stored.
743      */
arrayStore(final Type type)744     public void arrayStore(final Type type) {
745         mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
746     }
747 
748     // ------------------------------------------------------------------------
749     // Instructions to manage the stack
750     // ------------------------------------------------------------------------
751 
752     /**
753      * Generates a POP instruction.
754      */
pop()755     public void pop() {
756         mv.visitInsn(Opcodes.POP);
757     }
758 
759     /**
760      * Generates a POP2 instruction.
761      */
pop2()762     public void pop2() {
763         mv.visitInsn(Opcodes.POP2);
764     }
765 
766     /**
767      * Generates a DUP instruction.
768      */
dup()769     public void dup() {
770         mv.visitInsn(Opcodes.DUP);
771     }
772 
773     /**
774      * Generates a DUP2 instruction.
775      */
dup2()776     public void dup2() {
777         mv.visitInsn(Opcodes.DUP2);
778     }
779 
780     /**
781      * Generates a DUP_X1 instruction.
782      */
dupX1()783     public void dupX1() {
784         mv.visitInsn(Opcodes.DUP_X1);
785     }
786 
787     /**
788      * Generates a DUP_X2 instruction.
789      */
dupX2()790     public void dupX2() {
791         mv.visitInsn(Opcodes.DUP_X2);
792     }
793 
794     /**
795      * Generates a DUP2_X1 instruction.
796      */
dup2X1()797     public void dup2X1() {
798         mv.visitInsn(Opcodes.DUP2_X1);
799     }
800 
801     /**
802      * Generates a DUP2_X2 instruction.
803      */
dup2X2()804     public void dup2X2() {
805         mv.visitInsn(Opcodes.DUP2_X2);
806     }
807 
808     /**
809      * Generates a SWAP instruction.
810      */
swap()811     public void swap() {
812         mv.visitInsn(Opcodes.SWAP);
813     }
814 
815     /**
816      * Generates the instructions to swap the top two stack values.
817      *
818      * @param prev
819      *            type of the top - 1 stack value.
820      * @param type
821      *            type of the top stack value.
822      */
swap(final Type prev, final Type type)823     public void swap(final Type prev, final Type type) {
824         if (type.getSize() == 1) {
825             if (prev.getSize() == 1) {
826                 swap(); // same as dupX1(), pop();
827             } else {
828                 dupX2();
829                 pop();
830             }
831         } else {
832             if (prev.getSize() == 1) {
833                 dup2X1();
834                 pop2();
835             } else {
836                 dup2X2();
837                 pop2();
838             }
839         }
840     }
841 
842     // ------------------------------------------------------------------------
843     // Instructions to do mathematical and logical operations
844     // ------------------------------------------------------------------------
845 
846     /**
847      * Generates the instruction to do the specified mathematical or logical
848      * operation.
849      *
850      * @param op
851      *            a mathematical or logical operation. Must be one of ADD, SUB,
852      *            MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
853      * @param type
854      *            the type of the operand(s) for this operation.
855      */
math(final int op, final Type type)856     public void math(final int op, final Type type) {
857         mv.visitInsn(type.getOpcode(op));
858     }
859 
860     /**
861      * Generates the instructions to compute the bitwise negation of the top
862      * stack value.
863      */
not()864     public void not() {
865         mv.visitInsn(Opcodes.ICONST_1);
866         mv.visitInsn(Opcodes.IXOR);
867     }
868 
869     /**
870      * Generates the instruction to increment the given local variable.
871      *
872      * @param local
873      *            the local variable to be incremented.
874      * @param amount
875      *            the amount by which the local variable must be incremented.
876      */
iinc(final int local, final int amount)877     public void iinc(final int local, final int amount) {
878         mv.visitIincInsn(local, amount);
879     }
880 
881     /**
882      * Generates the instructions to cast a numerical value from one type to
883      * another.
884      *
885      * @param from
886      *            the type of the top stack value
887      * @param to
888      *            the type into which this value must be cast.
889      */
cast(final Type from, final Type to)890     public void cast(final Type from, final Type to) {
891         if (from != to) {
892             if (from == Type.DOUBLE_TYPE) {
893                 if (to == Type.FLOAT_TYPE) {
894                     mv.visitInsn(Opcodes.D2F);
895                 } else if (to == Type.LONG_TYPE) {
896                     mv.visitInsn(Opcodes.D2L);
897                 } else {
898                     mv.visitInsn(Opcodes.D2I);
899                     cast(Type.INT_TYPE, to);
900                 }
901             } else if (from == Type.FLOAT_TYPE) {
902                 if (to == Type.DOUBLE_TYPE) {
903                     mv.visitInsn(Opcodes.F2D);
904                 } else if (to == Type.LONG_TYPE) {
905                     mv.visitInsn(Opcodes.F2L);
906                 } else {
907                     mv.visitInsn(Opcodes.F2I);
908                     cast(Type.INT_TYPE, to);
909                 }
910             } else if (from == Type.LONG_TYPE) {
911                 if (to == Type.DOUBLE_TYPE) {
912                     mv.visitInsn(Opcodes.L2D);
913                 } else if (to == Type.FLOAT_TYPE) {
914                     mv.visitInsn(Opcodes.L2F);
915                 } else {
916                     mv.visitInsn(Opcodes.L2I);
917                     cast(Type.INT_TYPE, to);
918                 }
919             } else {
920                 if (to == Type.BYTE_TYPE) {
921                     mv.visitInsn(Opcodes.I2B);
922                 } else if (to == Type.CHAR_TYPE) {
923                     mv.visitInsn(Opcodes.I2C);
924                 } else if (to == Type.DOUBLE_TYPE) {
925                     mv.visitInsn(Opcodes.I2D);
926                 } else if (to == Type.FLOAT_TYPE) {
927                     mv.visitInsn(Opcodes.I2F);
928                 } else if (to == Type.LONG_TYPE) {
929                     mv.visitInsn(Opcodes.I2L);
930                 } else if (to == Type.SHORT_TYPE) {
931                     mv.visitInsn(Opcodes.I2S);
932                 }
933             }
934         }
935     }
936 
937     // ------------------------------------------------------------------------
938     // Instructions to do boxing and unboxing operations
939     // ------------------------------------------------------------------------
940 
getBoxedType(final Type type)941     private static Type getBoxedType(final Type type) {
942         switch (type.getSort()) {
943         case Type.BYTE:
944             return BYTE_TYPE;
945         case Type.BOOLEAN:
946             return BOOLEAN_TYPE;
947         case Type.SHORT:
948             return SHORT_TYPE;
949         case Type.CHAR:
950             return CHARACTER_TYPE;
951         case Type.INT:
952             return INTEGER_TYPE;
953         case Type.FLOAT:
954             return FLOAT_TYPE;
955         case Type.LONG:
956             return LONG_TYPE;
957         case Type.DOUBLE:
958             return DOUBLE_TYPE;
959         }
960         return type;
961     }
962 
963     /**
964      * Generates the instructions to box the top stack value. This value is
965      * replaced by its boxed equivalent on top of the stack.
966      *
967      * @param type
968      *            the type of the top stack value.
969      */
box(final Type type)970     public void box(final Type type) {
971         if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
972             return;
973         }
974         if (type == Type.VOID_TYPE) {
975             push((String) null);
976         } else {
977             Type boxed = getBoxedType(type);
978             newInstance(boxed);
979             if (type.getSize() == 2) {
980                 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
981                 dupX2();
982                 dupX2();
983                 pop();
984             } else {
985                 // p -> po -> opo -> oop -> o
986                 dupX1();
987                 swap();
988             }
989             invokeConstructor(boxed, new Method("<init>", Type.VOID_TYPE,
990                     new Type[] { type }));
991         }
992     }
993 
994     /**
995      * Generates the instructions to box the top stack value using Java 5's
996      * valueOf() method. This value is replaced by its boxed equivalent on top
997      * of the stack.
998      *
999      * @param type
1000      *            the type of the top stack value.
1001      */
valueOf(final Type type)1002     public void valueOf(final Type type) {
1003         if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
1004             return;
1005         }
1006         if (type == Type.VOID_TYPE) {
1007             push((String) null);
1008         } else {
1009             Type boxed = getBoxedType(type);
1010             invokeStatic(boxed, new Method("valueOf", boxed,
1011                     new Type[] { type }));
1012         }
1013     }
1014 
1015     /**
1016      * Generates the instructions to unbox the top stack value. This value is
1017      * replaced by its unboxed equivalent on top of the stack.
1018      *
1019      * @param type
1020      *            the type of the top stack value.
1021      */
unbox(final Type type)1022     public void unbox(final Type type) {
1023         Type t = NUMBER_TYPE;
1024         Method sig = null;
1025         switch (type.getSort()) {
1026         case Type.VOID:
1027             return;
1028         case Type.CHAR:
1029             t = CHARACTER_TYPE;
1030             sig = CHAR_VALUE;
1031             break;
1032         case Type.BOOLEAN:
1033             t = BOOLEAN_TYPE;
1034             sig = BOOLEAN_VALUE;
1035             break;
1036         case Type.DOUBLE:
1037             sig = DOUBLE_VALUE;
1038             break;
1039         case Type.FLOAT:
1040             sig = FLOAT_VALUE;
1041             break;
1042         case Type.LONG:
1043             sig = LONG_VALUE;
1044             break;
1045         case Type.INT:
1046         case Type.SHORT:
1047         case Type.BYTE:
1048             sig = INT_VALUE;
1049         }
1050         if (sig == null) {
1051             checkCast(type);
1052         } else {
1053             checkCast(t);
1054             invokeVirtual(t, sig);
1055         }
1056     }
1057 
1058     // ------------------------------------------------------------------------
1059     // Instructions to jump to other instructions
1060     // ------------------------------------------------------------------------
1061 
1062     /**
1063      * Creates a new {@link Label}.
1064      *
1065      * @return a new {@link Label}.
1066      */
newLabel()1067     public Label newLabel() {
1068         return new Label();
1069     }
1070 
1071     /**
1072      * Marks the current code position with the given label.
1073      *
1074      * @param label
1075      *            a label.
1076      */
mark(final Label label)1077     public void mark(final Label label) {
1078         mv.visitLabel(label);
1079     }
1080 
1081     /**
1082      * Marks the current code position with a new label.
1083      *
1084      * @return the label that was created to mark the current code position.
1085      */
mark()1086     public Label mark() {
1087         Label label = new Label();
1088         mv.visitLabel(label);
1089         return label;
1090     }
1091 
1092     /**
1093      * Generates the instructions to jump to a label based on the comparison of
1094      * the top two stack values.
1095      *
1096      * @param type
1097      *            the type of the top two stack values.
1098      * @param mode
1099      *            how these values must be compared. One of EQ, NE, LT, GE, GT,
1100      *            LE.
1101      * @param label
1102      *            where to jump if the comparison result is <tt>true</tt>.
1103      */
ifCmp(final Type type, final int mode, final Label label)1104     public void ifCmp(final Type type, final int mode, final Label label) {
1105         switch (type.getSort()) {
1106         case Type.LONG:
1107             mv.visitInsn(Opcodes.LCMP);
1108             break;
1109         case Type.DOUBLE:
1110             mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPL
1111                     : Opcodes.DCMPG);
1112             break;
1113         case Type.FLOAT:
1114             mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPL
1115                     : Opcodes.FCMPG);
1116             break;
1117         case Type.ARRAY:
1118         case Type.OBJECT:
1119             switch (mode) {
1120             case EQ:
1121                 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
1122                 return;
1123             case NE:
1124                 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
1125                 return;
1126             }
1127             throw new IllegalArgumentException("Bad comparison for type "
1128                     + type);
1129         default:
1130             int intOp = -1;
1131             switch (mode) {
1132             case EQ:
1133                 intOp = Opcodes.IF_ICMPEQ;
1134                 break;
1135             case NE:
1136                 intOp = Opcodes.IF_ICMPNE;
1137                 break;
1138             case GE:
1139                 intOp = Opcodes.IF_ICMPGE;
1140                 break;
1141             case LT:
1142                 intOp = Opcodes.IF_ICMPLT;
1143                 break;
1144             case LE:
1145                 intOp = Opcodes.IF_ICMPLE;
1146                 break;
1147             case GT:
1148                 intOp = Opcodes.IF_ICMPGT;
1149                 break;
1150             }
1151             mv.visitJumpInsn(intOp, label);
1152             return;
1153         }
1154         mv.visitJumpInsn(mode, label);
1155     }
1156 
1157     /**
1158      * Generates the instructions to jump to a label based on the comparison of
1159      * the top two integer stack values.
1160      *
1161      * @param mode
1162      *            how these values must be compared. One of EQ, NE, LT, GE, GT,
1163      *            LE.
1164      * @param label
1165      *            where to jump if the comparison result is <tt>true</tt>.
1166      */
ifICmp(final int mode, final Label label)1167     public void ifICmp(final int mode, final Label label) {
1168         ifCmp(Type.INT_TYPE, mode, label);
1169     }
1170 
1171     /**
1172      * Generates the instructions to jump to a label based on the comparison of
1173      * the top integer stack value with zero.
1174      *
1175      * @param mode
1176      *            how these values must be compared. One of EQ, NE, LT, GE, GT,
1177      *            LE.
1178      * @param label
1179      *            where to jump if the comparison result is <tt>true</tt>.
1180      */
ifZCmp(final int mode, final Label label)1181     public void ifZCmp(final int mode, final Label label) {
1182         mv.visitJumpInsn(mode, label);
1183     }
1184 
1185     /**
1186      * Generates the instruction to jump to the given label if the top stack
1187      * value is null.
1188      *
1189      * @param label
1190      *            where to jump if the condition is <tt>true</tt>.
1191      */
ifNull(final Label label)1192     public void ifNull(final Label label) {
1193         mv.visitJumpInsn(Opcodes.IFNULL, label);
1194     }
1195 
1196     /**
1197      * Generates the instruction to jump to the given label if the top stack
1198      * value is not null.
1199      *
1200      * @param label
1201      *            where to jump if the condition is <tt>true</tt>.
1202      */
ifNonNull(final Label label)1203     public void ifNonNull(final Label label) {
1204         mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1205     }
1206 
1207     /**
1208      * Generates the instruction to jump to the given label.
1209      *
1210      * @param label
1211      *            where to jump if the condition is <tt>true</tt>.
1212      */
goTo(final Label label)1213     public void goTo(final Label label) {
1214         mv.visitJumpInsn(Opcodes.GOTO, label);
1215     }
1216 
1217     /**
1218      * Generates a RET instruction.
1219      *
1220      * @param local
1221      *            a local variable identifier, as returned by
1222      *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
1223      */
ret(final int local)1224     public void ret(final int local) {
1225         mv.visitVarInsn(Opcodes.RET, local);
1226     }
1227 
1228     /**
1229      * Generates the instructions for a switch statement.
1230      *
1231      * @param keys
1232      *            the switch case keys.
1233      * @param generator
1234      *            a generator to generate the code for the switch cases.
1235      */
tableSwitch(final int[] keys, final TableSwitchGenerator generator)1236     public void tableSwitch(final int[] keys,
1237             final TableSwitchGenerator generator) {
1238         float density;
1239         if (keys.length == 0) {
1240             density = 0;
1241         } else {
1242             density = (float) keys.length
1243                     / (keys[keys.length - 1] - keys[0] + 1);
1244         }
1245         tableSwitch(keys, generator, density >= 0.5f);
1246     }
1247 
1248     /**
1249      * Generates the instructions for a switch statement.
1250      *
1251      * @param keys
1252      *            the switch case keys.
1253      * @param generator
1254      *            a generator to generate the code for the switch cases.
1255      * @param useTable
1256      *            <tt>true</tt> to use a TABLESWITCH instruction, or
1257      *            <tt>false</tt> to use a LOOKUPSWITCH instruction.
1258      */
tableSwitch(final int[] keys, final TableSwitchGenerator generator, final boolean useTable)1259     public void tableSwitch(final int[] keys,
1260             final TableSwitchGenerator generator, final boolean useTable) {
1261         for (int i = 1; i < keys.length; ++i) {
1262             if (keys[i] < keys[i - 1]) {
1263                 throw new IllegalArgumentException(
1264                         "keys must be sorted ascending");
1265             }
1266         }
1267         Label def = newLabel();
1268         Label end = newLabel();
1269         if (keys.length > 0) {
1270             int len = keys.length;
1271             int min = keys[0];
1272             int max = keys[len - 1];
1273             int range = max - min + 1;
1274             if (useTable) {
1275                 Label[] labels = new Label[range];
1276                 Arrays.fill(labels, def);
1277                 for (int i = 0; i < len; ++i) {
1278                     labels[keys[i] - min] = newLabel();
1279                 }
1280                 mv.visitTableSwitchInsn(min, max, def, labels);
1281                 for (int i = 0; i < range; ++i) {
1282                     Label label = labels[i];
1283                     if (label != def) {
1284                         mark(label);
1285                         generator.generateCase(i + min, end);
1286                     }
1287                 }
1288             } else {
1289                 Label[] labels = new Label[len];
1290                 for (int i = 0; i < len; ++i) {
1291                     labels[i] = newLabel();
1292                 }
1293                 mv.visitLookupSwitchInsn(def, keys, labels);
1294                 for (int i = 0; i < len; ++i) {
1295                     mark(labels[i]);
1296                     generator.generateCase(keys[i], end);
1297                 }
1298             }
1299         }
1300         mark(def);
1301         generator.generateDefault();
1302         mark(end);
1303     }
1304 
1305     /**
1306      * Generates the instruction to return the top stack value to the caller.
1307      */
returnValue()1308     public void returnValue() {
1309         mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
1310     }
1311 
1312     // ------------------------------------------------------------------------
1313     // Instructions to load and store fields
1314     // ------------------------------------------------------------------------
1315 
1316     /**
1317      * Generates a get field or set field instruction.
1318      *
1319      * @param opcode
1320      *            the instruction's opcode.
1321      * @param ownerType
1322      *            the class in which the field is defined.
1323      * @param name
1324      *            the name of the field.
1325      * @param fieldType
1326      *            the type of the field.
1327      */
fieldInsn(final int opcode, final Type ownerType, final String name, final Type fieldType)1328     private void fieldInsn(final int opcode, final Type ownerType,
1329             final String name, final Type fieldType) {
1330         mv.visitFieldInsn(opcode, ownerType.getInternalName(), name,
1331                 fieldType.getDescriptor());
1332     }
1333 
1334     /**
1335      * Generates the instruction to push the value of a static field on the
1336      * stack.
1337      *
1338      * @param owner
1339      *            the class in which the field is defined.
1340      * @param name
1341      *            the name of the field.
1342      * @param type
1343      *            the type of the field.
1344      */
getStatic(final Type owner, final String name, final Type type)1345     public void getStatic(final Type owner, final String name, final Type type) {
1346         fieldInsn(Opcodes.GETSTATIC, owner, name, type);
1347     }
1348 
1349     /**
1350      * Generates the instruction to store the top stack value in a static field.
1351      *
1352      * @param owner
1353      *            the class in which the field is defined.
1354      * @param name
1355      *            the name of the field.
1356      * @param type
1357      *            the type of the field.
1358      */
putStatic(final Type owner, final String name, final Type type)1359     public void putStatic(final Type owner, final String name, final Type type) {
1360         fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
1361     }
1362 
1363     /**
1364      * Generates the instruction to push the value of a non static field on the
1365      * stack.
1366      *
1367      * @param owner
1368      *            the class in which the field is defined.
1369      * @param name
1370      *            the name of the field.
1371      * @param type
1372      *            the type of the field.
1373      */
getField(final Type owner, final String name, final Type type)1374     public void getField(final Type owner, final String name, final Type type) {
1375         fieldInsn(Opcodes.GETFIELD, owner, name, type);
1376     }
1377 
1378     /**
1379      * Generates the instruction to store the top stack value in a non static
1380      * field.
1381      *
1382      * @param owner
1383      *            the class in which the field is defined.
1384      * @param name
1385      *            the name of the field.
1386      * @param type
1387      *            the type of the field.
1388      */
putField(final Type owner, final String name, final Type type)1389     public void putField(final Type owner, final String name, final Type type) {
1390         fieldInsn(Opcodes.PUTFIELD, owner, name, type);
1391     }
1392 
1393     // ------------------------------------------------------------------------
1394     // Instructions to invoke methods
1395     // ------------------------------------------------------------------------
1396 
1397     /**
1398      * Generates an invoke method instruction.
1399      *
1400      * @param opcode
1401      *            the instruction's opcode.
1402      * @param type
1403      *            the class in which the method is defined.
1404      * @param method
1405      *            the method to be invoked.
1406      */
invokeInsn(final int opcode, final Type type, final Method method, final boolean itf)1407     private void invokeInsn(final int opcode, final Type type,
1408             final Method method, final boolean itf) {
1409         String owner = type.getSort() == Type.ARRAY ? type.getDescriptor()
1410                 : type.getInternalName();
1411         mv.visitMethodInsn(opcode, owner, method.getName(),
1412                 method.getDescriptor(), itf);
1413     }
1414 
1415     /**
1416      * Generates the instruction to invoke a normal method.
1417      *
1418      * @param owner
1419      *            the class in which the method is defined.
1420      * @param method
1421      *            the method to be invoked.
1422      */
invokeVirtual(final Type owner, final Method method)1423     public void invokeVirtual(final Type owner, final Method method) {
1424         invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false);
1425     }
1426 
1427     /**
1428      * Generates the instruction to invoke a constructor.
1429      *
1430      * @param type
1431      *            the class in which the constructor is defined.
1432      * @param method
1433      *            the constructor to be invoked.
1434      */
invokeConstructor(final Type type, final Method method)1435     public void invokeConstructor(final Type type, final Method method) {
1436         invokeInsn(Opcodes.INVOKESPECIAL, type, method, false);
1437     }
1438 
1439     /**
1440      * Generates the instruction to invoke a static method.
1441      *
1442      * @param owner
1443      *            the class in which the method is defined.
1444      * @param method
1445      *            the method to be invoked.
1446      */
invokeStatic(final Type owner, final Method method)1447     public void invokeStatic(final Type owner, final Method method) {
1448         invokeInsn(Opcodes.INVOKESTATIC, owner, method, false);
1449     }
1450 
1451     /**
1452      * Generates the instruction to invoke an interface method.
1453      *
1454      * @param owner
1455      *            the class in which the method is defined.
1456      * @param method
1457      *            the method to be invoked.
1458      */
invokeInterface(final Type owner, final Method method)1459     public void invokeInterface(final Type owner, final Method method) {
1460         invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true);
1461     }
1462 
1463     /**
1464      * Generates an invokedynamic instruction.
1465      *
1466      * @param name
1467      *            the method's name.
1468      * @param desc
1469      *            the method's descriptor (see {@link Type Type}).
1470      * @param bsm
1471      *            the bootstrap method.
1472      * @param bsmArgs
1473      *            the bootstrap method constant arguments. Each argument must be
1474      *            an {@link Integer}, {@link Float}, {@link Long},
1475      *            {@link Double}, {@link String}, {@link Type} or {@link Handle}
1476      *            value. This method is allowed to modify the content of the
1477      *            array so a caller should expect that this array may change.
1478      */
invokeDynamic(String name, String desc, Handle bsm, Object... bsmArgs)1479     public void invokeDynamic(String name, String desc, Handle bsm,
1480             Object... bsmArgs) {
1481         mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
1482     }
1483 
1484     // ------------------------------------------------------------------------
1485     // Instructions to create objects and arrays
1486     // ------------------------------------------------------------------------
1487 
1488     /**
1489      * Generates a type dependent instruction.
1490      *
1491      * @param opcode
1492      *            the instruction's opcode.
1493      * @param type
1494      *            the instruction's operand.
1495      */
typeInsn(final int opcode, final Type type)1496     private void typeInsn(final int opcode, final Type type) {
1497         mv.visitTypeInsn(opcode, type.getInternalName());
1498     }
1499 
1500     /**
1501      * Generates the instruction to create a new object.
1502      *
1503      * @param type
1504      *            the class of the object to be created.
1505      */
newInstance(final Type type)1506     public void newInstance(final Type type) {
1507         typeInsn(Opcodes.NEW, type);
1508     }
1509 
1510     /**
1511      * Generates the instruction to create a new array.
1512      *
1513      * @param type
1514      *            the type of the array elements.
1515      */
newArray(final Type type)1516     public void newArray(final Type type) {
1517         int typ;
1518         switch (type.getSort()) {
1519         case Type.BOOLEAN:
1520             typ = Opcodes.T_BOOLEAN;
1521             break;
1522         case Type.CHAR:
1523             typ = Opcodes.T_CHAR;
1524             break;
1525         case Type.BYTE:
1526             typ = Opcodes.T_BYTE;
1527             break;
1528         case Type.SHORT:
1529             typ = Opcodes.T_SHORT;
1530             break;
1531         case Type.INT:
1532             typ = Opcodes.T_INT;
1533             break;
1534         case Type.FLOAT:
1535             typ = Opcodes.T_FLOAT;
1536             break;
1537         case Type.LONG:
1538             typ = Opcodes.T_LONG;
1539             break;
1540         case Type.DOUBLE:
1541             typ = Opcodes.T_DOUBLE;
1542             break;
1543         default:
1544             typeInsn(Opcodes.ANEWARRAY, type);
1545             return;
1546         }
1547         mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1548     }
1549 
1550     // ------------------------------------------------------------------------
1551     // Miscelaneous instructions
1552     // ------------------------------------------------------------------------
1553 
1554     /**
1555      * Generates the instruction to compute the length of an array.
1556      */
arrayLength()1557     public void arrayLength() {
1558         mv.visitInsn(Opcodes.ARRAYLENGTH);
1559     }
1560 
1561     /**
1562      * Generates the instruction to throw an exception.
1563      */
throwException()1564     public void throwException() {
1565         mv.visitInsn(Opcodes.ATHROW);
1566     }
1567 
1568     /**
1569      * Generates the instructions to create and throw an exception. The
1570      * exception class must have a constructor with a single String argument.
1571      *
1572      * @param type
1573      *            the class of the exception to be thrown.
1574      * @param msg
1575      *            the detailed message of the exception.
1576      */
throwException(final Type type, final String msg)1577     public void throwException(final Type type, final String msg) {
1578         newInstance(type);
1579         dup();
1580         push(msg);
1581         invokeConstructor(type, Method.getMethod("void <init> (String)"));
1582         throwException();
1583     }
1584 
1585     /**
1586      * Generates the instruction to check that the top stack value is of the
1587      * given type.
1588      *
1589      * @param type
1590      *            a class or interface type.
1591      */
checkCast(final Type type)1592     public void checkCast(final Type type) {
1593         if (!type.equals(OBJECT_TYPE)) {
1594             typeInsn(Opcodes.CHECKCAST, type);
1595         }
1596     }
1597 
1598     /**
1599      * Generates the instruction to test if the top stack value is of the given
1600      * type.
1601      *
1602      * @param type
1603      *            a class or interface type.
1604      */
instanceOf(final Type type)1605     public void instanceOf(final Type type) {
1606         typeInsn(Opcodes.INSTANCEOF, type);
1607     }
1608 
1609     /**
1610      * Generates the instruction to get the monitor of the top stack value.
1611      */
monitorEnter()1612     public void monitorEnter() {
1613         mv.visitInsn(Opcodes.MONITORENTER);
1614     }
1615 
1616     /**
1617      * Generates the instruction to release the monitor of the top stack value.
1618      */
monitorExit()1619     public void monitorExit() {
1620         mv.visitInsn(Opcodes.MONITOREXIT);
1621     }
1622 
1623     // ------------------------------------------------------------------------
1624     // Non instructions
1625     // ------------------------------------------------------------------------
1626 
1627     /**
1628      * Marks the end of the visited method.
1629      */
endMethod()1630     public void endMethod() {
1631         if ((access & Opcodes.ACC_ABSTRACT) == 0) {
1632             mv.visitMaxs(0, 0);
1633         }
1634         mv.visitEnd();
1635     }
1636 
1637     /**
1638      * Marks the start of an exception handler.
1639      *
1640      * @param start
1641      *            beginning of the exception handler's scope (inclusive).
1642      * @param end
1643      *            end of the exception handler's scope (exclusive).
1644      * @param exception
1645      *            internal name of the type of exceptions handled by the
1646      *            handler.
1647      */
catchException(final Label start, final Label end, final Type exception)1648     public void catchException(final Label start, final Label end,
1649             final Type exception) {
1650         Label doCatch = new Label();
1651         if (exception == null) {
1652             mv.visitTryCatchBlock(start, end, doCatch, null);
1653         } else {
1654             mv.visitTryCatchBlock(start, end, doCatch,
1655                     exception.getInternalName());
1656         }
1657         mark(doCatch);
1658     }
1659 }
1660