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