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