You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2018/11/29 00:33:56 UTC

[09/46] tapestry-5 git commit: TAP5-2588: upgrading from ASM 6 to 7 for Java 9+ support

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
old mode 100644
new mode 100755
index 931a73d..e355c78
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
@@ -1,46 +1,43 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
 package org.apache.tapestry5.internal.plastic.asm.util;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
@@ -50,1503 +47,1420 @@ import org.apache.tapestry5.internal.plastic.asm.TypePath;
 import org.apache.tapestry5.internal.plastic.asm.TypeReference;
 import org.apache.tapestry5.internal.plastic.asm.tree.MethodNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.analysis.Analyzer;
+import org.apache.tapestry5.internal.plastic.asm.tree.analysis.AnalyzerException;
 import org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicValue;
 import org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicVerifier;
 
 /**
- * A {@link MethodVisitor} that checks that its methods are properly used. More
- * precisely this method adapter checks each instruction individually, i.e.,
- * each visit method checks some preconditions based <i>only</i> on its
- * arguments - such as the fact that the given opcode is correct for a given
- * visit method. This adapter can also perform some basic data flow checks (more
- * precisely those that can be performed without the full class hierarchy - see
- * {@link org.objectweb.asm.tree.analysis.BasicVerifier}). For instance in a
- * method whose signature is <tt>void m ()</tt>, the invalid instruction
- * IRETURN, or the invalid sequence IADD L2I will be detected if the data flow
- * checks are enabled. These checks are enabled by using the
- * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor.
- * They are not performed if any other constructor is used.
- * 
+ * A {@link MethodVisitor} that checks that its methods are properly used. More precisely this
+ * method adapter checks each instruction individually, i.e., each visit method checks some
+ * preconditions based <i>only</i> on its arguments - such as the fact that the given opcode is
+ * correct for a given visit method. This adapter can also perform some basic data flow checks (more
+ * precisely those that can be performed without the full class hierarchy - see {@link
+ * org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicVerifier}). For instance in a method whose signature is
+ * {@code void m ()}, the invalid instruction IRETURN, or the invalid sequence IADD L2I will be
+ * detected if the data flow checks are enabled. These checks are enabled by using the {@link
+ * #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor. They are not performed if
+ * any other constructor is used.
+ *
  * @author Eric Bruneton
  */
 public class CheckMethodAdapter extends MethodVisitor {
 
-    /**
-     * The class version number.
-     */
-    public int version;
-
-    /**
-     * The access flags of the method.
-     */
-    private int access;
-
-    /**
-     * <tt>true</tt> if the visitCode method has been called.
-     */
-    private boolean startCode;
-
-    /**
-     * <tt>true</tt> if the visitMaxs method has been called.
-     */
-    private boolean endCode;
-
-    /**
-     * <tt>true</tt> if the visitEnd method has been called.
-     */
-    private boolean endMethod;
-
-    /**
-     * Number of visited instructions.
-     */
-    private int insnCount;
-
-    /**
-     * The already visited labels. This map associate Integer values to pseudo
-     * code offsets.
-     */
-    private final Map<Label, Integer> labels;
-
-    /**
-     * The labels used in this method. Every used label must be visited with
-     * visitLabel before the end of the method (i.e. should be in #labels).
-     */
-    private Set<Label> usedLabels;
-
-    /**
-     * Number of visited frames in expanded form.
-     */
-    private int expandedFrames;
-
-    /**
-     * Number of visited frames in compressed form.
-     */
-    private int compressedFrames;
-
-    /**
-     * Number of instructions before the last visited frame.
-     */
-    private int lastFrame = -1;
-
-    /**
-     * The exception handler ranges. Each pair of list element contains the
-     * start and end labels of an exception handler block.
-     */
-    private List<Label> handlers;
-
-    /**
-     * Code of the visit method to be used for each opcode.
-     */
-    private static final int[] TYPE;
-
-    /**
-     * The Label.status field.
-     */
-    private static Field labelStatusField;
-
-    static {
-        String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD"
-                + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
-                + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD"
-                + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA";
-        TYPE = new int[s.length()];
-        for (int i = 0; i < TYPE.length; ++i) {
-            TYPE[i] = s.charAt(i) - 'A' - 1;
-        }
+  /** The 'generic' instruction visit methods (i.e. those that take an opcode argument). */
+  private enum Method {
+    VISIT_INSN,
+    VISIT_INT_INSN,
+    VISIT_VAR_INSN,
+    VISIT_TYPE_INSN,
+    VISIT_FIELD_INSN,
+    VISIT_METHOD_INSN,
+    VISIT_JUMP_INSN
+  }
+
+  /** The method to use to visit each instruction. Only generic methods are represented here. */
+  private static final Method[] OPCODE_METHODS = {
+    Method.VISIT_INSN, // NOP
+    Method.VISIT_INSN, // ACONST_NULL
+    Method.VISIT_INSN, // ICONST_M1
+    Method.VISIT_INSN, // ICONST_0
+    Method.VISIT_INSN, // ICONST_1
+    Method.VISIT_INSN, // ICONST_2
+    Method.VISIT_INSN, // ICONST_3
+    Method.VISIT_INSN, // ICONST_4
+    Method.VISIT_INSN, // ICONST_5
+    Method.VISIT_INSN, // LCONST_0
+    Method.VISIT_INSN, // LCONST_1
+    Method.VISIT_INSN, // FCONST_0
+    Method.VISIT_INSN, // FCONST_1
+    Method.VISIT_INSN, // FCONST_2
+    Method.VISIT_INSN, // DCONST_0
+    Method.VISIT_INSN, // DCONST_1
+    Method.VISIT_INT_INSN, // BIPUSH
+    Method.VISIT_INT_INSN, // SIPUSH
+    null, // LDC
+    null, // LDC_W
+    null, // LDC2_W
+    Method.VISIT_VAR_INSN, // ILOAD
+    Method.VISIT_VAR_INSN, // LLOAD
+    Method.VISIT_VAR_INSN, // FLOAD
+    Method.VISIT_VAR_INSN, // DLOAD
+    Method.VISIT_VAR_INSN, // ALOAD
+    null, // ILOAD_0
+    null, // ILOAD_1
+    null, // ILOAD_2
+    null, // ILOAD_3
+    null, // LLOAD_0
+    null, // LLOAD_1
+    null, // LLOAD_2
+    null, // LLOAD_3
+    null, // FLOAD_0
+    null, // FLOAD_1
+    null, // FLOAD_2
+    null, // FLOAD_3
+    null, // DLOAD_0
+    null, // DLOAD_1
+    null, // DLOAD_2
+    null, // DLOAD_3
+    null, // ALOAD_0
+    null, // ALOAD_1
+    null, // ALOAD_2
+    null, // ALOAD_3
+    Method.VISIT_INSN, // IALOAD
+    Method.VISIT_INSN, // LALOAD
+    Method.VISIT_INSN, // FALOAD
+    Method.VISIT_INSN, // DALOAD
+    Method.VISIT_INSN, // AALOAD
+    Method.VISIT_INSN, // BALOAD
+    Method.VISIT_INSN, // CALOAD
+    Method.VISIT_INSN, // SALOAD
+    Method.VISIT_VAR_INSN, // ISTORE
+    Method.VISIT_VAR_INSN, // LSTORE
+    Method.VISIT_VAR_INSN, // FSTORE
+    Method.VISIT_VAR_INSN, // DSTORE
+    Method.VISIT_VAR_INSN, // ASTORE
+    null, // ISTORE_0
+    null, // ISTORE_1
+    null, // ISTORE_2
+    null, // ISTORE_3
+    null, // LSTORE_0
+    null, // LSTORE_1
+    null, // LSTORE_2
+    null, // LSTORE_3
+    null, // FSTORE_0
+    null, // FSTORE_1
+    null, // FSTORE_2
+    null, // FSTORE_3
+    null, // DSTORE_0
+    null, // DSTORE_1
+    null, // DSTORE_2
+    null, // DSTORE_3
+    null, // ASTORE_0
+    null, // ASTORE_1
+    null, // ASTORE_2
+    null, // ASTORE_3
+    Method.VISIT_INSN, // IASTORE
+    Method.VISIT_INSN, // LASTORE
+    Method.VISIT_INSN, // FASTORE
+    Method.VISIT_INSN, // DASTORE
+    Method.VISIT_INSN, // AASTORE
+    Method.VISIT_INSN, // BASTORE
+    Method.VISIT_INSN, // CASTORE
+    Method.VISIT_INSN, // SASTORE
+    Method.VISIT_INSN, // POP
+    Method.VISIT_INSN, // POP2
+    Method.VISIT_INSN, // DUP
+    Method.VISIT_INSN, // DUP_X1
+    Method.VISIT_INSN, // DUP_X2
+    Method.VISIT_INSN, // DUP2
+    Method.VISIT_INSN, // DUP2_X1
+    Method.VISIT_INSN, // DUP2_X2
+    Method.VISIT_INSN, // SWAP
+    Method.VISIT_INSN, // IADD
+    Method.VISIT_INSN, // LADD
+    Method.VISIT_INSN, // FADD
+    Method.VISIT_INSN, // DADD
+    Method.VISIT_INSN, // ISUB
+    Method.VISIT_INSN, // LSUB
+    Method.VISIT_INSN, // FSUB
+    Method.VISIT_INSN, // DSUB
+    Method.VISIT_INSN, // IMUL
+    Method.VISIT_INSN, // LMUL
+    Method.VISIT_INSN, // FMUL
+    Method.VISIT_INSN, // DMUL
+    Method.VISIT_INSN, // IDIV
+    Method.VISIT_INSN, // LDIV
+    Method.VISIT_INSN, // FDIV
+    Method.VISIT_INSN, // DDIV
+    Method.VISIT_INSN, // IREM
+    Method.VISIT_INSN, // LREM
+    Method.VISIT_INSN, // FREM
+    Method.VISIT_INSN, // DREM
+    Method.VISIT_INSN, // INEG
+    Method.VISIT_INSN, // LNEG
+    Method.VISIT_INSN, // FNEG
+    Method.VISIT_INSN, // DNEG
+    Method.VISIT_INSN, // ISHL
+    Method.VISIT_INSN, // LSHL
+    Method.VISIT_INSN, // ISHR
+    Method.VISIT_INSN, // LSHR
+    Method.VISIT_INSN, // IUSHR
+    Method.VISIT_INSN, // LUSHR
+    Method.VISIT_INSN, // IAND
+    Method.VISIT_INSN, // LAND
+    Method.VISIT_INSN, // IOR
+    Method.VISIT_INSN, // LOR
+    Method.VISIT_INSN, // IXOR
+    Method.VISIT_INSN, // LXOR
+    null, // IINC
+    Method.VISIT_INSN, // I2L
+    Method.VISIT_INSN, // I2F
+    Method.VISIT_INSN, // I2D
+    Method.VISIT_INSN, // L2I
+    Method.VISIT_INSN, // L2F
+    Method.VISIT_INSN, // L2D
+    Method.VISIT_INSN, // F2I
+    Method.VISIT_INSN, // F2L
+    Method.VISIT_INSN, // F2D
+    Method.VISIT_INSN, // D2I
+    Method.VISIT_INSN, // D2L
+    Method.VISIT_INSN, // D2F
+    Method.VISIT_INSN, // I2B
+    Method.VISIT_INSN, // I2C
+    Method.VISIT_INSN, // I2S
+    Method.VISIT_INSN, // LCMP
+    Method.VISIT_INSN, // FCMPL
+    Method.VISIT_INSN, // FCMPG
+    Method.VISIT_INSN, // DCMPL
+    Method.VISIT_INSN, // DCMPG
+    Method.VISIT_JUMP_INSN, // IFEQ
+    Method.VISIT_JUMP_INSN, // IFNE
+    Method.VISIT_JUMP_INSN, // IFLT
+    Method.VISIT_JUMP_INSN, // IFGE
+    Method.VISIT_JUMP_INSN, // IFGT
+    Method.VISIT_JUMP_INSN, // IFLE
+    Method.VISIT_JUMP_INSN, // IF_ICMPEQ
+    Method.VISIT_JUMP_INSN, // IF_ICMPNE
+    Method.VISIT_JUMP_INSN, // IF_ICMPLT
+    Method.VISIT_JUMP_INSN, // IF_ICMPGE
+    Method.VISIT_JUMP_INSN, // IF_ICMPGT
+    Method.VISIT_JUMP_INSN, // IF_ICMPLE
+    Method.VISIT_JUMP_INSN, // IF_ACMPEQ
+    Method.VISIT_JUMP_INSN, // IF_ACMPNE
+    Method.VISIT_JUMP_INSN, // GOTO
+    Method.VISIT_JUMP_INSN, // JSR
+    Method.VISIT_VAR_INSN, // RET
+    null, // TABLESWITCH
+    null, // LOOKUPSWITCH
+    Method.VISIT_INSN, // IRETURN
+    Method.VISIT_INSN, // LRETURN
+    Method.VISIT_INSN, // FRETURN
+    Method.VISIT_INSN, // DRETURN
+    Method.VISIT_INSN, // ARETURN
+    Method.VISIT_INSN, // RETURN
+    Method.VISIT_FIELD_INSN, // GETSTATIC
+    Method.VISIT_FIELD_INSN, // PUTSTATIC
+    Method.VISIT_FIELD_INSN, // GETFIELD
+    Method.VISIT_FIELD_INSN, // PUTFIELD
+    Method.VISIT_METHOD_INSN, // INVOKEVIRTUAL
+    Method.VISIT_METHOD_INSN, // INVOKESPECIAL
+    Method.VISIT_METHOD_INSN, // INVOKESTATIC
+    Method.VISIT_METHOD_INSN, // INVOKEINTERFACE
+    null, // INVOKEDYNAMIC
+    Method.VISIT_TYPE_INSN, // NEW
+    Method.VISIT_INT_INSN, // NEWARRAY
+    Method.VISIT_TYPE_INSN, // ANEWARRAY
+    Method.VISIT_INSN, // ARRAYLENGTH
+    Method.VISIT_INSN, // ATHROW
+    Method.VISIT_TYPE_INSN, // CHECKCAST
+    Method.VISIT_TYPE_INSN, // INSTANCEOF
+    Method.VISIT_INSN, // MONITORENTER
+    Method.VISIT_INSN, // MONITOREXIT
+    null, // WIDE
+    null, // MULTIANEWARRAY
+    Method.VISIT_JUMP_INSN, // IFNULL
+    Method.VISIT_JUMP_INSN // IFNONNULL
+  };
+
+  private static final String INVALID = "Invalid ";
+  private static final String INVALID_DESCRIPTOR = "Invalid descriptor: ";
+  private static final String INVALID_TYPE_REFERENCE = "Invalid type reference sort 0x";
+  private static final String INVALID_LOCAL_VARIABLE_INDEX = "Invalid local variable index";
+  private static final String MUST_NOT_BE_NULL_OR_EMPTY = " (must not be null or empty)";
+  private static final String START_LABEL = "start label";
+  private static final String END_LABEL = "end label";
+
+  /** The class version number. */
+  public int version;
+
+  /** The access flags of the visited method. */
+  private int access;
+
+  /**
+   * The number of method parameters that can have runtime visible annotations. 0 means that all the
+   * parameters from the method descriptor can have annotations.
+   */
+  private int visibleAnnotableParameterCount;
+
+  /**
+   * The number of method parameters that can have runtime invisible annotations. 0 means that all
+   * the parameters from the method descriptor can have annotations.
+   */
+  private int invisibleAnnotableParameterCount;
+
+  /** Whether the {@link #visitCode} method has been called. */
+  private boolean visitCodeCalled;
+
+  /** Whether the {@link #visitMaxs} method has been called. */
+  private boolean visitMaxCalled;
+
+  /** Whether the {@link #visitEnd} method has been called. */
+  private boolean visitEndCalled;
+
+  /** The number of visited instructions so far. */
+  private int insnCount;
+
+  /** The index of the instruction designated by each visited label. */
+  private final Map<Label, Integer> labelInsnIndices;
+
+  /** The labels referenced by the visited method. */
+  private Set<Label> referencedLabels;
+
+  /** The index of the instruction corresponding to the last visited stack map frame. */
+  private int lastFrameInsnIndex = -1;
+
+  /** The number of visited frames in expanded form. */
+  private int numExpandedFrames;
+
+  /** The number of visited frames in compressed form. */
+  private int numCompressedFrames;
+
+  /**
+   * The exception handler ranges. Each pair of list element contains the start and end labels of an
+   * exception handler block.
+   */
+  private List<Label> handlers;
+
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+   * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+   * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
+   * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
+   *
+   * @param methodvisitor the method visitor to which this adapter must delegate calls.
+   */
+  public CheckMethodAdapter(final MethodVisitor methodvisitor) {
+    this(methodvisitor, new HashMap<Label, Integer>());
+  }
+
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+   * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+   * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
+   * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
+   *
+   * @param methodVisitor the method visitor to which this adapter must delegate calls.
+   * @param labelInsnIndices the index of the instruction designated by each visited label so far
+   *     (in other methods). This map is updated with the labels from the visited method.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public CheckMethodAdapter(
+      final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) {
+    this(Opcodes.ASM7, methodVisitor, labelInsnIndices);
+    if (getClass() != CheckMethodAdapter.class) {
+      throw new IllegalStateException();
     }
-
-    // code to generate the above string
-    // public static void main (String[] args) {
-    // int[] TYPE = new int[] {
-    // 0, //NOP
-    // 0, //ACONST_NULL
-    // 0, //ICONST_M1
-    // 0, //ICONST_0
-    // 0, //ICONST_1
-    // 0, //ICONST_2
-    // 0, //ICONST_3
-    // 0, //ICONST_4
-    // 0, //ICONST_5
-    // 0, //LCONST_0
-    // 0, //LCONST_1
-    // 0, //FCONST_0
-    // 0, //FCONST_1
-    // 0, //FCONST_2
-    // 0, //DCONST_0
-    // 0, //DCONST_1
-    // 1, //BIPUSH
-    // 1, //SIPUSH
-    // 7, //LDC
-    // -1, //LDC_W
-    // -1, //LDC2_W
-    // 2, //ILOAD
-    // 2, //LLOAD
-    // 2, //FLOAD
-    // 2, //DLOAD
-    // 2, //ALOAD
-    // -1, //ILOAD_0
-    // -1, //ILOAD_1
-    // -1, //ILOAD_2
-    // -1, //ILOAD_3
-    // -1, //LLOAD_0
-    // -1, //LLOAD_1
-    // -1, //LLOAD_2
-    // -1, //LLOAD_3
-    // -1, //FLOAD_0
-    // -1, //FLOAD_1
-    // -1, //FLOAD_2
-    // -1, //FLOAD_3
-    // -1, //DLOAD_0
-    // -1, //DLOAD_1
-    // -1, //DLOAD_2
-    // -1, //DLOAD_3
-    // -1, //ALOAD_0
-    // -1, //ALOAD_1
-    // -1, //ALOAD_2
-    // -1, //ALOAD_3
-    // 0, //IALOAD
-    // 0, //LALOAD
-    // 0, //FALOAD
-    // 0, //DALOAD
-    // 0, //AALOAD
-    // 0, //BALOAD
-    // 0, //CALOAD
-    // 0, //SALOAD
-    // 2, //ISTORE
-    // 2, //LSTORE
-    // 2, //FSTORE
-    // 2, //DSTORE
-    // 2, //ASTORE
-    // -1, //ISTORE_0
-    // -1, //ISTORE_1
-    // -1, //ISTORE_2
-    // -1, //ISTORE_3
-    // -1, //LSTORE_0
-    // -1, //LSTORE_1
-    // -1, //LSTORE_2
-    // -1, //LSTORE_3
-    // -1, //FSTORE_0
-    // -1, //FSTORE_1
-    // -1, //FSTORE_2
-    // -1, //FSTORE_3
-    // -1, //DSTORE_0
-    // -1, //DSTORE_1
-    // -1, //DSTORE_2
-    // -1, //DSTORE_3
-    // -1, //ASTORE_0
-    // -1, //ASTORE_1
-    // -1, //ASTORE_2
-    // -1, //ASTORE_3
-    // 0, //IASTORE
-    // 0, //LASTORE
-    // 0, //FASTORE
-    // 0, //DASTORE
-    // 0, //AASTORE
-    // 0, //BASTORE
-    // 0, //CASTORE
-    // 0, //SASTORE
-    // 0, //POP
-    // 0, //POP2
-    // 0, //DUP
-    // 0, //DUP_X1
-    // 0, //DUP_X2
-    // 0, //DUP2
-    // 0, //DUP2_X1
-    // 0, //DUP2_X2
-    // 0, //SWAP
-    // 0, //IADD
-    // 0, //LADD
-    // 0, //FADD
-    // 0, //DADD
-    // 0, //ISUB
-    // 0, //LSUB
-    // 0, //FSUB
-    // 0, //DSUB
-    // 0, //IMUL
-    // 0, //LMUL
-    // 0, //FMUL
-    // 0, //DMUL
-    // 0, //IDIV
-    // 0, //LDIV
-    // 0, //FDIV
-    // 0, //DDIV
-    // 0, //IREM
-    // 0, //LREM
-    // 0, //FREM
-    // 0, //DREM
-    // 0, //INEG
-    // 0, //LNEG
-    // 0, //FNEG
-    // 0, //DNEG
-    // 0, //ISHL
-    // 0, //LSHL
-    // 0, //ISHR
-    // 0, //LSHR
-    // 0, //IUSHR
-    // 0, //LUSHR
-    // 0, //IAND
-    // 0, //LAND
-    // 0, //IOR
-    // 0, //LOR
-    // 0, //IXOR
-    // 0, //LXOR
-    // 8, //IINC
-    // 0, //I2L
-    // 0, //I2F
-    // 0, //I2D
-    // 0, //L2I
-    // 0, //L2F
-    // 0, //L2D
-    // 0, //F2I
-    // 0, //F2L
-    // 0, //F2D
-    // 0, //D2I
-    // 0, //D2L
-    // 0, //D2F
-    // 0, //I2B
-    // 0, //I2C
-    // 0, //I2S
-    // 0, //LCMP
-    // 0, //FCMPL
-    // 0, //FCMPG
-    // 0, //DCMPL
-    // 0, //DCMPG
-    // 6, //IFEQ
-    // 6, //IFNE
-    // 6, //IFLT
-    // 6, //IFGE
-    // 6, //IFGT
-    // 6, //IFLE
-    // 6, //IF_ICMPEQ
-    // 6, //IF_ICMPNE
-    // 6, //IF_ICMPLT
-    // 6, //IF_ICMPGE
-    // 6, //IF_ICMPGT
-    // 6, //IF_ICMPLE
-    // 6, //IF_ACMPEQ
-    // 6, //IF_ACMPNE
-    // 6, //GOTO
-    // 6, //JSR
-    // 2, //RET
-    // 9, //TABLESWITCH
-    // 10, //LOOKUPSWITCH
-    // 0, //IRETURN
-    // 0, //LRETURN
-    // 0, //FRETURN
-    // 0, //DRETURN
-    // 0, //ARETURN
-    // 0, //RETURN
-    // 4, //GETSTATIC
-    // 4, //PUTSTATIC
-    // 4, //GETFIELD
-    // 4, //PUTFIELD
-    // 5, //INVOKEVIRTUAL
-    // 5, //INVOKESPECIAL
-    // 5, //INVOKESTATIC
-    // 5, //INVOKEINTERFACE
-    // -1, //INVOKEDYNAMIC
-    // 3, //NEW
-    // 1, //NEWARRAY
-    // 3, //ANEWARRAY
-    // 0, //ARRAYLENGTH
-    // 0, //ATHROW
-    // 3, //CHECKCAST
-    // 3, //INSTANCEOF
-    // 0, //MONITORENTER
-    // 0, //MONITOREXIT
-    // -1, //WIDE
-    // 11, //MULTIANEWARRAY
-    // 6, //IFNULL
-    // 6, //IFNONNULL
-    // -1, //GOTO_W
-    // -1 //JSR_W
-    // };
-    // for (int i = 0; i < TYPE.length; ++i) {
-    // System.out.print((char)(TYPE[i] + 1 + 'A'));
-    // }
-    // System.out.println();
-    // }
-
-    /**
-     * Constructs a new {@link CheckMethodAdapter} object. This method adapter
-     * will not perform any data flow check (see
-     * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
-     * <i>Subclasses must not use this constructor</i>. Instead, they must use
-     * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version.
-     * 
-     * @param mv
-     *            the method visitor to which this adapter must delegate calls.
-     */
-    public CheckMethodAdapter(final MethodVisitor mv) {
-        this(mv, new HashMap<Label, Integer>());
-    }
-
-    /**
-     * Constructs a new {@link CheckMethodAdapter} object. This method adapter
-     * will not perform any data flow check (see
-     * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
-     * <i>Subclasses must not use this constructor</i>. Instead, they must use
-     * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version.
-     * 
-     * @param mv
-     *            the method visitor to which this adapter must delegate calls.
-     * @param labels
-     *            a map of already visited labels (in other methods).
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public CheckMethodAdapter(final MethodVisitor mv,
-            final Map<Label, Integer> labels) {
-        this(Opcodes.ASM6, mv, labels);
-        if (getClass() != CheckMethodAdapter.class) {
-            throw new IllegalStateException();
-        }
+  }
+
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+   * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+   *
+   * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param methodVisitor the method visitor to which this adapter must delegate calls.
+   * @param labelInsnIndices the index of the instruction designated by each visited label so far
+   *     (in other methods). This map is updated with the labels from the visited method.
+   */
+  protected CheckMethodAdapter(
+      final int api,
+      final MethodVisitor methodVisitor,
+      final Map<Label, Integer> labelInsnIndices) {
+    super(api, methodVisitor);
+    this.labelInsnIndices = labelInsnIndices;
+    this.referencedLabels = new HashSet<Label>();
+    this.handlers = new ArrayList<Label>();
+  }
+
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
+   * flow checks. For instance in a method whose signature is {@code void m ()}, the invalid
+   * instruction IRETURN, or the invalid sequence IADD L2I will be detected. <i>Subclasses must not
+   * use this constructor</i>. Instead, they must use the {@link
+   * #CheckMethodAdapter(int,int,String,String,MethodVisitor,Map)} version.
+   *
+   * @param access the method's access flags.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param methodVisitor the method visitor to which this adapter must delegate calls.
+   * @param labelInsnIndices the index of the instruction designated by each visited label so far
+   *     (in other methods). This map is updated with the labels from the visited method.
+   */
+  public CheckMethodAdapter(
+      final int access,
+      final String name,
+      final String descriptor,
+      final MethodVisitor methodVisitor,
+      final Map<Label, Integer> labelInsnIndices) {
+    this(Opcodes.ASM7, access, name, descriptor, methodVisitor, labelInsnIndices);
+    if (getClass() != CheckMethodAdapter.class) {
+      throw new IllegalStateException();
     }
-
-    /**
-     * Constructs a new {@link CheckMethodAdapter} object. This method adapter
-     * will not perform any data flow check (see
-     * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
-     * 
-     * @param api
-     *            the ASM API version implemented by this CheckMethodAdapter.
-     *            Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5}
-     *            or {@link Opcodes#ASM6}.
-     * @param mv
-     *            the method visitor to which this adapter must delegate calls.
-     * @param labels
-     *            a map of already visited labels (in other methods).
-     */
-    protected CheckMethodAdapter(final int api, final MethodVisitor mv,
-            final Map<Label, Integer> labels) {
-        super(api, mv);
-        this.labels = labels;
-        this.usedLabels = new HashSet<Label>();
-        this.handlers = new ArrayList<Label>();
-    }
-
-    /**
-     * Constructs a new {@link CheckMethodAdapter} object. This method adapter
-     * will perform basic data flow checks. For instance in a method whose
-     * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the
-     * invalid sequence IADD L2I will be detected.
-     * 
-     * @param access
-     *            the method's access flags.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param cmv
-     *            the method visitor to which this adapter must delegate calls.
-     * @param labels
-     *            a map of already visited labels (in other methods).
-     */
-    public CheckMethodAdapter(final int access, final String name,
-            final String desc, final MethodVisitor cmv,
-            final Map<Label, Integer> labels) {
-        this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
-            @Override
-            public void visitEnd() {
-                Analyzer<BasicValue> a = new Analyzer<BasicValue>(
-                        new BasicVerifier());
-                try {
-                    a.analyze("dummy", this);
-                } catch (Exception e) {
-                    if (e instanceof IndexOutOfBoundsException
-                            && maxLocals == 0 && maxStack == 0) {
-                        throw new RuntimeException(
-                                "Data flow checking option requires valid, non zero maxLocals and maxStack values.");
-                    }
-                    e.printStackTrace();
-                    StringWriter sw = new StringWriter();
-                    PrintWriter pw = new PrintWriter(sw, true);
-                    CheckClassAdapter.printAnalyzerResult(this, a, pw);
-                    pw.close();
-                    throw new RuntimeException(e.getMessage() + ' '
-                            + sw.toString());
-                }
-                accept(cmv);
+  }
+
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
+   * flow checks. For instance in a method whose signature is {@code void m ()}, the invalid
+   * instruction IRETURN, or the invalid sequence IADD L2I will be detected.
+   *
+   * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param access the method's access flags.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param methodVisitor the method visitor to which this adapter must delegate calls.
+   * @param labelInsnIndices the index of the instruction designated by each visited label so far
+   *     (in other methods). This map is updated with the labels from the visited method.
+   */
+  protected CheckMethodAdapter(
+      final int api,
+      final int access,
+      final String name,
+      final String descriptor,
+      final MethodVisitor methodVisitor,
+      final Map<Label, Integer> labelInsnIndices) {
+    this(
+        api,
+        new MethodNode(api, access, name, descriptor, null, null) {
+          @Override
+          public void visitEnd() {
+            Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier());
+            try {
+              analyzer.analyze("dummy", this);
+            } catch (IndexOutOfBoundsException e) {
+              if (maxLocals == 0 && maxStack == 0) {
+                throw new IllegalArgumentException(
+                    "Data flow checking option requires valid, non zero maxLocals and maxStack.",
+                    e);
+              }
+              throwError(analyzer, e);
+            } catch (AnalyzerException e) {
+              throwError(analyzer, e);
             }
-        }, labels);
-        this.access = access;
+            accept(methodVisitor);
+          }
+
+          private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) {
+            StringWriter stringWriter = new StringWriter();
+            PrintWriter printWriter = new PrintWriter(stringWriter, true);
+            CheckClassAdapter.printAnalyzerResult(this, analyzer, printWriter);
+            printWriter.close();
+            throw new IllegalArgumentException(e.getMessage() + ' ' + stringWriter.toString(), e);
+          }
+        },
+        labelInsnIndices);
+    this.access = access;
+  }
+
+  @Override
+  public void visitParameter(final String name, final int access) {
+    if (name != null) {
+      checkUnqualifiedName(version, name, "name");
     }
-
-    @Override
-    public void visitParameter(String name, int access) {
-        if (name != null) {
-            checkUnqualifiedName(version, name, "name");
-        }
-        CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL
-                + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
-        super.visitParameter(name, access);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        checkEndMethod();
-        checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        checkEndMethod();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.METHOD_TYPE_PARAMETER
-                && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
-                && sort != TypeReference.METHOD_RETURN
-                && sort != TypeReference.METHOD_RECEIVER
-                && sort != TypeReference.METHOD_FORMAL_PARAMETER
-                && sort != TypeReference.THROWS) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
-                typePath, desc, visible));
+    CheckClassAdapter.checkAccess(
+        access, Opcodes.ACC_FINAL + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
+    super.visitParameter(name, access);
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    checkVisitEndNotCalled();
+    checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
+  }
+
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    checkVisitEndNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.METHOD_TYPE_PARAMETER
+        && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
+        && sort != TypeReference.METHOD_RETURN
+        && sort != TypeReference.METHOD_RECEIVER
+        && sort != TypeReference.METHOD_FORMAL_PARAMETER
+        && sort != TypeReference.THROWS) {
+      throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
     }
-
-    @Override
-    public AnnotationVisitor visitAnnotationDefault() {
-        checkEndMethod();
-        return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
+    CheckClassAdapter.checkTypeRef(typeRef);
+    CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotationDefault() {
+    checkVisitEndNotCalled();
+    return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
+  }
+
+  @Override
+  public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+    checkVisitEndNotCalled();
+    if (visible) {
+      visibleAnnotableParameterCount = parameterCount;
+    } else {
+      invisibleAnnotableParameterCount = parameterCount;
     }
-
-    @Override
-    public AnnotationVisitor visitParameterAnnotation(final int parameter,
-            final String desc, final boolean visible) {
-        checkEndMethod();
-        checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitParameterAnnotation(
-                parameter, desc, visible));
+    super.visitAnnotableParameterCount(parameterCount, visible);
+  }
+
+  @Override
+  public AnnotationVisitor visitParameterAnnotation(
+      final int parameter, final String descriptor, final boolean visible) {
+    checkVisitEndNotCalled();
+    if ((visible
+            && visibleAnnotableParameterCount > 0
+            && parameter >= visibleAnnotableParameterCount)
+        || (!visible
+            && invisibleAnnotableParameterCount > 0
+            && parameter >= invisibleAnnotableParameterCount)) {
+      throw new IllegalArgumentException("Invalid parameter index");
     }
-
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        checkEndMethod();
-        if (attr == null) {
-            throw new IllegalArgumentException(
-                    "Invalid attribute (must not be null)");
-        }
-        super.visitAttribute(attr);
+    checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitParameterAnnotation(parameter, descriptor, visible));
+  }
+
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    checkVisitEndNotCalled();
+    if (attribute == null) {
+      throw new IllegalArgumentException("Invalid attribute (must not be null)");
     }
+    super.visitAttribute(attribute);
+  }
 
-    @Override
-    public void visitCode() {
-        if ((access & Opcodes.ACC_ABSTRACT) != 0) {
-            throw new RuntimeException("Abstract methods cannot have code");
-        }
-        startCode = true;
-        super.visitCode();
+  @Override
+  public void visitCode() {
+    if ((access & Opcodes.ACC_ABSTRACT) != 0) {
+      throw new UnsupportedOperationException("Abstract methods cannot have code");
     }
-
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        if (insnCount == lastFrame) {
-            throw new IllegalStateException(
-                    "At most one frame can be visited at a given code location.");
-        }
-        lastFrame = insnCount;
-        int mLocal;
-        int mStack;
-        switch (type) {
-        case Opcodes.F_NEW:
-        case Opcodes.F_FULL:
-            mLocal = Integer.MAX_VALUE;
-            mStack = Integer.MAX_VALUE;
-            break;
-
-        case Opcodes.F_SAME:
-            mLocal = 0;
-            mStack = 0;
-            break;
-
-        case Opcodes.F_SAME1:
-            mLocal = 0;
-            mStack = 1;
-            break;
-
-        case Opcodes.F_APPEND:
-        case Opcodes.F_CHOP:
-            mLocal = 3;
-            mStack = 0;
-            break;
-
-        default:
-            throw new IllegalArgumentException("Invalid frame type " + type);
-        }
-
-        if (nLocal > mLocal) {
-            throw new IllegalArgumentException("Invalid nLocal=" + nLocal
-                    + " for frame type " + type);
-        }
-        if (nStack > mStack) {
-            throw new IllegalArgumentException("Invalid nStack=" + nStack
-                    + " for frame type " + type);
-        }
-
-        if (type != Opcodes.F_CHOP) {
-            if (nLocal > 0 && (local == null || local.length < nLocal)) {
-                throw new IllegalArgumentException(
-                        "Array local[] is shorter than nLocal");
-            }
-            for (int i = 0; i < nLocal; ++i) {
-                checkFrameValue(local[i]);
-            }
-        }
-        if (nStack > 0 && (stack == null || stack.length < nStack)) {
-            throw new IllegalArgumentException(
-                    "Array stack[] is shorter than nStack");
-        }
-        for (int i = 0; i < nStack; ++i) {
-            checkFrameValue(stack[i]);
-        }
-        if (type == Opcodes.F_NEW) {
-            ++expandedFrames;
-        } else {
-            ++compressedFrames;
-        }
-        if (expandedFrames > 0 && compressedFrames > 0) {
-            throw new RuntimeException(
-                    "Expanded and compressed frames must not be mixed.");
-        }
-        super.visitFrame(type, nLocal, local, nStack, stack);
-    }
-
-    @Override
-    public void visitInsn(final int opcode) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 0);
-        super.visitInsn(opcode);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitIntInsn(final int opcode, final int operand) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 1);
-        switch (opcode) {
-        case Opcodes.BIPUSH:
-            checkSignedByte(operand, "Invalid operand");
-            break;
-        case Opcodes.SIPUSH:
-            checkSignedShort(operand, "Invalid operand");
-            break;
-        // case Constants.NEWARRAY:
-        default:
-            if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
-                throw new IllegalArgumentException(
-                        "Invalid operand (must be an array type code T_...): "
-                                + operand);
-            }
-        }
-        super.visitIntInsn(opcode, operand);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 2);
-        checkUnsignedShort(var, "Invalid variable index");
-        super.visitVarInsn(opcode, var);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 3);
-        checkInternalName(type, "type");
-        if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
-            throw new IllegalArgumentException(
-                    "NEW cannot be used to create arrays: " + type);
-        }
-        super.visitTypeInsn(opcode, type);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 4);
-        checkInternalName(owner, "owner");
-        checkUnqualifiedName(version, name, "name");
-        checkDesc(desc, false);
-        super.visitFieldInsn(opcode, owner, name, desc);
-        ++insnCount;
-    }
-
-    @Deprecated
-    @Override
-    public void visitMethodInsn(int opcode, String owner, String name,
-            String desc) {
-        if (api >= Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc);
-            return;
-        }
-        doVisitMethodInsn(opcode, owner, name, desc,
-                opcode == Opcodes.INVOKEINTERFACE);
+    visitCodeCalled = true;
+    super.visitCode();
+  }
+
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    if (insnCount == lastFrameInsnIndex) {
+      throw new IllegalStateException("At most one frame can be visited at a given code location.");
     }
-
-    @Override
-    public void visitMethodInsn(int opcode, String owner, String name,
-            String desc, boolean itf) {
-        if (api < Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
-        }
-        doVisitMethodInsn(opcode, owner, name, desc, itf);
+    lastFrameInsnIndex = insnCount;
+    int maxNumLocal;
+    int maxNumStack;
+    switch (type) {
+      case Opcodes.F_NEW:
+      case Opcodes.F_FULL:
+        maxNumLocal = Integer.MAX_VALUE;
+        maxNumStack = Integer.MAX_VALUE;
+        break;
+
+      case Opcodes.F_SAME:
+        maxNumLocal = 0;
+        maxNumStack = 0;
+        break;
+
+      case Opcodes.F_SAME1:
+        maxNumLocal = 0;
+        maxNumStack = 1;
+        break;
+
+      case Opcodes.F_APPEND:
+      case Opcodes.F_CHOP:
+        maxNumLocal = 3;
+        maxNumStack = 0;
+        break;
+
+      default:
+        throw new IllegalArgumentException("Invalid frame type " + type);
     }
 
-    private void doVisitMethodInsn(int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 5);
-        if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
-            checkMethodIdentifier(version, name, "name");
-        }
-        checkInternalName(owner, "owner");
-        checkMethodDesc(desc);
-        if (opcode == Opcodes.INVOKEVIRTUAL && itf) {
-            throw new IllegalArgumentException(
-                    "INVOKEVIRTUAL can't be used with interfaces");
-        }
-        if (opcode == Opcodes.INVOKEINTERFACE && !itf) {
-            throw new IllegalArgumentException(
-                    "INVOKEINTERFACE can't be used with classes");
-        }
-        if (opcode == Opcodes.INVOKESPECIAL && itf
-                && (version & 0xFFFF) < Opcodes.V1_8) {
-            throw new IllegalArgumentException(
-                    "INVOKESPECIAL can't be used with interfaces prior to Java 8");
-        }
-
-        // Calling super.visitMethodInsn requires to call the correct version
-        // depending on this.api (otherwise infinite loops can occur). To
-        // simplify and to make it easier to automatically remove the backward
-        // compatibility code, we inline the code of the overridden method here.
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, owner, name, desc, itf);
-        }
-        ++insnCount;
-    }
-
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        checkStartCode();
-        checkEndCode();
-        checkMethodIdentifier(version, name, "name");
-        checkMethodDesc(desc);
-        if (bsm.getTag() != Opcodes.H_INVOKESTATIC
-                && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
-            throw new IllegalArgumentException("invalid handle tag "
-                    + bsm.getTag());
-        }
-        for (int i = 0; i < bsmArgs.length; i++) {
-            checkLDCConstant(bsmArgs[i]);
-        }
-        super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitJumpInsn(final int opcode, final Label label) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 6);
-        checkLabel(label, false, "label");
-        checkNonDebugLabel(label);
-        super.visitJumpInsn(opcode, label);
-        usedLabels.add(label);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitLabel(final Label label) {
-        checkStartCode();
-        checkEndCode();
-        checkLabel(label, false, "label");
-        if (labels.get(label) != null) {
-            throw new IllegalArgumentException("Already visited label");
-        }
-        labels.put(label, insnCount);
-        super.visitLabel(label);
-    }
-
-    @Override
-    public void visitLdcInsn(final Object cst) {
-        checkStartCode();
-        checkEndCode();
-        checkLDCConstant(cst);
-        super.visitLdcInsn(cst);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        checkStartCode();
-        checkEndCode();
-        checkUnsignedShort(var, "Invalid variable index");
-        checkSignedShort(increment, "Invalid increment");
-        super.visitIincInsn(var, increment);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        checkStartCode();
-        checkEndCode();
-        if (max < min) {
-            throw new IllegalArgumentException("Max = " + max
-                    + " must be greater than or equal to min = " + min);
-        }
-        checkLabel(dflt, false, "default label");
-        checkNonDebugLabel(dflt);
-        if (labels == null || labels.length != max - min + 1) {
-            throw new IllegalArgumentException(
-                    "There must be max - min + 1 labels");
-        }
-        for (int i = 0; i < labels.length; ++i) {
-            checkLabel(labels[i], false, "label at index " + i);
-            checkNonDebugLabel(labels[i]);
-        }
-        super.visitTableSwitchInsn(min, max, dflt, labels);
-        for (int i = 0; i < labels.length; ++i) {
-            usedLabels.add(labels[i]);
-        }
-        ++insnCount;
-    }
-
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        checkEndCode();
-        checkStartCode();
-        checkLabel(dflt, false, "default label");
-        checkNonDebugLabel(dflt);
-        if (keys == null || labels == null || keys.length != labels.length) {
-            throw new IllegalArgumentException(
-                    "There must be the same number of keys and labels");
-        }
-        for (int i = 0; i < labels.length; ++i) {
-            checkLabel(labels[i], false, "label at index " + i);
-            checkNonDebugLabel(labels[i]);
-        }
-        super.visitLookupSwitchInsn(dflt, keys, labels);
-        usedLabels.add(dflt);
-        for (int i = 0; i < labels.length; ++i) {
-            usedLabels.add(labels[i]);
-        }
-        ++insnCount;
-    }
-
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        checkStartCode();
-        checkEndCode();
-        checkDesc(desc, false);
-        if (desc.charAt(0) != '[') {
-            throw new IllegalArgumentException(
-                    "Invalid descriptor (must be an array type descriptor): "
-                            + desc);
-        }
-        if (dims < 1) {
-            throw new IllegalArgumentException(
-                    "Invalid dimensions (must be greater than 0): " + dims);
-        }
-        if (dims > desc.lastIndexOf('[') + 1) {
-            throw new IllegalArgumentException(
-                    "Invalid dimensions (must not be greater than dims(desc)): "
-                            + dims);
-        }
-        super.visitMultiANewArrayInsn(desc, dims);
-        ++insnCount;
-    }
-
-    @Override
-    public AnnotationVisitor visitInsnAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        checkStartCode();
-        checkEndCode();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.INSTANCEOF && sort != TypeReference.NEW
-                && sort != TypeReference.CONSTRUCTOR_REFERENCE
-                && sort != TypeReference.METHOD_REFERENCE
-                && sort != TypeReference.CAST
-                && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
-                && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
-                && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
-                && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitInsnAnnotation(typeRef,
-                typePath, desc, visible));
-    }
-
-    @Override
-    public void visitTryCatchBlock(final Label start, final Label end,
-            final Label handler, final String type) {
-        checkStartCode();
-        checkEndCode();
-        checkLabel(start, false, "start label");
-        checkLabel(end, false, "end label");
-        checkLabel(handler, false, "handler label");
-        checkNonDebugLabel(start);
-        checkNonDebugLabel(end);
-        checkNonDebugLabel(handler);
-        if (labels.get(start) != null || labels.get(end) != null
-                || labels.get(handler) != null) {
-            throw new IllegalStateException(
-                    "Try catch blocks must be visited before their labels");
-        }
-        if (type != null) {
-            checkInternalName(type, "type");
-        }
-        super.visitTryCatchBlock(start, end, handler, type);
-        handlers.add(start);
-        handlers.add(end);
-    }
-
-    @Override
-    public AnnotationVisitor visitTryCatchAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        checkStartCode();
-        checkEndCode();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.EXCEPTION_PARAMETER) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitTryCatchAnnotation(
-                typeRef, typePath, desc, visible));
-    }
-
-    @Override
-    public void visitLocalVariable(final String name, final String desc,
-            final String signature, final Label start, final Label end,
-            final int index) {
-        checkStartCode();
-        checkEndCode();
-        checkUnqualifiedName(version, name, "name");
-        checkDesc(desc, false);
-        checkLabel(start, true, "start label");
-        checkLabel(end, true, "end label");
-        checkUnsignedShort(index, "Invalid variable index");
-        int s = labels.get(start).intValue();
-        int e = labels.get(end).intValue();
-        if (e < s) {
-            throw new IllegalArgumentException(
-                    "Invalid start and end labels (end must be greater than start)");
-        }
-        super.visitLocalVariable(name, desc, signature, start, end, index);
-    }
-
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        checkStartCode();
-        checkEndCode();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.LOCAL_VARIABLE
-                && sort != TypeReference.RESOURCE_VARIABLE) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        checkDesc(desc, false);
-        if (start == null || end == null || index == null
-                || end.length != start.length || index.length != start.length) {
-            throw new IllegalArgumentException(
-                    "Invalid start, end and index arrays (must be non null and of identical length");
-        }
-        for (int i = 0; i < start.length; ++i) {
-            checkLabel(start[i], true, "start label");
-            checkLabel(end[i], true, "end label");
-            checkUnsignedShort(index[i], "Invalid variable index");
-            int s = labels.get(start[i]).intValue();
-            int e = labels.get(end[i]).intValue();
-            if (e < s) {
-                throw new IllegalArgumentException(
-                        "Invalid start and end labels (end must be greater than start)");
-            }
-        }
-        return super.visitLocalVariableAnnotation(typeRef, typePath, start,
-                end, index, desc, visible);
-    }
-
-    @Override
-    public void visitLineNumber(final int line, final Label start) {
-        checkStartCode();
-        checkEndCode();
-        checkUnsignedShort(line, "Invalid line number");
-        checkLabel(start, true, "start label");
-        super.visitLineNumber(line, start);
-    }
-
-    @Override
-    public void visitMaxs(final int maxStack, final int maxLocals) {
-        checkStartCode();
-        checkEndCode();
-        endCode = true;
-        for (Label l : usedLabels) {
-            if (labels.get(l) == null) {
-                throw new IllegalStateException("Undefined label used");
-            }
-        }
-        for (int i = 0; i < handlers.size();) {
-            Integer start = labels.get(handlers.get(i++));
-            Integer end = labels.get(handlers.get(i++));
-            if (start == null || end == null) {
-                throw new IllegalStateException(
-                        "Undefined try catch block labels");
-            }
-            if (end.intValue() <= start.intValue()) {
-                throw new IllegalStateException(
-                        "Emty try catch block handler range");
-            }
-        }
-        checkUnsignedShort(maxStack, "Invalid max stack");
-        checkUnsignedShort(maxLocals, "Invalid max locals");
-        super.visitMaxs(maxStack, maxLocals);
+    if (numLocal > maxNumLocal) {
+      throw new IllegalArgumentException(
+          "Invalid numLocal=" + numLocal + " for frame type " + type);
     }
-
-    @Override
-    public void visitEnd() {
-        checkEndMethod();
-        endMethod = true;
-        super.visitEnd();
+    if (numStack > maxNumStack) {
+      throw new IllegalArgumentException(
+          "Invalid numStack=" + numStack + " for frame type " + type);
     }
 
-    // -------------------------------------------------------------------------
-
-    /**
-     * Checks that the visitCode method has been called.
-     */
-    void checkStartCode() {
-        if (!startCode) {
-            throw new IllegalStateException(
-                    "Cannot visit instructions before visitCode has been called.");
-        }
+    if (type != Opcodes.F_CHOP) {
+      if (numLocal > 0 && (local == null || local.length < numLocal)) {
+        throw new IllegalArgumentException("Array local[] is shorter than numLocal");
+      }
+      for (int i = 0; i < numLocal; ++i) {
+        checkFrameValue(local[i]);
+      }
     }
-
-    /**
-     * Checks that the visitMaxs method has not been called.
-     */
-    void checkEndCode() {
-        if (endCode) {
-            throw new IllegalStateException(
-                    "Cannot visit instructions after visitMaxs has been called.");
-        }
+    if (numStack > 0 && (stack == null || stack.length < numStack)) {
+      throw new IllegalArgumentException("Array stack[] is shorter than numStack");
     }
-
-    /**
-     * Checks that the visitEnd method has not been called.
-     */
-    void checkEndMethod() {
-        if (endMethod) {
-            throw new IllegalStateException(
-                    "Cannot visit elements after visitEnd has been called.");
-        }
+    for (int i = 0; i < numStack; ++i) {
+      checkFrameValue(stack[i]);
     }
-
-    /**
-     * Checks a stack frame value.
-     * 
-     * @param value
-     *            the value to be checked.
-     */
-    void checkFrameValue(final Object value) {
-        if (value == Opcodes.TOP || value == Opcodes.INTEGER
-                || value == Opcodes.FLOAT || value == Opcodes.LONG
-                || value == Opcodes.DOUBLE || value == Opcodes.NULL
-                || value == Opcodes.UNINITIALIZED_THIS) {
-            return;
-        }
-        if (value instanceof String) {
-            checkInternalName((String) value, "Invalid stack frame value");
-            return;
-        }
-        if (!(value instanceof Label)) {
-            throw new IllegalArgumentException("Invalid stack frame value: "
-                    + value);
-        } else {
-            usedLabels.add((Label) value);
-        }
+    if (type == Opcodes.F_NEW) {
+      ++numExpandedFrames;
+    } else {
+      ++numCompressedFrames;
     }
-
-    /**
-     * Checks that the type of the given opcode is equal to the given type.
-     * 
-     * @param opcode
-     *            the opcode to be checked.
-     * @param type
-     *            the expected opcode type.
-     */
-    static void checkOpcode(final int opcode, final int type) {
-        if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
-            throw new IllegalArgumentException("Invalid opcode: " + opcode);
-        }
+    if (numExpandedFrames > 0 && numCompressedFrames > 0) {
+      throw new IllegalArgumentException("Expanded and compressed frames must not be mixed.");
     }
-
-    /**
-     * Checks that the given value is a signed byte.
-     * 
-     * @param value
-     *            the value to be checked.
-     * @param msg
-     *            an message to be used in case of error.
-     */
-    static void checkSignedByte(final int value, final String msg) {
-        if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
-            throw new IllegalArgumentException(msg
-                    + " (must be a signed byte): " + value);
-        }
+    super.visitFrame(type, numLocal, local, numStack, stack);
+  }
+
+  @Override
+  public void visitInsn(final int opcode) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_INSN);
+    super.visitInsn(opcode);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_INT_INSN);
+    switch (opcode) {
+      case Opcodes.BIPUSH:
+        checkSignedByte(operand, "Invalid operand");
+        break;
+      case Opcodes.SIPUSH:
+        checkSignedShort(operand, "Invalid operand");
+        break;
+      case Opcodes.NEWARRAY:
+        if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
+          throw new IllegalArgumentException(
+              "Invalid operand (must be an array type code T_...): " + operand);
+        }
+        break;
+      default:
+        throw new AssertionError();
     }
-
-    /**
-     * Checks that the given value is a signed short.
-     * 
-     * @param value
-     *            the value to be checked.
-     * @param msg
-     *            an message to be used in case of error.
-     */
-    static void checkSignedShort(final int value, final String msg) {
-        if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
-            throw new IllegalArgumentException(msg
-                    + " (must be a signed short): " + value);
-        }
+    super.visitIntInsn(opcode, operand);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_VAR_INSN);
+    checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
+    super.visitVarInsn(opcode, var);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_TYPE_INSN);
+    checkInternalName(version, type, "type");
+    if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
+      throw new IllegalArgumentException("NEW cannot be used to create arrays: " + type);
     }
-
-    /**
-     * Checks that the given value is an unsigned short.
-     * 
-     * @param value
-     *            the value to be checked.
-     * @param msg
-     *            an message to be used in case of error.
-     */
-    static void checkUnsignedShort(final int value, final String msg) {
-        if (value < 0 || value > 65535) {
-            throw new IllegalArgumentException(msg
-                    + " (must be an unsigned short): " + value);
-        }
+    super.visitTypeInsn(opcode, type);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_FIELD_INSN);
+    checkInternalName(version, owner, "owner");
+    checkUnqualifiedName(version, name, "name");
+    checkDescriptor(version, descriptor, false);
+    super.visitFieldInsn(opcode, owner, name, descriptor);
+    ++insnCount;
+  }
+
+  /**
+   * Deprecated.
+   *
+   * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
+   */
+  @Deprecated
+  @Override
+  public void visitMethodInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    if (api >= Opcodes.ASM5) {
+      super.visitMethodInsn(opcode, owner, name, descriptor);
+      return;
     }
-
-    /**
-     * Checks that the given value is an {@link Integer}, a{@link Float}, a
-     * {@link Long}, a {@link Double} or a {@link String}.
-     * 
-     * @param cst
-     *            the value to be checked.
-     */
-    static void checkConstant(final Object cst) {
-        if (!(cst instanceof Integer) && !(cst instanceof Float)
-                && !(cst instanceof Long) && !(cst instanceof Double)
-                && !(cst instanceof String)) {
-            throw new IllegalArgumentException("Invalid constant: " + cst);
-        }
+    doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
+  }
+
+  @Override
+  public void visitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    if (api < Opcodes.ASM5) {
+      super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+      return;
     }
-
-    void checkLDCConstant(final Object cst) {
-        if (cst instanceof Type) {
-            int s = ((Type) cst).getSort();
-            if (s != Type.OBJECT && s != Type.ARRAY && s != Type.METHOD) {
-                throw new IllegalArgumentException("Illegal LDC constant value");
-            }
-            if (s != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
-                throw new IllegalArgumentException(
-                        "ldc of a constant class requires at least version 1.5");
-            }
-            if (s == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
-                throw new IllegalArgumentException(
-                        "ldc of a method type requires at least version 1.7");
-            }
-        } else if (cst instanceof Handle) {
-            if ((version & 0xFFFF) < Opcodes.V1_7) {
-                throw new IllegalArgumentException(
-                        "ldc of a handle requires at least version 1.7");
-            }
-            int tag = ((Handle) cst).getTag();
-            if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
-                throw new IllegalArgumentException("invalid handle tag " + tag);
-            }
-        } else {
-            checkConstant(cst);
-        }
+    doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
+  }
+
+  private void doVisitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
+    if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
+      checkMethodIdentifier(version, name, "name");
     }
-
-    /**
-     * Checks that the given string is a valid unqualified name.
-     * 
-     * @param version
-     *            the class version.
-     * @param name
-     *            the string to be checked.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkUnqualifiedName(int version, final String name,
-            final String msg) {
-        if ((version & 0xFFFF) < Opcodes.V1_5) {
-            checkIdentifier(name, msg);
-        } else {
-            for (int i = 0; i < name.length(); ++i) {
-                if (".;[/".indexOf(name.charAt(i)) != -1) {
-                    throw new IllegalArgumentException("Invalid " + msg
-                            + " (must be a valid unqualified name): " + name);
-                }
-            }
-        }
+    checkInternalName(version, owner, "owner");
+    checkMethodDescriptor(version, descriptor);
+    if (opcode == Opcodes.INVOKEVIRTUAL && isInterface) {
+      throw new IllegalArgumentException("INVOKEVIRTUAL can't be used with interfaces");
     }
-
-    /**
-     * Checks that the given string is a valid Java identifier.
-     * 
-     * @param name
-     *            the string to be checked.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkIdentifier(final String name, final String msg) {
-        checkIdentifier(name, 0, -1, msg);
-    }
-
-    /**
-     * Checks that the given substring is a valid Java identifier.
-     * 
-     * @param name
-     *            the string to be checked.
-     * @param start
-     *            index of the first character of the identifier (inclusive).
-     * @param end
-     *            index of the last character of the identifier (exclusive). -1
-     *            is equivalent to <tt>name.length()</tt> if name is not
-     *            <tt>null</tt>.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkIdentifier(final String name, final int start,
-            final int end, final String msg) {
-        if (name == null || (end == -1 ? name.length() <= start : end <= start)) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        if (!Character.isJavaIdentifierStart(name.charAt(start))) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must be a valid Java identifier): " + name);
-        }
-        int max = end == -1 ? name.length() : end;
-        for (int i = start + 1; i < max; ++i) {
-            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
-                throw new IllegalArgumentException("Invalid " + msg
-                        + " (must be a valid Java identifier): " + name);
-            }
-        }
+    if (opcode == Opcodes.INVOKEINTERFACE && !isInterface) {
+      throw new IllegalArgumentException("INVOKEINTERFACE can't be used with classes");
     }
-
-    /**
-     * Checks that the given string is a valid Java identifier.
-     * 
-     * @param version
-     *            the class version.
-     * @param name
-     *            the string to be checked.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkMethodIdentifier(int version, final String name,
-            final String msg) {
-        if (name == null || name.length() == 0) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        if ((version & 0xFFFF) >= Opcodes.V1_5) {
-            for (int i = 0; i < name.length(); ++i) {
-                if (".;[/<>".indexOf(name.charAt(i)) != -1) {
-                    throw new IllegalArgumentException("Invalid " + msg
-                            + " (must be a valid unqualified name): " + name);
-                }
-            }
-            return;
-        }
-        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
-            throw new IllegalArgumentException(
-                    "Invalid "
-                            + msg
-                            + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
-                            + name);
-        }
-        for (int i = 1; i < name.length(); ++i) {
-            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
-                throw new IllegalArgumentException(
-                        "Invalid "
-                                + msg
-                                + " (must be '<init>' or '<clinit>' or a valid Java identifier): "
-                                + name);
-            }
-        }
+    if (opcode == Opcodes.INVOKESPECIAL && isInterface && (version & 0xFFFF) < Opcodes.V1_8) {
+      throw new IllegalArgumentException(
+          "INVOKESPECIAL can't be used with interfaces prior to Java 8");
     }
 
-    /**
-     * Checks that the given string is a valid internal class name.
-     * 
-     * @param name
-     *            the string to be checked.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkInternalName(final String name, final String msg) {
-        if (name == null || name.length() == 0) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        if (name.charAt(0) == '[') {
-            checkDesc(name, false);
-        } else {
-            checkInternalName(name, 0, -1, msg);
-        }
+    // Calling super.visitMethodInsn requires to call the correct version depending on this.api
+    // (otherwise infinite loops can occur). To simplify and to make it easier to automatically
+    // remove the backward compatibility code, we inline the code of the overridden method here.
+    if (mv != null) {
+      mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
     }
-
-    /**
-     * Checks that the given substring is a valid internal class name.
-     * 
-     * @param name
-     *            the string to be checked.
-     * @param start
-     *            index of the first character of the identifier (inclusive).
-     * @param end
-     *            index of the last character of the identifier (exclusive). -1
-     *            is equivalent to <tt>name.length()</tt> if name is not
-     *            <tt>null</tt>.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkInternalName(final String name, final int start,
-            final int end, final String msg) {
-        int max = end == -1 ? name.length() : end;
-        try {
-            int begin = start;
-            int slash;
-            do {
-                slash = name.indexOf('/', begin + 1);
-                if (slash == -1 || slash > max) {
-                    slash = max;
-                }
-                checkIdentifier(name, begin, slash, null);
-                begin = slash + 1;
-            } while (slash != max);
-        } catch (IllegalArgumentException unused) {
-            throw new IllegalArgumentException(
-                    "Invalid "
-                            + msg
-                            + " (must be a fully qualified class name in internal form): "
-                            + name);
-        }
+    ++insnCount;
+  }
+
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkMethodIdentifier(version, name, "name");
+    checkMethodDescriptor(version, descriptor);
+    if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
+        && bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
+      throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
     }
-
-    /**
-     * Checks that the given string is a valid type descriptor.
-     * 
-     * @param desc
-     *            the string to be checked.
-     * @param canBeVoid
-     *            <tt>true</tt> if <tt>V</tt> can be considered valid.
-     */
-    static void checkDesc(final String desc, final boolean canBeVoid) {
-        int end = checkDesc(desc, 0, canBeVoid);
-        if (end != desc.length()) {
-            throw new IllegalArgumentException("Invalid descriptor: " + desc);
-        }
+    for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
+      checkLdcConstant(bootstrapMethodArgument);
     }
-
-    /**
-     * Checks that a the given substring is a valid type descriptor.
-     * 
-     * @param desc
-     *            the string to be checked.
-     * @param start
-     *            index of the first character of the identifier (inclusive).
-     * @param canBeVoid
-     *            <tt>true</tt> if <tt>V</tt> can be considered valid.
-     * @return the index of the last character of the type decriptor, plus one.
-     */
-    static int checkDesc(final String desc, final int start,
-            final boolean canBeVoid) {
-        if (desc == null || start >= desc.length()) {
-            throw new IllegalArgumentException(
-                    "Invalid type descriptor (must not be null or empty)");
-        }
-        int index;
-        switch (desc.charAt(start)) {
-        case 'V':
-            if (canBeVoid) {
-                return start + 1;
-            } else {
-                throw new IllegalArgumentException("Invalid descriptor: "
-                        + desc);
-            }
-        case 'Z':
-        case 'C':
-        case 'B':
-        case 'S':
-        case 'I':
-        case 'F':
-        case 'J':
-        case 'D':
-            return start + 1;
-        case '[':
-            index = start + 1;
-            while (index < desc.length() && desc.charAt(index) == '[') {
-                ++index;
-            }
-            if (index < desc.length()) {
-                return checkDesc(desc, index, false);
-            } else {
-                throw new IllegalArgumentException("Invalid descriptor: "
-                        + desc);
-            }
-        case 'L':
-            index = desc.indexOf(';', start);
-            if (index == -1 || index - start < 2) {
-                throw new IllegalArgumentException("Invalid descriptor: "
-                        + desc);
-            }
-            try {
-                checkInternalName(desc, start + 1, index, null);
-            } catch (IllegalArgumentException unused) {
-                throw new IllegalArgumentException("Invalid descriptor: "
-                        + desc);
-            }
-            return index + 1;
-        default:
-            throw new IllegalArgumentException("Invalid descriptor: " + desc);
-        }
+    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_JUMP_INSN);
+    checkLabel(label, false, "label");
+    super.visitJumpInsn(opcode, label);
+    referencedLabels.add(label);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitLabel(final Label label) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkLabel(label, false, "label");
+    if (labelInsnIndices.get(label) != null) {
+      throw new IllegalArgumentException("Already visited label");
+    }
+    labelInsnIndices.put(label, insnCount);
+    super.visitLabel(label);
+  }
+
+  @Override
+  public void visitLdcInsn(final Object value) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkLdcConstant(value);
+    super.visitLdcInsn(value);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
+    checkSignedShort(increment, "Invalid increment");
+    super.visitIincInsn(var, increment);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    if (max < min) {
+      throw new IllegalArgumentException(
+          "Max = " + max + " must be greater than or equal to min = " + min);
+    }
+    checkLabel(dflt, false, "default label");
+    if (labels == null || labels.length != max - min + 1) {
+      throw new IllegalArgumentException("There must be max - min + 1 labels");
+    }
+    for (int i = 0; i < labels.length; ++i) {
+      checkLabel(labels[i], false, "label at index " + i);
+    }
+    super.visitTableSwitchInsn(min, max, dflt, labels);
+    for (Label label : labels) {
+      referencedLabels.add(label);
+    }
+    ++insnCount;
+  }
+
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    checkVisitMaxsNotCalled();
+    checkVisitCodeCalled();
+    checkLabel(dflt, false, "default label");
+    if (keys == null || labels == null || keys.length != labels.length) {
+      throw new IllegalArgumentException("There must be the same number of keys and labels");
+    }
+    for (int i = 0; i < labels.length; ++i) {
+      checkLabel(labels[i], false, "label at index " + i);
+    }
+    super.visitLookupSwitchInsn(dflt, keys, labels);
+    referencedLabels.add(dflt);
+    for (Label label : labels) {
+      referencedLabels.add(label);
+    }
+    ++insnCount;
+  }
+
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkDescriptor(version, descriptor, false);
+    if (descriptor.charAt(0) != '[') {
+      throw new IllegalArgumentException(
+          "Invalid descriptor (must be an array type descriptor): " + descriptor);
+    }
+    if (numDimensions < 1) {
+      throw new IllegalArgumentException(
+          "Invalid dimensions (must be greater than 0): " + numDimensions);
     }
+    if (numDimensions > descriptor.lastIndexOf('[') + 1) {
+      throw new IllegalArgumentException(
+          "Invalid dimensions (must not be greater than numDimensions(descriptor)): "
+              + numDimensions);
+    }
+    super.visitMultiANewArrayInsn(descriptor, numDimensions);
+    ++insnCount;
+  }
+
+  @Override
+  public AnnotationVisitor visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.INSTANCEOF
+        && sort != TypeReference.NEW
+        && sort != TypeReference.CONSTRUCTOR_REFERENCE
+        && sort != TypeReference.METHOD_REFERENCE
+        && sort != TypeReference.CAST
+        && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+        && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
+        && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+        && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
+      throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+    }
+    CheckClassAdapter.checkTypeRef(typeRef);
+    CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitInsnAnnotation(typeRef, typePath, descriptor, visible));
+  }
+
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkLabel(start, false, START_LABEL);
+    checkLabel(end, false, END_LABEL);
+    checkLabel(handler, false, "handler label");
+    if (labelInsnIndices.get(start) != null
+        || labelInsnIndices.get(end) != null
+        || labelInsnIndices.get(handler) != null) {
+      throw new IllegalStateException("Try catch blocks must be visited before their labels");
+    }
+    if (type != null) {
+      checkInternalName(version, type, "type");
+    }
+    super.visitTryCatchBlock(start, end, handler, type);
+    handlers.add(start);
+    handlers.add(end);
+  }
+
+  @Override
+  public AnnotationVisitor visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.EXCEPTION_PARAMETER) {
+      throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+    }
+    CheckClassAdapter.checkTypeRef(typeRef);
+    CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible));
+  }
+
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkUnqualifiedName(version, name, "name");
+    checkDescriptor(version, descriptor, false);
+    checkLabel(start, true, START_LABEL);
+    checkLabel(end, true, END_LABEL);
+    checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX);
+    int startInsnIndex = labelInsnIndices.get(start).intValue();
+    int endInsnIndex = labelInsnIndices.get(end).intValue();
+    if (endInsnIndex < startInsnIndex) {
+      throw new IllegalArgumentException(
+          "Invalid start and end labels (end must be greater than start)");
+    }
+    super.visitLocalVariable(name, descriptor, signature, start, end, index);
+  }
+
+  @Override
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.LOCAL_VARIABLE && sort != TypeReference.RESOURCE_VARIABLE) {
+      throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+    }
+    CheckClassAdapter.checkTypeRef(typeRef);
+    checkDescriptor(version, descriptor, false);
+    if (start == null
+        || end == null
+        || index == null
+        || end.length != start.length
+        || index.length != start.length) {
+      throw new IllegalArgumentException(
+          "Invalid start, end and index arrays (must be non null and of identical length");
+    }
+    for (int i = 0; i < start.length; ++i) {
+      checkLabel(start[i], true, START_LABEL);
+      checkLabel(end[i], true, END_LABEL);
+      checkUnsignedShort(index[i], INVALID_LOCAL_VARIABLE_INDEX);
+      int startInsnIndex = labelInsnIndices.get(start[i]).intValue();
+      int endInsnIndex = labelInsnIndices.get(end[i]).intValue();
+      if (endInsnIndex < startInsnIndex) {
+        throw new IllegalArgumentException(
+            "Invalid start and end labels (end must be greater than start)");
+      }
+    }
+    return super.visitLocalVariableAnnotation(
+        typeRef, typePath, start, end, index, descriptor, visible);
+  }
+
+  @Override
+  public void visitLineNumber(final int line, final Label start) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkUnsignedShort(line, "Invalid line number");
+    checkL

<TRUNCATED>