Home | History | Annotate | Download | only in util
      1 /***
      2  * ASM: a very small and fast Java bytecode manipulation framework
      3  * Copyright (c) 2000-2007 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.mockito.asm.util;
     31 
     32 import org.mockito.asm.AnnotationVisitor;
     33 import org.mockito.asm.Attribute;
     34 import org.mockito.asm.Label;
     35 import org.mockito.asm.MethodAdapter;
     36 import org.mockito.asm.MethodVisitor;
     37 import org.mockito.asm.Opcodes;
     38 import org.mockito.asm.Type;
     39 
     40 import java.util.HashMap;
     41 import java.util.Map;
     42 
     43 /**
     44  * A {@link MethodAdapter} that checks that its methods are properly used. More
     45  * precisely this code adapter checks each instruction individually (i.e., each
     46  * visit method checks some preconditions based <i>only</i> on its arguments -
     47  * such as the fact that the given opcode is correct for a given visit method),
     48  * but does <i>not</i> check the <i>sequence</i> of instructions. For example,
     49  * in a method whose signature is <tt>void m ()</tt>, the invalid instruction
     50  * IRETURN, or the invalid sequence IADD L2I will <i>not</i> be detected by
     51  * this code adapter.
     52  *
     53  * @author Eric Bruneton
     54  */
     55 public class CheckMethodAdapter extends MethodAdapter {
     56 
     57     /**
     58      * <tt>true</tt> if the visitCode method has been called.
     59      */
     60     private boolean startCode;
     61 
     62     /**
     63      * <tt>true</tt> if the visitMaxs method has been called.
     64      */
     65     private boolean endCode;
     66 
     67     /**
     68      * <tt>true</tt> if the visitEnd method has been called.
     69      */
     70     private boolean endMethod;
     71 
     72     /**
     73      * The already visited labels. This map associate Integer values to Label
     74      * keys.
     75      */
     76     private final Map labels;
     77 
     78     /**
     79      * Code of the visit method to be used for each opcode.
     80      */
     81     private static final int[] TYPE;
     82 
     83     static {
     84         String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD"
     85                 + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
     86                 + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD"
     87                 + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA";
     88         TYPE = new int[s.length()];
     89         for (int i = 0; i < TYPE.length; ++i) {
     90             TYPE[i] = s.charAt(i) - 'A' - 1;
     91         }
     92     }
     93 
     94     // code to generate the above string
     95     // public static void main (String[] args) {
     96     // int[] TYPE = new int[] {
     97     // 0, //NOP
     98     // 0, //ACONST_NULL
     99     // 0, //ICONST_M1
    100     // 0, //ICONST_0
    101     // 0, //ICONST_1
    102     // 0, //ICONST_2
    103     // 0, //ICONST_3
    104     // 0, //ICONST_4
    105     // 0, //ICONST_5
    106     // 0, //LCONST_0
    107     // 0, //LCONST_1
    108     // 0, //FCONST_0
    109     // 0, //FCONST_1
    110     // 0, //FCONST_2
    111     // 0, //DCONST_0
    112     // 0, //DCONST_1
    113     // 1, //BIPUSH
    114     // 1, //SIPUSH
    115     // 7, //LDC
    116     // -1, //LDC_W
    117     // -1, //LDC2_W
    118     // 2, //ILOAD
    119     // 2, //LLOAD
    120     // 2, //FLOAD
    121     // 2, //DLOAD
    122     // 2, //ALOAD
    123     // -1, //ILOAD_0
    124     // -1, //ILOAD_1
    125     // -1, //ILOAD_2
    126     // -1, //ILOAD_3
    127     // -1, //LLOAD_0
    128     // -1, //LLOAD_1
    129     // -1, //LLOAD_2
    130     // -1, //LLOAD_3
    131     // -1, //FLOAD_0
    132     // -1, //FLOAD_1
    133     // -1, //FLOAD_2
    134     // -1, //FLOAD_3
    135     // -1, //DLOAD_0
    136     // -1, //DLOAD_1
    137     // -1, //DLOAD_2
    138     // -1, //DLOAD_3
    139     // -1, //ALOAD_0
    140     // -1, //ALOAD_1
    141     // -1, //ALOAD_2
    142     // -1, //ALOAD_3
    143     // 0, //IALOAD
    144     // 0, //LALOAD
    145     // 0, //FALOAD
    146     // 0, //DALOAD
    147     // 0, //AALOAD
    148     // 0, //BALOAD
    149     // 0, //CALOAD
    150     // 0, //SALOAD
    151     // 2, //ISTORE
    152     // 2, //LSTORE
    153     // 2, //FSTORE
    154     // 2, //DSTORE
    155     // 2, //ASTORE
    156     // -1, //ISTORE_0
    157     // -1, //ISTORE_1
    158     // -1, //ISTORE_2
    159     // -1, //ISTORE_3
    160     // -1, //LSTORE_0
    161     // -1, //LSTORE_1
    162     // -1, //LSTORE_2
    163     // -1, //LSTORE_3
    164     // -1, //FSTORE_0
    165     // -1, //FSTORE_1
    166     // -1, //FSTORE_2
    167     // -1, //FSTORE_3
    168     // -1, //DSTORE_0
    169     // -1, //DSTORE_1
    170     // -1, //DSTORE_2
    171     // -1, //DSTORE_3
    172     // -1, //ASTORE_0
    173     // -1, //ASTORE_1
    174     // -1, //ASTORE_2
    175     // -1, //ASTORE_3
    176     // 0, //IASTORE
    177     // 0, //LASTORE
    178     // 0, //FASTORE
    179     // 0, //DASTORE
    180     // 0, //AASTORE
    181     // 0, //BASTORE
    182     // 0, //CASTORE
    183     // 0, //SASTORE
    184     // 0, //POP
    185     // 0, //POP2
    186     // 0, //DUP
    187     // 0, //DUP_X1
    188     // 0, //DUP_X2
    189     // 0, //DUP2
    190     // 0, //DUP2_X1
    191     // 0, //DUP2_X2
    192     // 0, //SWAP
    193     // 0, //IADD
    194     // 0, //LADD
    195     // 0, //FADD
    196     // 0, //DADD
    197     // 0, //ISUB
    198     // 0, //LSUB
    199     // 0, //FSUB
    200     // 0, //DSUB
    201     // 0, //IMUL
    202     // 0, //LMUL
    203     // 0, //FMUL
    204     // 0, //DMUL
    205     // 0, //IDIV
    206     // 0, //LDIV
    207     // 0, //FDIV
    208     // 0, //DDIV
    209     // 0, //IREM
    210     // 0, //LREM
    211     // 0, //FREM
    212     // 0, //DREM
    213     // 0, //INEG
    214     // 0, //LNEG
    215     // 0, //FNEG
    216     // 0, //DNEG
    217     // 0, //ISHL
    218     // 0, //LSHL
    219     // 0, //ISHR
    220     // 0, //LSHR
    221     // 0, //IUSHR
    222     // 0, //LUSHR
    223     // 0, //IAND
    224     // 0, //LAND
    225     // 0, //IOR
    226     // 0, //LOR
    227     // 0, //IXOR
    228     // 0, //LXOR
    229     // 8, //IINC
    230     // 0, //I2L
    231     // 0, //I2F
    232     // 0, //I2D
    233     // 0, //L2I
    234     // 0, //L2F
    235     // 0, //L2D
    236     // 0, //F2I
    237     // 0, //F2L
    238     // 0, //F2D
    239     // 0, //D2I
    240     // 0, //D2L
    241     // 0, //D2F
    242     // 0, //I2B
    243     // 0, //I2C
    244     // 0, //I2S
    245     // 0, //LCMP
    246     // 0, //FCMPL
    247     // 0, //FCMPG
    248     // 0, //DCMPL
    249     // 0, //DCMPG
    250     // 6, //IFEQ
    251     // 6, //IFNE
    252     // 6, //IFLT
    253     // 6, //IFGE
    254     // 6, //IFGT
    255     // 6, //IFLE
    256     // 6, //IF_ICMPEQ
    257     // 6, //IF_ICMPNE
    258     // 6, //IF_ICMPLT
    259     // 6, //IF_ICMPGE
    260     // 6, //IF_ICMPGT
    261     // 6, //IF_ICMPLE
    262     // 6, //IF_ACMPEQ
    263     // 6, //IF_ACMPNE
    264     // 6, //GOTO
    265     // 6, //JSR
    266     // 2, //RET
    267     // 9, //TABLESWITCH
    268     // 10, //LOOKUPSWITCH
    269     // 0, //IRETURN
    270     // 0, //LRETURN
    271     // 0, //FRETURN
    272     // 0, //DRETURN
    273     // 0, //ARETURN
    274     // 0, //RETURN
    275     // 4, //GETSTATIC
    276     // 4, //PUTSTATIC
    277     // 4, //GETFIELD
    278     // 4, //PUTFIELD
    279     // 5, //INVOKEVIRTUAL
    280     // 5, //INVOKESPECIAL
    281     // 5, //INVOKESTATIC
    282     // 5, //INVOKEINTERFACE
    283     // -1, //UNUSED
    284     // 3, //NEW
    285     // 1, //NEWARRAY
    286     // 3, //ANEWARRAY
    287     // 0, //ARRAYLENGTH
    288     // 0, //ATHROW
    289     // 3, //CHECKCAST
    290     // 3, //INSTANCEOF
    291     // 0, //MONITORENTER
    292     // 0, //MONITOREXIT
    293     // -1, //WIDE
    294     // 11, //MULTIANEWARRAY
    295     // 6, //IFNULL
    296     // 6, //IFNONNULL
    297     // -1, //GOTO_W
    298     // -1 //JSR_W
    299     // };
    300     // for (int i = 0; i < TYPE.length; ++i) {
    301     // System.out.print((char)(TYPE[i] + 1 + 'A'));
    302     // }
    303     // System.out.println();
    304     // }
    305 
    306     /**
    307      * Constructs a new {@link CheckMethodAdapter} object.
    308      *
    309      * @param cv the code visitor to which this adapter must delegate calls.
    310      */
    311     public CheckMethodAdapter(final MethodVisitor cv) {
    312         super(cv);
    313         this.labels = new HashMap();
    314     }
    315 
    316     public AnnotationVisitor visitAnnotation(
    317         final String desc,
    318         final boolean visible)
    319     {
    320         checkEndMethod();
    321         checkDesc(desc, false);
    322         return new CheckAnnotationAdapter(mv.visitAnnotation(desc, visible));
    323     }
    324 
    325     public AnnotationVisitor visitAnnotationDefault() {
    326         checkEndMethod();
    327         return new CheckAnnotationAdapter(mv.visitAnnotationDefault(), false);
    328     }
    329 
    330     public AnnotationVisitor visitParameterAnnotation(
    331         final int parameter,
    332         final String desc,
    333         final boolean visible)
    334     {
    335         checkEndMethod();
    336         checkDesc(desc, false);
    337         return new CheckAnnotationAdapter(mv.visitParameterAnnotation(parameter,
    338                 desc,
    339                 visible));
    340     }
    341 
    342     public void visitAttribute(final Attribute attr) {
    343         checkEndMethod();
    344         if (attr == null) {
    345             throw new IllegalArgumentException("Invalid attribute (must not be null)");
    346         }
    347         mv.visitAttribute(attr);
    348     }
    349 
    350     public void visitCode() {
    351         startCode = true;
    352         mv.visitCode();
    353     }
    354 
    355     public void visitFrame(
    356         final int type,
    357         final int nLocal,
    358         final Object[] local,
    359         final int nStack,
    360         final Object[] stack)
    361     {
    362         int mLocal;
    363         int mStack;
    364         switch (type) {
    365             case Opcodes.F_NEW:
    366             case Opcodes.F_FULL:
    367                 mLocal = Integer.MAX_VALUE;
    368                 mStack = Integer.MAX_VALUE;
    369                 break;
    370 
    371             case Opcodes.F_SAME:
    372                 mLocal = 0;
    373                 mStack = 0;
    374                 break;
    375 
    376             case Opcodes.F_SAME1:
    377                 mLocal = 0;
    378                 mStack = 1;
    379                 break;
    380 
    381             case Opcodes.F_APPEND:
    382             case Opcodes.F_CHOP:
    383                 mLocal = 3;
    384                 mStack = 0;
    385                 break;
    386 
    387             default:
    388                 throw new IllegalArgumentException("Invalid frame type " + type);
    389         }
    390 
    391         if (nLocal > mLocal) {
    392             throw new IllegalArgumentException("Invalid nLocal=" + nLocal
    393                     + " for frame type " + type);
    394         }
    395         if (nStack > mStack) {
    396             throw new IllegalArgumentException("Invalid nStack=" + nStack
    397                     + " for frame type " + type);
    398         }
    399 
    400         if (type != Opcodes.F_CHOP) {
    401             if (nLocal > 0 && (local == null || local.length < nLocal)) {
    402                 throw new IllegalArgumentException("Array local[] is shorter than nLocal");
    403             }
    404             for (int i = 0; i < nLocal; ++i) {
    405                 checkFrameValue(local[i]);
    406             }
    407         }
    408         if (nStack > 0 && (stack == null || stack.length < nStack)) {
    409             throw new IllegalArgumentException("Array stack[] is shorter than nStack");
    410         }
    411         for (int i = 0; i < nStack; ++i) {
    412             checkFrameValue(stack[i]);
    413         }
    414 
    415         mv.visitFrame(type, nLocal, local, nStack, stack);
    416     }
    417 
    418     public void visitInsn(final int opcode) {
    419         checkStartCode();
    420         checkEndCode();
    421         checkOpcode(opcode, 0);
    422         mv.visitInsn(opcode);
    423     }
    424 
    425     public void visitIntInsn(final int opcode, final int operand) {
    426         checkStartCode();
    427         checkEndCode();
    428         checkOpcode(opcode, 1);
    429         switch (opcode) {
    430             case Opcodes.BIPUSH:
    431                 checkSignedByte(operand, "Invalid operand");
    432                 break;
    433             case Opcodes.SIPUSH:
    434                 checkSignedShort(operand, "Invalid operand");
    435                 break;
    436             // case Constants.NEWARRAY:
    437             default:
    438                 if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
    439                     throw new IllegalArgumentException("Invalid operand (must be an array type code T_...): "
    440                             + operand);
    441                 }
    442         }
    443         mv.visitIntInsn(opcode, operand);
    444     }
    445 
    446     public void visitVarInsn(final int opcode, final int var) {
    447         checkStartCode();
    448         checkEndCode();
    449         checkOpcode(opcode, 2);
    450         checkUnsignedShort(var, "Invalid variable index");
    451         mv.visitVarInsn(opcode, var);
    452     }
    453 
    454     public void visitTypeInsn(final int opcode, final String type) {
    455         checkStartCode();
    456         checkEndCode();
    457         checkOpcode(opcode, 3);
    458         checkInternalName(type, "type");
    459         if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
    460             throw new IllegalArgumentException("NEW cannot be used to create arrays: "
    461                     + type);
    462         }
    463         mv.visitTypeInsn(opcode, type);
    464     }
    465 
    466     public void visitFieldInsn(
    467         final int opcode,
    468         final String owner,
    469         final String name,
    470         final String desc)
    471     {
    472         checkStartCode();
    473         checkEndCode();
    474         checkOpcode(opcode, 4);
    475         checkInternalName(owner, "owner");
    476         checkIdentifier(name, "name");
    477         checkDesc(desc, false);
    478         mv.visitFieldInsn(opcode, owner, name, desc);
    479     }
    480 
    481     public void visitMethodInsn(
    482         final int opcode,
    483         final String owner,
    484         final String name,
    485         final String desc)
    486     {
    487         checkStartCode();
    488         checkEndCode();
    489         checkOpcode(opcode, 5);
    490         checkMethodIdentifier(name, "name");
    491         checkInternalName(owner, "owner");
    492         checkMethodDesc(desc);
    493         mv.visitMethodInsn(opcode, owner, name, desc);
    494     }
    495 
    496     public void visitJumpInsn(final int opcode, final Label label) {
    497         checkStartCode();
    498         checkEndCode();
    499         checkOpcode(opcode, 6);
    500         checkLabel(label, false, "label");
    501         mv.visitJumpInsn(opcode, label);
    502     }
    503 
    504     public void visitLabel(final Label label) {
    505         checkStartCode();
    506         checkEndCode();
    507         checkLabel(label, false, "label");
    508         if (labels.get(label) != null) {
    509             throw new IllegalArgumentException("Already visited label");
    510         }
    511         labels.put(label, new Integer(labels.size()));
    512         mv.visitLabel(label);
    513     }
    514 
    515     public void visitLdcInsn(final Object cst) {
    516         checkStartCode();
    517         checkEndCode();
    518         if (!(cst instanceof Type)) {
    519             checkConstant(cst);
    520         }
    521         mv.visitLdcInsn(cst);
    522     }
    523 
    524     public void visitIincInsn(final int var, final int increment) {
    525         checkStartCode();
    526         checkEndCode();
    527         checkUnsignedShort(var, "Invalid variable index");
    528         checkSignedShort(increment, "Invalid increment");
    529         mv.visitIincInsn(var, increment);
    530     }
    531 
    532     public void visitTableSwitchInsn(
    533         final int min,
    534         final int max,
    535         final Label dflt,
    536         final Label[] labels)
    537     {
    538         checkStartCode();
    539         checkEndCode();
    540         if (max < min) {
    541             throw new IllegalArgumentException("Max = " + max
    542                     + " must be greater than or equal to min = " + min);
    543         }
    544         checkLabel(dflt, false, "default label");
    545         if (labels == null || labels.length != max - min + 1) {
    546             throw new IllegalArgumentException("There must be max - min + 1 labels");
    547         }
    548         for (int i = 0; i < labels.length; ++i) {
    549             checkLabel(labels[i], false, "label at index " + i);
    550         }
    551         mv.visitTableSwitchInsn(min, max, dflt, labels);
    552     }
    553 
    554     public void visitLookupSwitchInsn(
    555         final Label dflt,
    556         final int[] keys,
    557         final Label[] labels)
    558     {
    559         checkEndCode();
    560         checkStartCode();
    561         checkLabel(dflt, false, "default label");
    562         if (keys == null || labels == null || keys.length != labels.length) {
    563             throw new IllegalArgumentException("There must be the same number of keys and labels");
    564         }
    565         for (int i = 0; i < labels.length; ++i) {
    566             checkLabel(labels[i], false, "label at index " + i);
    567         }
    568         mv.visitLookupSwitchInsn(dflt, keys, labels);
    569     }
    570 
    571     public void visitMultiANewArrayInsn(final String desc, final int dims) {
    572         checkStartCode();
    573         checkEndCode();
    574         checkDesc(desc, false);
    575         if (desc.charAt(0) != '[') {
    576             throw new IllegalArgumentException("Invalid descriptor (must be an array type descriptor): "
    577                     + desc);
    578         }
    579         if (dims < 1) {
    580             throw new IllegalArgumentException("Invalid dimensions (must be greater than 0): "
    581                     + dims);
    582         }
    583         if (dims > desc.lastIndexOf('[') + 1) {
    584             throw new IllegalArgumentException("Invalid dimensions (must not be greater than dims(desc)): "
    585                     + dims);
    586         }
    587         mv.visitMultiANewArrayInsn(desc, dims);
    588     }
    589 
    590     public void visitTryCatchBlock(
    591         final Label start,
    592         final Label end,
    593         final Label handler,
    594         final String type)
    595     {
    596         checkStartCode();
    597         checkEndCode();
    598         if (type != null) {
    599             checkInternalName(type, "type");
    600         }
    601         mv.visitTryCatchBlock(start, end, handler, type);
    602     }
    603 
    604     public void visitLocalVariable(
    605         final String name,
    606         final String desc,
    607         final String signature,
    608         final Label start,
    609         final Label end,
    610         final int index)
    611     {
    612         checkStartCode();
    613         checkEndCode();
    614         checkIdentifier(name, "name");
    615         checkDesc(desc, false);
    616         checkLabel(start, true, "start label");
    617         checkLabel(end, true, "end label");
    618         checkUnsignedShort(index, "Invalid variable index");
    619         int s = ((Integer) labels.get(start)).intValue();
    620         int e = ((Integer) labels.get(end)).intValue();
    621         if (e < s) {
    622             throw new IllegalArgumentException("Invalid start and end labels (end must be greater than start)");
    623         }
    624         mv.visitLocalVariable(name, desc, signature, start, end, index);
    625     }
    626 
    627     public void visitLineNumber(final int line, final Label start) {
    628         checkStartCode();
    629         checkEndCode();
    630         checkUnsignedShort(line, "Invalid line number");
    631         checkLabel(start, true, "start label");
    632         mv.visitLineNumber(line, start);
    633     }
    634 
    635     public void visitMaxs(final int maxStack, final int maxLocals) {
    636         checkStartCode();
    637         checkEndCode();
    638         endCode = true;
    639         checkUnsignedShort(maxStack, "Invalid max stack");
    640         checkUnsignedShort(maxLocals, "Invalid max locals");
    641         mv.visitMaxs(maxStack, maxLocals);
    642     }
    643 
    644     public void visitEnd() {
    645         checkEndMethod();
    646         endMethod = true;
    647         mv.visitEnd();
    648     }
    649 
    650     // -------------------------------------------------------------------------
    651 
    652     /**
    653      * Checks that the visitCode method has been called.
    654      */
    655     void checkStartCode() {
    656         if (!startCode) {
    657             throw new IllegalStateException("Cannot visit instructions before visitCode has been called.");
    658         }
    659     }
    660 
    661     /**
    662      * Checks that the visitMaxs method has not been called.
    663      */
    664     void checkEndCode() {
    665         if (endCode) {
    666             throw new IllegalStateException("Cannot visit instructions after visitMaxs has been called.");
    667         }
    668     }
    669 
    670     /**
    671      * Checks that the visitEnd method has not been called.
    672      */
    673     void checkEndMethod() {
    674         if (endMethod) {
    675             throw new IllegalStateException("Cannot visit elements after visitEnd has been called.");
    676         }
    677     }
    678 
    679     /**
    680      * Checks a stack frame value.
    681      *
    682      * @param value the value to be checked.
    683      */
    684     static void checkFrameValue(final Object value) {
    685         if (value == Opcodes.TOP || value == Opcodes.INTEGER
    686                 || value == Opcodes.FLOAT || value == Opcodes.LONG
    687                 || value == Opcodes.DOUBLE || value == Opcodes.NULL
    688                 || value == Opcodes.UNINITIALIZED_THIS)
    689         {
    690             return;
    691         }
    692         if (value instanceof String) {
    693             checkInternalName((String) value, "Invalid stack frame value");
    694             return;
    695         }
    696         if (!(value instanceof Label)) {
    697             throw new IllegalArgumentException("Invalid stack frame value: "
    698                     + value);
    699         }
    700     }
    701 
    702     /**
    703      * Checks that the type of the given opcode is equal to the given type.
    704      *
    705      * @param opcode the opcode to be checked.
    706      * @param type the expected opcode type.
    707      */
    708     static void checkOpcode(final int opcode, final int type) {
    709         if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
    710             throw new IllegalArgumentException("Invalid opcode: " + opcode);
    711         }
    712     }
    713 
    714     /**
    715      * Checks that the given value is a signed byte.
    716      *
    717      * @param value the value to be checked.
    718      * @param msg an message to be used in case of error.
    719      */
    720     static void checkSignedByte(final int value, final String msg) {
    721         if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
    722             throw new IllegalArgumentException(msg
    723                     + " (must be a signed byte): " + value);
    724         }
    725     }
    726 
    727     /**
    728      * Checks that the given value is a signed short.
    729      *
    730      * @param value the value to be checked.
    731      * @param msg an message to be used in case of error.
    732      */
    733     static void checkSignedShort(final int value, final String msg) {
    734         if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
    735             throw new IllegalArgumentException(msg
    736                     + " (must be a signed short): " + value);
    737         }
    738     }
    739 
    740     /**
    741      * Checks that the given value is an unsigned short.
    742      *
    743      * @param value the value to be checked.
    744      * @param msg an message to be used in case of error.
    745      */
    746     static void checkUnsignedShort(final int value, final String msg) {
    747         if (value < 0 || value > 65535) {
    748             throw new IllegalArgumentException(msg
    749                     + " (must be an unsigned short): " + value);
    750         }
    751     }
    752 
    753     /**
    754      * Checks that the given value is an {@link Integer}, a{@link Float}, a
    755      * {@link Long}, a {@link Double} or a {@link String}.
    756      *
    757      * @param cst the value to be checked.
    758      */
    759     static void checkConstant(final Object cst) {
    760         if (!(cst instanceof Integer) && !(cst instanceof Float)
    761                 && !(cst instanceof Long) && !(cst instanceof Double)
    762                 && !(cst instanceof String))
    763         {
    764             throw new IllegalArgumentException("Invalid constant: " + cst);
    765         }
    766     }
    767 
    768     /**
    769      * Checks that the given string is a valid Java identifier.
    770      *
    771      * @param name the string to be checked.
    772      * @param msg a message to be used in case of error.
    773      */
    774     static void checkIdentifier(final String name, final String msg) {
    775         checkIdentifier(name, 0, -1, msg);
    776     }
    777 
    778     /**
    779      * Checks that the given substring is a valid Java identifier.
    780      *
    781      * @param name the string to be checked.
    782      * @param start index of the first character of the identifier (inclusive).
    783      * @param end index of the last character of the identifier (exclusive). -1
    784      *        is equivalent to <tt>name.length()</tt> if name is not
    785      *        <tt>null</tt>.
    786      * @param msg a message to be used in case of error.
    787      */
    788     static void checkIdentifier(
    789         final String name,
    790         final int start,
    791         final int end,
    792         final String msg)
    793     {
    794         if (name == null || (end == -1 ? name.length() <= start : end <= start))
    795         {
    796             throw new IllegalArgumentException("Invalid " + msg
    797                     + " (must not be null or empty)");
    798         }
    799         if (!Character.isJavaIdentifierStart(name.charAt(start))) {
    800             throw new IllegalArgumentException("Invalid " + msg
    801                     + " (must be a valid Java identifier): " + name);
    802         }
    803         int max = end == -1 ? name.length() : end;
    804         for (int i = start + 1; i < max; ++i) {
    805             if (!Character.isJavaIdentifierPart(name.charAt(i))) {
    806                 throw new IllegalArgumentException("Invalid " + msg
    807                         + " (must be a valid Java identifier): " + name);
    808             }
    809         }
    810     }
    811 
    812     /**
    813      * Checks that the given string is a valid Java identifier or is equal to
    814      * '&lt;init&gt;' or '&lt;clinit&gt;'.
    815      *
    816      * @param name the string to be checked.
    817      * @param msg a message to be used in case of error.
    818      */
    819     static void checkMethodIdentifier(final String name, final String msg) {
    820         if (name == null || name.length() == 0) {
    821             throw new IllegalArgumentException("Invalid " + msg
    822                     + " (must not be null or empty)");
    823         }
    824         if ("<init>".equals(name) || "<clinit>".equals(name)) {
    825             return;
    826         }
    827         if (!Character.isJavaIdentifierStart(name.charAt(0))) {
    828             throw new IllegalArgumentException("Invalid "
    829                     + msg
    830                     + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
    831                     + name);
    832         }
    833         for (int i = 1; i < name.length(); ++i) {
    834             if (!Character.isJavaIdentifierPart(name.charAt(i))) {
    835                 throw new IllegalArgumentException("Invalid "
    836                         + msg
    837                         + " (must be '<init>' or '<clinit>' or a valid Java identifier): "
    838                         + name);
    839             }
    840         }
    841     }
    842 
    843     /**
    844      * Checks that the given string is a valid internal class name.
    845      *
    846      * @param name the string to be checked.
    847      * @param msg a message to be used in case of error.
    848      */
    849     static void checkInternalName(final String name, final String msg) {
    850         if (name == null || name.length() == 0) {
    851             throw new IllegalArgumentException("Invalid " + msg
    852                     + " (must not be null or empty)");
    853         }
    854         if (name.charAt(0) == '[') {
    855             checkDesc(name, false);
    856         } else {
    857             checkInternalName(name, 0, -1, msg);
    858         }
    859     }
    860 
    861     /**
    862      * Checks that the given substring is a valid internal class name.
    863      *
    864      * @param name the string to be checked.
    865      * @param start index of the first character of the identifier (inclusive).
    866      * @param end index of the last character of the identifier (exclusive). -1
    867      *        is equivalent to <tt>name.length()</tt> if name is not
    868      *        <tt>null</tt>.
    869      * @param msg a message to be used in case of error.
    870      */
    871     static void checkInternalName(
    872         final String name,
    873         final int start,
    874         final int end,
    875         final String msg)
    876     {
    877         int max = end == -1 ? name.length() : end;
    878         try {
    879             int begin = start;
    880             int slash;
    881             do {
    882                 slash = name.indexOf('/', begin + 1);
    883                 if (slash == -1 || slash > max) {
    884                     slash = max;
    885                 }
    886                 checkIdentifier(name, begin, slash, null);
    887                 begin = slash + 1;
    888             } while (slash != max);
    889         } catch (IllegalArgumentException _) {
    890             throw new IllegalArgumentException("Invalid "
    891                     + msg
    892                     + " (must be a fully qualified class name in internal form): "
    893                     + name);
    894         }
    895     }
    896 
    897     /**
    898      * Checks that the given string is a valid type descriptor.
    899      *
    900      * @param desc the string to be checked.
    901      * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
    902      */
    903     static void checkDesc(final String desc, final boolean canBeVoid) {
    904         int end = checkDesc(desc, 0, canBeVoid);
    905         if (end != desc.length()) {
    906             throw new IllegalArgumentException("Invalid descriptor: " + desc);
    907         }
    908     }
    909 
    910     /**
    911      * Checks that a the given substring is a valid type descriptor.
    912      *
    913      * @param desc the string to be checked.
    914      * @param start index of the first character of the identifier (inclusive).
    915      * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
    916      * @return the index of the last character of the type decriptor, plus one.
    917      */
    918     static int checkDesc(
    919         final String desc,
    920         final int start,
    921         final boolean canBeVoid)
    922     {
    923         if (desc == null || start >= desc.length()) {
    924             throw new IllegalArgumentException("Invalid type descriptor (must not be null or empty)");
    925         }
    926         int index;
    927         switch (desc.charAt(start)) {
    928             case 'V':
    929                 if (canBeVoid) {
    930                     return start + 1;
    931                 } else {
    932                     throw new IllegalArgumentException("Invalid descriptor: "
    933                             + desc);
    934                 }
    935             case 'Z':
    936             case 'C':
    937             case 'B':
    938             case 'S':
    939             case 'I':
    940             case 'F':
    941             case 'J':
    942             case 'D':
    943                 return start + 1;
    944             case '[':
    945                 index = start + 1;
    946                 while (index < desc.length() && desc.charAt(index) == '[') {
    947                     ++index;
    948                 }
    949                 if (index < desc.length()) {
    950                     return checkDesc(desc, index, false);
    951                 } else {
    952                     throw new IllegalArgumentException("Invalid descriptor: "
    953                             + desc);
    954                 }
    955             case 'L':
    956                 index = desc.indexOf(';', start);
    957                 if (index == -1 || index - start < 2) {
    958                     throw new IllegalArgumentException("Invalid descriptor: "
    959                             + desc);
    960                 }
    961                 try {
    962                     checkInternalName(desc, start + 1, index, null);
    963                 } catch (IllegalArgumentException _) {
    964                     throw new IllegalArgumentException("Invalid descriptor: "
    965                             + desc);
    966                 }
    967                 return index + 1;
    968             default:
    969                 throw new IllegalArgumentException("Invalid descriptor: "
    970                         + desc);
    971         }
    972     }
    973 
    974     /**
    975      * Checks that the given string is a valid method descriptor.
    976      *
    977      * @param desc the string to be checked.
    978      */
    979     static void checkMethodDesc(final String desc) {
    980         if (desc == null || desc.length() == 0) {
    981             throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)");
    982         }
    983         if (desc.charAt(0) != '(' || desc.length() < 3) {
    984             throw new IllegalArgumentException("Invalid descriptor: " + desc);
    985         }
    986         int start = 1;
    987         if (desc.charAt(start) != ')') {
    988             do {
    989                 if (desc.charAt(start) == 'V') {
    990                     throw new IllegalArgumentException("Invalid descriptor: "
    991                             + desc);
    992                 }
    993                 start = checkDesc(desc, start, false);
    994             } while (start < desc.length() && desc.charAt(start) != ')');
    995         }
    996         start = checkDesc(desc, start + 1, true);
    997         if (start != desc.length()) {
    998             throw new IllegalArgumentException("Invalid descriptor: " + desc);
    999         }
   1000     }
   1001 
   1002     /**
   1003      * Checks a class signature.
   1004      *
   1005      * @param signature a string containing the signature that must be checked.
   1006      */
   1007     static void checkClassSignature(final String signature) {
   1008         // ClassSignature:
   1009         // FormalTypeParameters? ClassTypeSignature ClassTypeSignature*
   1010 
   1011         int pos = 0;
   1012         if (getChar(signature, 0) == '<') {
   1013             pos = checkFormalTypeParameters(signature, pos);
   1014         }
   1015         pos = checkClassTypeSignature(signature, pos);
   1016         while (getChar(signature, pos) == 'L') {
   1017             pos = checkClassTypeSignature(signature, pos);
   1018         }
   1019         if (pos != signature.length()) {
   1020             throw new IllegalArgumentException(signature + ": error at index "
   1021                     + pos);
   1022         }
   1023     }
   1024 
   1025     /**
   1026      * Checks a method signature.
   1027      *
   1028      * @param signature a string containing the signature that must be checked.
   1029      */
   1030     static void checkMethodSignature(final String signature) {
   1031         // MethodTypeSignature:
   1032         // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) (
   1033         // ^ClassTypeSignature | ^TypeVariableSignature )*
   1034 
   1035         int pos = 0;
   1036         if (getChar(signature, 0) == '<') {
   1037             pos = checkFormalTypeParameters(signature, pos);
   1038         }
   1039         pos = checkChar('(', signature, pos);
   1040         while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) {
   1041             pos = checkTypeSignature(signature, pos);
   1042         }
   1043         pos = checkChar(')', signature, pos);
   1044         if (getChar(signature, pos) == 'V') {
   1045             ++pos;
   1046         } else {
   1047             pos = checkTypeSignature(signature, pos);
   1048         }
   1049         while (getChar(signature, pos) == '^') {
   1050             ++pos;
   1051             if (getChar(signature, pos) == 'L') {
   1052                 pos = checkClassTypeSignature(signature, pos);
   1053             } else {
   1054                 pos = checkTypeVariableSignature(signature, pos);
   1055             }
   1056         }
   1057         if (pos != signature.length()) {
   1058             throw new IllegalArgumentException(signature + ": error at index "
   1059                     + pos);
   1060         }
   1061     }
   1062 
   1063     /**
   1064      * Checks a field signature.
   1065      *
   1066      * @param signature a string containing the signature that must be checked.
   1067      */
   1068     static void checkFieldSignature(final String signature) {
   1069         int pos = checkFieldTypeSignature(signature, 0);
   1070         if (pos != signature.length()) {
   1071             throw new IllegalArgumentException(signature + ": error at index "
   1072                     + pos);
   1073         }
   1074     }
   1075 
   1076     /**
   1077      * Checks the formal type parameters of a class or method signature.
   1078      *
   1079      * @param signature a string containing the signature that must be checked.
   1080      * @param pos index of first character to be checked.
   1081      * @return the index of the first character after the checked part.
   1082      */
   1083     private static int checkFormalTypeParameters(final String signature, int pos)
   1084     {
   1085         // FormalTypeParameters:
   1086         // < FormalTypeParameter+ >
   1087 
   1088         pos = checkChar('<', signature, pos);
   1089         pos = checkFormalTypeParameter(signature, pos);
   1090         while (getChar(signature, pos) != '>') {
   1091             pos = checkFormalTypeParameter(signature, pos);
   1092         }
   1093         return pos + 1;
   1094     }
   1095 
   1096     /**
   1097      * Checks a formal type parameter of a class or method signature.
   1098      *
   1099      * @param signature a string containing the signature that must be checked.
   1100      * @param pos index of first character to be checked.
   1101      * @return the index of the first character after the checked part.
   1102      */
   1103     private static int checkFormalTypeParameter(final String signature, int pos)
   1104     {
   1105         // FormalTypeParameter:
   1106         // Identifier : FieldTypeSignature? (: FieldTypeSignature)*
   1107 
   1108         pos = checkIdentifier(signature, pos);
   1109         pos = checkChar(':', signature, pos);
   1110         if ("L[T".indexOf(getChar(signature, pos)) != -1) {
   1111             pos = checkFieldTypeSignature(signature, pos);
   1112         }
   1113         while (getChar(signature, pos) == ':') {
   1114             pos = checkFieldTypeSignature(signature, pos + 1);
   1115         }
   1116         return pos;
   1117     }
   1118 
   1119     /**
   1120      * Checks a field type signature.
   1121      *
   1122      * @param signature a string containing the signature that must be checked.
   1123      * @param pos index of first character to be checked.
   1124      * @return the index of the first character after the checked part.
   1125      */
   1126     private static int checkFieldTypeSignature(final String signature, int pos)
   1127     {
   1128         // FieldTypeSignature:
   1129         // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature
   1130         //
   1131         // ArrayTypeSignature:
   1132         // [ TypeSignature
   1133 
   1134         switch (getChar(signature, pos)) {
   1135             case 'L':
   1136                 return checkClassTypeSignature(signature, pos);
   1137             case '[':
   1138                 return checkTypeSignature(signature, pos + 1);
   1139             default:
   1140                 return checkTypeVariableSignature(signature, pos);
   1141         }
   1142     }
   1143 
   1144     /**
   1145      * Checks a class type signature.
   1146      *
   1147      * @param signature a string containing the signature that must be checked.
   1148      * @param pos index of first character to be checked.
   1149      * @return the index of the first character after the checked part.
   1150      */
   1151     private static int checkClassTypeSignature(final String signature, int pos)
   1152     {
   1153         // ClassTypeSignature:
   1154         // L Identifier ( / Identifier )* TypeArguments? ( . Identifier
   1155         // TypeArguments? )* ;
   1156 
   1157         pos = checkChar('L', signature, pos);
   1158         pos = checkIdentifier(signature, pos);
   1159         while (getChar(signature, pos) == '/') {
   1160             pos = checkIdentifier(signature, pos + 1);
   1161         }
   1162         if (getChar(signature, pos) == '<') {
   1163             pos = checkTypeArguments(signature, pos);
   1164         }
   1165         while (getChar(signature, pos) == '.') {
   1166             pos = checkIdentifier(signature, pos + 1);
   1167             if (getChar(signature, pos) == '<') {
   1168                 pos = checkTypeArguments(signature, pos);
   1169             }
   1170         }
   1171         return checkChar(';', signature, pos);
   1172     }
   1173 
   1174     /**
   1175      * Checks the type arguments in a class type signature.
   1176      *
   1177      * @param signature a string containing the signature that must be checked.
   1178      * @param pos index of first character to be checked.
   1179      * @return the index of the first character after the checked part.
   1180      */
   1181     private static int checkTypeArguments(final String signature, int pos) {
   1182         // TypeArguments:
   1183         // < TypeArgument+ >
   1184 
   1185         pos = checkChar('<', signature, pos);
   1186         pos = checkTypeArgument(signature, pos);
   1187         while (getChar(signature, pos) != '>') {
   1188             pos = checkTypeArgument(signature, pos);
   1189         }
   1190         return pos + 1;
   1191     }
   1192 
   1193     /**
   1194      * Checks a type argument in a class type signature.
   1195      *
   1196      * @param signature a string containing the signature that must be checked.
   1197      * @param pos index of first character to be checked.
   1198      * @return the index of the first character after the checked part.
   1199      */
   1200     private static int checkTypeArgument(final String signature, int pos) {
   1201         // TypeArgument:
   1202         // * | ( ( + | - )? FieldTypeSignature )
   1203 
   1204         char c = getChar(signature, pos);
   1205         if (c == '*') {
   1206             return pos + 1;
   1207         } else if (c == '+' || c == '-') {
   1208             pos++;
   1209         }
   1210         return checkFieldTypeSignature(signature, pos);
   1211     }
   1212 
   1213     /**
   1214      * Checks a type variable signature.
   1215      *
   1216      * @param signature a string containing the signature that must be checked.
   1217      * @param pos index of first character to be checked.
   1218      * @return the index of the first character after the checked part.
   1219      */
   1220     private static int checkTypeVariableSignature(
   1221         final String signature,
   1222         int pos)
   1223     {
   1224         // TypeVariableSignature:
   1225         // T Identifier ;
   1226 
   1227         pos = checkChar('T', signature, pos);
   1228         pos = checkIdentifier(signature, pos);
   1229         return checkChar(';', signature, pos);
   1230     }
   1231 
   1232     /**
   1233      * Checks a type signature.
   1234      *
   1235      * @param signature a string containing the signature that must be checked.
   1236      * @param pos index of first character to be checked.
   1237      * @return the index of the first character after the checked part.
   1238      */
   1239     private static int checkTypeSignature(final String signature, int pos) {
   1240         // TypeSignature:
   1241         // Z | C | B | S | I | F | J | D | FieldTypeSignature
   1242 
   1243         switch (getChar(signature, pos)) {
   1244             case 'Z':
   1245             case 'C':
   1246             case 'B':
   1247             case 'S':
   1248             case 'I':
   1249             case 'F':
   1250             case 'J':
   1251             case 'D':
   1252                 return pos + 1;
   1253             default:
   1254                 return checkFieldTypeSignature(signature, pos);
   1255         }
   1256     }
   1257 
   1258     /**
   1259      * Checks an identifier.
   1260      *
   1261      * @param signature a string containing the signature that must be checked.
   1262      * @param pos index of first character to be checked.
   1263      * @return the index of the first character after the checked part.
   1264      */
   1265     private static int checkIdentifier(final String signature, int pos) {
   1266         if (!Character.isJavaIdentifierStart(getChar(signature, pos))) {
   1267             throw new IllegalArgumentException(signature
   1268                     + ": identifier expected at index " + pos);
   1269         }
   1270         ++pos;
   1271         while (Character.isJavaIdentifierPart(getChar(signature, pos))) {
   1272             ++pos;
   1273         }
   1274         return pos;
   1275     }
   1276 
   1277     /**
   1278      * Checks a single character.
   1279      *
   1280      * @param signature a string containing the signature that must be checked.
   1281      * @param pos index of first character to be checked.
   1282      * @return the index of the first character after the checked part.
   1283      */
   1284     private static int checkChar(final char c, final String signature, int pos)
   1285     {
   1286         if (getChar(signature, pos) == c) {
   1287             return pos + 1;
   1288         }
   1289         throw new IllegalArgumentException(signature + ": '" + c
   1290                 + "' expected at index " + pos);
   1291     }
   1292 
   1293     /**
   1294      * Returns the signature car at the given index.
   1295      *
   1296      * @param signature a signature.
   1297      * @param pos an index in signature.
   1298      * @return the character at the given index, or 0 if there is no such
   1299      *         character.
   1300      */
   1301     private static char getChar(final String signature, int pos) {
   1302         return pos < signature.length() ? signature.charAt(pos) : (char) 0;
   1303     }
   1304 
   1305     /**
   1306      * Checks that the given label is not null. This method can also check that
   1307      * the label has been visited.
   1308      *
   1309      * @param label the label to be checked.
   1310      * @param checkVisited <tt>true</tt> to check that the label has been
   1311      *        visited.
   1312      * @param msg a message to be used in case of error.
   1313      */
   1314     void checkLabel(
   1315         final Label label,
   1316         final boolean checkVisited,
   1317         final String msg)
   1318     {
   1319         if (label == null) {
   1320             throw new IllegalArgumentException("Invalid " + msg
   1321                     + " (must not be null)");
   1322         }
   1323         if (checkVisited && labels.get(label) == null) {
   1324             throw new IllegalArgumentException("Invalid " + msg
   1325                     + " (must be visited first)");
   1326         }
   1327     }
   1328 }
   1329