1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * ASM: a very small and fast Java bytecode manipulation framework
  32  * Copyright (c) 2000-2011 INRIA, France Telecom
  33  * All rights reserved.
  34  *
  35  * Redistribution and use in source and binary forms, with or without
  36  * modification, are permitted provided that the following conditions
  37  * are met:
  38  * 1. Redistributions of source code must retain the above copyright
  39  *    notice, this list of conditions and the following disclaimer.
  40  * 2. Redistributions in binary form must reproduce the above copyright
  41  *    notice, this list of conditions and the following disclaimer in the
  42  *    documentation and/or other materials provided with the distribution.
  43  * 3. Neither the name of the copyright holders nor the names of its
  44  *    contributors may be used to endorse or promote products derived from
  45  *    this software without specific prior written permission.
  46  *
  47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  57  * THE POSSIBILITY OF SUCH DAMAGE.
  58  */
  59 package jdk.internal.org.objectweb.asm.util;
  60 
  61 import java.io.PrintWriter;
  62 import java.io.StringWriter;
  63 import java.util.ArrayList;
  64 import java.util.HashMap;
  65 import java.util.HashSet;
  66 import java.util.List;
  67 import java.util.Map;
  68 import java.util.Set;
  69 import jdk.internal.org.objectweb.asm.AnnotationVisitor;
  70 import jdk.internal.org.objectweb.asm.Attribute;
  71 import jdk.internal.org.objectweb.asm.ConstantDynamic;
  72 import jdk.internal.org.objectweb.asm.Handle;
  73 import jdk.internal.org.objectweb.asm.Label;
  74 import jdk.internal.org.objectweb.asm.MethodVisitor;
  75 import jdk.internal.org.objectweb.asm.Opcodes;
  76 import jdk.internal.org.objectweb.asm.Type;
  77 import jdk.internal.org.objectweb.asm.TypePath;
  78 import jdk.internal.org.objectweb.asm.TypeReference;
  79 import jdk.internal.org.objectweb.asm.tree.MethodNode;
  80 import jdk.internal.org.objectweb.asm.tree.analysis.Analyzer;
  81 import jdk.internal.org.objectweb.asm.tree.analysis.AnalyzerException;
  82 import jdk.internal.org.objectweb.asm.tree.analysis.BasicValue;
  83 import jdk.internal.org.objectweb.asm.tree.analysis.BasicVerifier;
  84 
  85 /**
  86  * A {@link MethodVisitor} that checks that its methods are properly used. More precisely this
  87  * method adapter checks each instruction individually, i.e., each visit method checks some
  88  * preconditions based <i>only</i> on its arguments - such as the fact that the given opcode is
  89  * correct for a given visit method. This adapter can also perform some basic data flow checks (more
  90  * precisely those that can be performed without the full class hierarchy - see {@link
  91  * jdk.internal.org.objectweb.asm.tree.analysis.BasicVerifier}). For instance in a method whose signature is
  92  * {@code void m ()}, the invalid instruction IRETURN, or the invalid sequence IADD L2I will be
  93  * detected if the data flow checks are enabled. These checks are enabled by using the {@link
  94  * #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor. They are not performed if
  95  * any other constructor is used.
  96  *
  97  * @author Eric Bruneton
  98  */
  99 public class CheckMethodAdapter extends MethodVisitor {
 100 
 101     /** The 'generic' instruction visit methods (i.e. those that take an opcode argument). */
 102     private enum Method {
 103         VISIT_INSN,
 104         VISIT_INT_INSN,
 105         VISIT_VAR_INSN,
 106         VISIT_TYPE_INSN,
 107         VISIT_FIELD_INSN,
 108         VISIT_METHOD_INSN,
 109         VISIT_JUMP_INSN
 110     }
 111 
 112     /** The method to use to visit each instruction. Only generic methods are represented here. */
 113     private static final Method[] OPCODE_METHODS = {
 114         Method.VISIT_INSN, // NOP
 115         Method.VISIT_INSN, // ACONST_NULL
 116         Method.VISIT_INSN, // ICONST_M1
 117         Method.VISIT_INSN, // ICONST_0
 118         Method.VISIT_INSN, // ICONST_1
 119         Method.VISIT_INSN, // ICONST_2
 120         Method.VISIT_INSN, // ICONST_3
 121         Method.VISIT_INSN, // ICONST_4
 122         Method.VISIT_INSN, // ICONST_5
 123         Method.VISIT_INSN, // LCONST_0
 124         Method.VISIT_INSN, // LCONST_1
 125         Method.VISIT_INSN, // FCONST_0
 126         Method.VISIT_INSN, // FCONST_1
 127         Method.VISIT_INSN, // FCONST_2
 128         Method.VISIT_INSN, // DCONST_0
 129         Method.VISIT_INSN, // DCONST_1
 130         Method.VISIT_INT_INSN, // BIPUSH
 131         Method.VISIT_INT_INSN, // SIPUSH
 132         null, // LDC
 133         null, // LDC_W
 134         null, // LDC2_W
 135         Method.VISIT_VAR_INSN, // ILOAD
 136         Method.VISIT_VAR_INSN, // LLOAD
 137         Method.VISIT_VAR_INSN, // FLOAD
 138         Method.VISIT_VAR_INSN, // DLOAD
 139         Method.VISIT_VAR_INSN, // ALOAD
 140         null, // ILOAD_0
 141         null, // ILOAD_1
 142         null, // ILOAD_2
 143         null, // ILOAD_3
 144         null, // LLOAD_0
 145         null, // LLOAD_1
 146         null, // LLOAD_2
 147         null, // LLOAD_3
 148         null, // FLOAD_0
 149         null, // FLOAD_1
 150         null, // FLOAD_2
 151         null, // FLOAD_3
 152         null, // DLOAD_0
 153         null, // DLOAD_1
 154         null, // DLOAD_2
 155         null, // DLOAD_3
 156         null, // ALOAD_0
 157         null, // ALOAD_1
 158         null, // ALOAD_2
 159         null, // ALOAD_3
 160         Method.VISIT_INSN, // IALOAD
 161         Method.VISIT_INSN, // LALOAD
 162         Method.VISIT_INSN, // FALOAD
 163         Method.VISIT_INSN, // DALOAD
 164         Method.VISIT_INSN, // AALOAD
 165         Method.VISIT_INSN, // BALOAD
 166         Method.VISIT_INSN, // CALOAD
 167         Method.VISIT_INSN, // SALOAD
 168         Method.VISIT_VAR_INSN, // ISTORE
 169         Method.VISIT_VAR_INSN, // LSTORE
 170         Method.VISIT_VAR_INSN, // FSTORE
 171         Method.VISIT_VAR_INSN, // DSTORE
 172         Method.VISIT_VAR_INSN, // ASTORE
 173         null, // ISTORE_0
 174         null, // ISTORE_1
 175         null, // ISTORE_2
 176         null, // ISTORE_3
 177         null, // LSTORE_0
 178         null, // LSTORE_1
 179         null, // LSTORE_2
 180         null, // LSTORE_3
 181         null, // FSTORE_0
 182         null, // FSTORE_1
 183         null, // FSTORE_2
 184         null, // FSTORE_3
 185         null, // DSTORE_0
 186         null, // DSTORE_1
 187         null, // DSTORE_2
 188         null, // DSTORE_3
 189         null, // ASTORE_0
 190         null, // ASTORE_1
 191         null, // ASTORE_2
 192         null, // ASTORE_3
 193         Method.VISIT_INSN, // IASTORE
 194         Method.VISIT_INSN, // LASTORE
 195         Method.VISIT_INSN, // FASTORE
 196         Method.VISIT_INSN, // DASTORE
 197         Method.VISIT_INSN, // AASTORE
 198         Method.VISIT_INSN, // BASTORE
 199         Method.VISIT_INSN, // CASTORE
 200         Method.VISIT_INSN, // SASTORE
 201         Method.VISIT_INSN, // POP
 202         Method.VISIT_INSN, // POP2
 203         Method.VISIT_INSN, // DUP
 204         Method.VISIT_INSN, // DUP_X1
 205         Method.VISIT_INSN, // DUP_X2
 206         Method.VISIT_INSN, // DUP2
 207         Method.VISIT_INSN, // DUP2_X1
 208         Method.VISIT_INSN, // DUP2_X2
 209         Method.VISIT_INSN, // SWAP
 210         Method.VISIT_INSN, // IADD
 211         Method.VISIT_INSN, // LADD
 212         Method.VISIT_INSN, // FADD
 213         Method.VISIT_INSN, // DADD
 214         Method.VISIT_INSN, // ISUB
 215         Method.VISIT_INSN, // LSUB
 216         Method.VISIT_INSN, // FSUB
 217         Method.VISIT_INSN, // DSUB
 218         Method.VISIT_INSN, // IMUL
 219         Method.VISIT_INSN, // LMUL
 220         Method.VISIT_INSN, // FMUL
 221         Method.VISIT_INSN, // DMUL
 222         Method.VISIT_INSN, // IDIV
 223         Method.VISIT_INSN, // LDIV
 224         Method.VISIT_INSN, // FDIV
 225         Method.VISIT_INSN, // DDIV
 226         Method.VISIT_INSN, // IREM
 227         Method.VISIT_INSN, // LREM
 228         Method.VISIT_INSN, // FREM
 229         Method.VISIT_INSN, // DREM
 230         Method.VISIT_INSN, // INEG
 231         Method.VISIT_INSN, // LNEG
 232         Method.VISIT_INSN, // FNEG
 233         Method.VISIT_INSN, // DNEG
 234         Method.VISIT_INSN, // ISHL
 235         Method.VISIT_INSN, // LSHL
 236         Method.VISIT_INSN, // ISHR
 237         Method.VISIT_INSN, // LSHR
 238         Method.VISIT_INSN, // IUSHR
 239         Method.VISIT_INSN, // LUSHR
 240         Method.VISIT_INSN, // IAND
 241         Method.VISIT_INSN, // LAND
 242         Method.VISIT_INSN, // IOR
 243         Method.VISIT_INSN, // LOR
 244         Method.VISIT_INSN, // IXOR
 245         Method.VISIT_INSN, // LXOR
 246         null, // IINC
 247         Method.VISIT_INSN, // I2L
 248         Method.VISIT_INSN, // I2F
 249         Method.VISIT_INSN, // I2D
 250         Method.VISIT_INSN, // L2I
 251         Method.VISIT_INSN, // L2F
 252         Method.VISIT_INSN, // L2D
 253         Method.VISIT_INSN, // F2I
 254         Method.VISIT_INSN, // F2L
 255         Method.VISIT_INSN, // F2D
 256         Method.VISIT_INSN, // D2I
 257         Method.VISIT_INSN, // D2L
 258         Method.VISIT_INSN, // D2F
 259         Method.VISIT_INSN, // I2B
 260         Method.VISIT_INSN, // I2C
 261         Method.VISIT_INSN, // I2S
 262         Method.VISIT_INSN, // LCMP
 263         Method.VISIT_INSN, // FCMPL
 264         Method.VISIT_INSN, // FCMPG
 265         Method.VISIT_INSN, // DCMPL
 266         Method.VISIT_INSN, // DCMPG
 267         Method.VISIT_JUMP_INSN, // IFEQ
 268         Method.VISIT_JUMP_INSN, // IFNE
 269         Method.VISIT_JUMP_INSN, // IFLT
 270         Method.VISIT_JUMP_INSN, // IFGE
 271         Method.VISIT_JUMP_INSN, // IFGT
 272         Method.VISIT_JUMP_INSN, // IFLE
 273         Method.VISIT_JUMP_INSN, // IF_ICMPEQ
 274         Method.VISIT_JUMP_INSN, // IF_ICMPNE
 275         Method.VISIT_JUMP_INSN, // IF_ICMPLT
 276         Method.VISIT_JUMP_INSN, // IF_ICMPGE
 277         Method.VISIT_JUMP_INSN, // IF_ICMPGT
 278         Method.VISIT_JUMP_INSN, // IF_ICMPLE
 279         Method.VISIT_JUMP_INSN, // IF_ACMPEQ
 280         Method.VISIT_JUMP_INSN, // IF_ACMPNE
 281         Method.VISIT_JUMP_INSN, // GOTO
 282         Method.VISIT_JUMP_INSN, // JSR
 283         Method.VISIT_VAR_INSN, // RET
 284         null, // TABLESWITCH
 285         null, // LOOKUPSWITCH
 286         Method.VISIT_INSN, // IRETURN
 287         Method.VISIT_INSN, // LRETURN
 288         Method.VISIT_INSN, // FRETURN
 289         Method.VISIT_INSN, // DRETURN
 290         Method.VISIT_INSN, // ARETURN
 291         Method.VISIT_INSN, // RETURN
 292         Method.VISIT_FIELD_INSN, // GETSTATIC
 293         Method.VISIT_FIELD_INSN, // PUTSTATIC
 294         Method.VISIT_FIELD_INSN, // GETFIELD
 295         Method.VISIT_FIELD_INSN, // PUTFIELD
 296         Method.VISIT_METHOD_INSN, // INVOKEVIRTUAL
 297         Method.VISIT_METHOD_INSN, // INVOKESPECIAL
 298         Method.VISIT_METHOD_INSN, // INVOKESTATIC
 299         Method.VISIT_METHOD_INSN, // INVOKEINTERFACE
 300         null, // INVOKEDYNAMIC
 301         Method.VISIT_TYPE_INSN, // NEW
 302         Method.VISIT_INT_INSN, // NEWARRAY
 303         Method.VISIT_TYPE_INSN, // ANEWARRAY
 304         Method.VISIT_INSN, // ARRAYLENGTH
 305         Method.VISIT_INSN, // ATHROW
 306         Method.VISIT_TYPE_INSN, // CHECKCAST
 307         Method.VISIT_TYPE_INSN, // INSTANCEOF
 308         Method.VISIT_INSN, // MONITORENTER
 309         Method.VISIT_INSN, // MONITOREXIT
 310         null, // WIDE
 311         null, // MULTIANEWARRAY
 312         Method.VISIT_JUMP_INSN, // IFNULL
 313         Method.VISIT_JUMP_INSN // IFNONNULL
 314     };
 315 
 316     private static final String INVALID = "Invalid ";
 317     private static final String INVALID_DESCRIPTOR = "Invalid descriptor: ";
 318     private static final String INVALID_TYPE_REFERENCE = "Invalid type reference sort 0x";
 319     private static final String INVALID_LOCAL_VARIABLE_INDEX = "Invalid local variable index";
 320     private static final String MUST_NOT_BE_NULL_OR_EMPTY = " (must not be null or empty)";
 321     private static final String START_LABEL = "start label";
 322     private static final String END_LABEL = "end label";
 323 
 324     /** The class version number. */
 325     public int version;
 326 
 327     /** The access flags of the visited method. */
 328     private int access;
 329 
 330     /**
 331       * The number of method parameters that can have runtime visible annotations. 0 means that all the
 332       * parameters from the method descriptor can have annotations.
 333       */
 334     private int visibleAnnotableParameterCount;
 335 
 336     /**
 337       * The number of method parameters that can have runtime invisible annotations. 0 means that all
 338       * the parameters from the method descriptor can have annotations.
 339       */
 340     private int invisibleAnnotableParameterCount;
 341 
 342     /** Whether the {@link #visitCode} method has been called. */
 343     private boolean visitCodeCalled;
 344 
 345     /** Whether the {@link #visitMaxs} method has been called. */
 346     private boolean visitMaxCalled;
 347 
 348     /** Whether the {@link #visitEnd} method has been called. */
 349     private boolean visitEndCalled;
 350 
 351     /** The number of visited instructions so far. */
 352     private int insnCount;
 353 
 354     /** The index of the instruction designated by each visited label. */
 355     private final Map<Label, Integer> labelInsnIndices;
 356 
 357     /** The labels referenced by the visited method. */
 358     private Set<Label> referencedLabels;
 359 
 360     /** The index of the instruction corresponding to the last visited stack map frame. */
 361     private int lastFrameInsnIndex = -1;
 362 
 363     /** The number of visited frames in expanded form. */
 364     private int numExpandedFrames;
 365 
 366     /** The number of visited frames in compressed form. */
 367     private int numCompressedFrames;
 368 
 369     /**
 370       * The exception handler ranges. Each pair of list element contains the start and end labels of an
 371       * exception handler block.
 372       */
 373     private List<Label> handlers;
 374 
 375     /**
 376       * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
 377       * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
 378       * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
 379       * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
 380       *
 381       * @param methodvisitor the method visitor to which this adapter must delegate calls.
 382       */
 383     public CheckMethodAdapter(final MethodVisitor methodvisitor) {
 384         this(methodvisitor, new HashMap<Label, Integer>());
 385     }
 386 
 387     /**
 388       * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
 389       * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
 390       * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
 391       * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
 392       *
 393       * @param methodVisitor the method visitor to which this adapter must delegate calls.
 394       * @param labelInsnIndices the index of the instruction designated by each visited label so far
 395       *     (in other methods). This map is updated with the labels from the visited method.
 396       * @throws IllegalStateException If a subclass calls this constructor.
 397       */
 398     public CheckMethodAdapter(
 399             final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) {
 400         this(Opcodes.ASM7, methodVisitor, labelInsnIndices);
 401         if (getClass() != CheckMethodAdapter.class) {
 402             throw new IllegalStateException();
 403         }
 404     }
 405 
 406     /**
 407       * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
 408       * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
 409       *
 410       * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
 411       *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
 412       * @param methodVisitor the method visitor to which this adapter must delegate calls.
 413       * @param labelInsnIndices the index of the instruction designated by each visited label so far
 414       *     (in other methods). This map is updated with the labels from the visited method.
 415       */
 416     protected CheckMethodAdapter(
 417             final int api,
 418             final MethodVisitor methodVisitor,
 419             final Map<Label, Integer> labelInsnIndices) {
 420         super(api, methodVisitor);
 421         this.labelInsnIndices = labelInsnIndices;
 422         this.referencedLabels = new HashSet<Label>();
 423         this.handlers = new ArrayList<Label>();
 424     }
 425 
 426     /**
 427       * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
 428       * flow checks. For instance in a method whose signature is {@code void m ()}, the invalid
 429       * instruction IRETURN, or the invalid sequence IADD L2I will be detected. <i>Subclasses must not
 430       * use this constructor</i>. Instead, they must use the {@link
 431       * #CheckMethodAdapter(int,int,String,String,MethodVisitor,Map)} version.
 432       *
 433       * @param access the method's access flags.
 434       * @param name the method's name.
 435       * @param descriptor the method's descriptor (see {@link Type}).
 436       * @param methodVisitor the method visitor to which this adapter must delegate calls.
 437       * @param labelInsnIndices the index of the instruction designated by each visited label so far
 438       *     (in other methods). This map is updated with the labels from the visited method.
 439       */
 440     public CheckMethodAdapter(
 441             final int access,
 442             final String name,
 443             final String descriptor,
 444             final MethodVisitor methodVisitor,
 445             final Map<Label, Integer> labelInsnIndices) {
 446         this(Opcodes.ASM7, access, name, descriptor, methodVisitor, labelInsnIndices);
 447         if (getClass() != CheckMethodAdapter.class) {
 448             throw new IllegalStateException();
 449         }
 450     }
 451 
 452     /**
 453       * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
 454       * flow checks. For instance in a method whose signature is {@code void m ()}, the invalid
 455       * instruction IRETURN, or the invalid sequence IADD L2I will be detected.
 456       *
 457       * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
 458       *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
 459       * @param access the method's access flags.
 460       * @param name the method's name.
 461       * @param descriptor the method's descriptor (see {@link Type}).
 462       * @param methodVisitor the method visitor to which this adapter must delegate calls.
 463       * @param labelInsnIndices the index of the instruction designated by each visited label so far
 464       *     (in other methods). This map is updated with the labels from the visited method.
 465       */
 466     protected CheckMethodAdapter(
 467             final int api,
 468             final int access,
 469             final String name,
 470             final String descriptor,
 471             final MethodVisitor methodVisitor,
 472             final Map<Label, Integer> labelInsnIndices) {
 473         this(
 474                 api,
 475                 new MethodNode(api, access, name, descriptor, null, null) {
 476                     @Override
 477                     public void visitEnd() {
 478                         Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier());
 479                         try {
 480                             analyzer.analyze("dummy", this);
 481                         } catch (IndexOutOfBoundsException e) {
 482                             if (maxLocals == 0 && maxStack == 0) {
 483                                 throw new IllegalArgumentException(
 484                                         "Data flow checking option requires valid, non zero maxLocals and maxStack.",
 485                                         e);
 486                             }
 487                             throwError(analyzer, e);
 488                         } catch (AnalyzerException e) {
 489                             throwError(analyzer, e);
 490                         }
 491                         accept(methodVisitor);
 492                     }
 493 
 494                     private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) {
 495                         StringWriter stringWriter = new StringWriter();
 496                         PrintWriter printWriter = new PrintWriter(stringWriter, true);
 497                         CheckClassAdapter.printAnalyzerResult(this, analyzer, printWriter);
 498                         printWriter.close();
 499                         throw new IllegalArgumentException(e.getMessage() + ' ' + stringWriter.toString(), e);
 500                     }
 501                 },
 502                 labelInsnIndices);
 503         this.access = access;
 504     }
 505 
 506     @Override
 507     public void visitParameter(final String name, final int access) {
 508         if (name != null) {
 509             checkUnqualifiedName(version, name, "name");
 510         }
 511         CheckClassAdapter.checkAccess(
 512                 access, Opcodes.ACC_FINAL + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
 513         super.visitParameter(name, access);
 514     }
 515 
 516     @Override
 517     public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
 518         checkVisitEndNotCalled();
 519         checkDescriptor(version, descriptor, false);
 520         return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
 521     }
 522 
 523     @Override
 524     public AnnotationVisitor visitTypeAnnotation(
 525             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
 526         checkVisitEndNotCalled();
 527         int sort = new TypeReference(typeRef).getSort();
 528         if (sort != TypeReference.METHOD_TYPE_PARAMETER
 529                 && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
 530                 && sort != TypeReference.METHOD_RETURN
 531                 && sort != TypeReference.METHOD_RECEIVER
 532                 && sort != TypeReference.METHOD_FORMAL_PARAMETER
 533                 && sort != TypeReference.THROWS) {
 534             throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
 535         }
 536         CheckClassAdapter.checkTypeRef(typeRef);
 537         CheckMethodAdapter.checkDescriptor(version, descriptor, false);
 538         return new CheckAnnotationAdapter(
 539                 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
 540     }
 541 
 542     @Override
 543     public AnnotationVisitor visitAnnotationDefault() {
 544         checkVisitEndNotCalled();
 545         return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
 546     }
 547 
 548     @Override
 549     public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
 550         checkVisitEndNotCalled();
 551         if (visible) {
 552             visibleAnnotableParameterCount = parameterCount;
 553         } else {
 554             invisibleAnnotableParameterCount = parameterCount;
 555         }
 556         super.visitAnnotableParameterCount(parameterCount, visible);
 557     }
 558 
 559     @Override
 560     public AnnotationVisitor visitParameterAnnotation(
 561             final int parameter, final String descriptor, final boolean visible) {
 562         checkVisitEndNotCalled();
 563         if ((visible
 564                         && visibleAnnotableParameterCount > 0
 565                         && parameter >= visibleAnnotableParameterCount)
 566                 || (!visible
 567                         && invisibleAnnotableParameterCount > 0
 568                         && parameter >= invisibleAnnotableParameterCount)) {
 569             throw new IllegalArgumentException("Invalid parameter index");
 570         }
 571         checkDescriptor(version, descriptor, false);
 572         return new CheckAnnotationAdapter(
 573                 super.visitParameterAnnotation(parameter, descriptor, visible));
 574     }
 575 
 576     @Override
 577     public void visitAttribute(final Attribute attribute) {
 578         checkVisitEndNotCalled();
 579         if (attribute == null) {
 580             throw new IllegalArgumentException("Invalid attribute (must not be null)");
 581         }
 582         super.visitAttribute(attribute);
 583     }
 584 
 585     @Override
 586     public void visitCode() {
 587         if ((access & Opcodes.ACC_ABSTRACT) != 0) {
 588             throw new UnsupportedOperationException("Abstract methods cannot have code");
 589         }
 590         visitCodeCalled = true;
 591         super.visitCode();
 592     }
 593 
 594     @Override
 595     public void visitFrame(
 596             final int type,
 597             final int numLocal,
 598             final Object[] local,
 599             final int numStack,
 600             final Object[] stack) {
 601         if (insnCount == lastFrameInsnIndex) {
 602             throw new IllegalStateException("At most one frame can be visited at a given code location.");
 603         }
 604         lastFrameInsnIndex = insnCount;
 605         int maxNumLocal;
 606         int maxNumStack;
 607         switch (type) {
 608             case Opcodes.F_NEW:
 609             case Opcodes.F_FULL:
 610                 maxNumLocal = Integer.MAX_VALUE;
 611                 maxNumStack = Integer.MAX_VALUE;
 612                 break;
 613 
 614             case Opcodes.F_SAME:
 615                 maxNumLocal = 0;
 616                 maxNumStack = 0;
 617                 break;
 618 
 619             case Opcodes.F_SAME1:
 620                 maxNumLocal = 0;
 621                 maxNumStack = 1;
 622                 break;
 623 
 624             case Opcodes.F_APPEND:
 625             case Opcodes.F_CHOP:
 626                 maxNumLocal = 3;
 627                 maxNumStack = 0;
 628                 break;
 629 
 630             default:
 631                 throw new IllegalArgumentException("Invalid frame type " + type);
 632         }
 633 
 634         if (numLocal > maxNumLocal) {
 635             throw new IllegalArgumentException(
 636                     "Invalid numLocal=" + numLocal + " for frame type " + type);
 637         }
 638         if (numStack > maxNumStack) {
 639             throw new IllegalArgumentException(
 640                     "Invalid numStack=" + numStack + " for frame type " + type);
 641         }
 642 
 643         if (type != Opcodes.F_CHOP) {
 644             if (numLocal > 0 && (local == null || local.length < numLocal)) {
 645                 throw new IllegalArgumentException("Array local[] is shorter than numLocal");
 646             }
 647             for (int i = 0; i < numLocal; ++i) {
 648                 checkFrameValue(local[i]);
 649             }
 650         }
 651         if (numStack > 0 && (stack == null || stack.length < numStack)) {
 652             throw new IllegalArgumentException("Array stack[] is shorter than numStack");
 653         }
 654         for (int i = 0; i < numStack; ++i) {
 655             checkFrameValue(stack[i]);
 656         }
 657         if (type == Opcodes.F_NEW) {
 658             ++numExpandedFrames;
 659         } else {
 660             ++numCompressedFrames;
 661         }
 662         if (numExpandedFrames > 0 && numCompressedFrames > 0) {
 663             throw new IllegalArgumentException("Expanded and compressed frames must not be mixed.");
 664         }
 665         super.visitFrame(type, numLocal, local, numStack, stack);
 666     }
 667 
 668     @Override
 669     public void visitInsn(final int opcode) {
 670         checkVisitCodeCalled();
 671         checkVisitMaxsNotCalled();
 672         checkOpcodeMethod(opcode, Method.VISIT_INSN);
 673         super.visitInsn(opcode);
 674         ++insnCount;
 675     }
 676 
 677     @Override
 678     public void visitIntInsn(final int opcode, final int operand) {
 679         checkVisitCodeCalled();
 680         checkVisitMaxsNotCalled();
 681         checkOpcodeMethod(opcode, Method.VISIT_INT_INSN);
 682         switch (opcode) {
 683             case Opcodes.BIPUSH:
 684                 checkSignedByte(operand, "Invalid operand");
 685                 break;
 686             case Opcodes.SIPUSH:
 687                 checkSignedShort(operand, "Invalid operand");
 688                 break;
 689             case Opcodes.NEWARRAY:
 690                 if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
 691                     throw new IllegalArgumentException(
 692                             "Invalid operand (must be an array type code T_...): " + operand);
 693                 }
 694                 break;
 695             default:
 696                 throw new AssertionError();
 697         }
 698         super.visitIntInsn(opcode, operand);
 699         ++insnCount;
 700     }
 701 
 702     @Override
 703     public void visitVarInsn(final int opcode, final int var) {
 704         checkVisitCodeCalled();
 705         checkVisitMaxsNotCalled();
 706         checkOpcodeMethod(opcode, Method.VISIT_VAR_INSN);
 707         checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
 708         super.visitVarInsn(opcode, var);
 709         ++insnCount;
 710     }
 711 
 712     @Override
 713     public void visitTypeInsn(final int opcode, final String type) {
 714         checkVisitCodeCalled();
 715         checkVisitMaxsNotCalled();
 716         checkOpcodeMethod(opcode, Method.VISIT_TYPE_INSN);
 717         checkInternalName(version, type, "type");
 718         if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
 719             throw new IllegalArgumentException("NEW cannot be used to create arrays: " + type);
 720         }
 721         super.visitTypeInsn(opcode, type);
 722         ++insnCount;
 723     }
 724 
 725     @Override
 726     public void visitFieldInsn(
 727             final int opcode, final String owner, final String name, final String descriptor) {
 728         checkVisitCodeCalled();
 729         checkVisitMaxsNotCalled();
 730         checkOpcodeMethod(opcode, Method.VISIT_FIELD_INSN);
 731         checkInternalName(version, owner, "owner");
 732         checkUnqualifiedName(version, name, "name");
 733         checkDescriptor(version, descriptor, false);
 734         super.visitFieldInsn(opcode, owner, name, descriptor);
 735         ++insnCount;
 736     }
 737 
 738     /**
 739       * Deprecated.
 740       *
 741       * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
 742       */
 743     @Deprecated
 744     @Override
 745     public void visitMethodInsn(
 746             final int opcode, final String owner, final String name, final String descriptor) {
 747         if (api >= Opcodes.ASM5) {
 748             super.visitMethodInsn(opcode, owner, name, descriptor);
 749             return;
 750         }
 751         doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
 752     }
 753 
 754     @Override
 755     public void visitMethodInsn(
 756             final int opcode,
 757             final String owner,
 758             final String name,
 759             final String descriptor,
 760             final boolean isInterface) {
 761         if (api < Opcodes.ASM5) {
 762             super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
 763             return;
 764         }
 765         doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
 766     }
 767 
 768     private void doVisitMethodInsn(
 769             final int opcode,
 770             final String owner,
 771             final String name,
 772             final String descriptor,
 773             final boolean isInterface) {
 774         checkVisitCodeCalled();
 775         checkVisitMaxsNotCalled();
 776         checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
 777         if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
 778             checkMethodIdentifier(version, name, "name");
 779         }
 780         checkInternalName(version, owner, "owner");
 781         checkMethodDescriptor(version, descriptor);
 782         if (opcode == Opcodes.INVOKEVIRTUAL && isInterface) {
 783             throw new IllegalArgumentException("INVOKEVIRTUAL can't be used with interfaces");
 784         }
 785         if (opcode == Opcodes.INVOKEINTERFACE && !isInterface) {
 786             throw new IllegalArgumentException("INVOKEINTERFACE can't be used with classes");
 787         }
 788         if (opcode == Opcodes.INVOKESPECIAL && isInterface && (version & 0xFFFF) < Opcodes.V1_8) {
 789             throw new IllegalArgumentException(
 790                     "INVOKESPECIAL can't be used with interfaces prior to Java 8");
 791         }
 792 
 793         // Calling super.visitMethodInsn requires to call the correct version depending on this.api
 794         // (otherwise infinite loops can occur). To simplify and to make it easier to automatically
 795         // remove the backward compatibility code, we inline the code of the overridden method here.
 796         if (mv != null) {
 797             mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
 798         }
 799         ++insnCount;
 800     }
 801 
 802     @Override
 803     public void visitInvokeDynamicInsn(
 804             final String name,
 805             final String descriptor,
 806             final Handle bootstrapMethodHandle,
 807             final Object... bootstrapMethodArguments) {
 808         checkVisitCodeCalled();
 809         checkVisitMaxsNotCalled();
 810         checkMethodIdentifier(version, name, "name");
 811         checkMethodDescriptor(version, descriptor);
 812         if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
 813                 && bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
 814             throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
 815         }
 816         for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
 817             checkLdcConstant(bootstrapMethodArgument);
 818         }
 819         super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
 820         ++insnCount;
 821     }
 822 
 823     @Override
 824     public void visitJumpInsn(final int opcode, final Label label) {
 825         checkVisitCodeCalled();
 826         checkVisitMaxsNotCalled();
 827         checkOpcodeMethod(opcode, Method.VISIT_JUMP_INSN);
 828         checkLabel(label, false, "label");
 829         super.visitJumpInsn(opcode, label);
 830         referencedLabels.add(label);
 831         ++insnCount;
 832     }
 833 
 834     @Override
 835     public void visitLabel(final Label label) {
 836         checkVisitCodeCalled();
 837         checkVisitMaxsNotCalled();
 838         checkLabel(label, false, "label");
 839         if (labelInsnIndices.get(label) != null) {
 840             throw new IllegalArgumentException("Already visited label");
 841         }
 842         labelInsnIndices.put(label, insnCount);
 843         super.visitLabel(label);
 844     }
 845 
 846     @Override
 847     public void visitLdcInsn(final Object value) {
 848         checkVisitCodeCalled();
 849         checkVisitMaxsNotCalled();
 850         checkLdcConstant(value);
 851         super.visitLdcInsn(value);
 852         ++insnCount;
 853     }
 854 
 855     @Override
 856     public void visitIincInsn(final int var, final int increment) {
 857         checkVisitCodeCalled();
 858         checkVisitMaxsNotCalled();
 859         checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
 860         checkSignedShort(increment, "Invalid increment");
 861         super.visitIincInsn(var, increment);
 862         ++insnCount;
 863     }
 864 
 865     @Override
 866     public void visitTableSwitchInsn(
 867             final int min, final int max, final Label dflt, final Label... labels) {
 868         checkVisitCodeCalled();
 869         checkVisitMaxsNotCalled();
 870         if (max < min) {
 871             throw new IllegalArgumentException(
 872                     "Max = " + max + " must be greater than or equal to min = " + min);
 873         }
 874         checkLabel(dflt, false, "default label");
 875         if (labels == null || labels.length != max - min + 1) {
 876             throw new IllegalArgumentException("There must be max - min + 1 labels");
 877         }
 878         for (int i = 0; i < labels.length; ++i) {
 879             checkLabel(labels[i], false, "label at index " + i);
 880         }
 881         super.visitTableSwitchInsn(min, max, dflt, labels);
 882         for (Label label : labels) {
 883             referencedLabels.add(label);
 884         }
 885         ++insnCount;
 886     }
 887 
 888     @Override
 889     public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
 890         checkVisitMaxsNotCalled();
 891         checkVisitCodeCalled();
 892         checkLabel(dflt, false, "default label");
 893         if (keys == null || labels == null || keys.length != labels.length) {
 894             throw new IllegalArgumentException("There must be the same number of keys and labels");
 895         }
 896         for (int i = 0; i < labels.length; ++i) {
 897             checkLabel(labels[i], false, "label at index " + i);
 898         }
 899         super.visitLookupSwitchInsn(dflt, keys, labels);
 900         referencedLabels.add(dflt);
 901         for (Label label : labels) {
 902             referencedLabels.add(label);
 903         }
 904         ++insnCount;
 905     }
 906 
 907     @Override
 908     public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
 909         checkVisitCodeCalled();
 910         checkVisitMaxsNotCalled();
 911         checkDescriptor(version, descriptor, false);
 912         if (descriptor.charAt(0) != '[') {
 913             throw new IllegalArgumentException(
 914                     "Invalid descriptor (must be an array type descriptor): " + descriptor);
 915         }
 916         if (numDimensions < 1) {
 917             throw new IllegalArgumentException(
 918                     "Invalid dimensions (must be greater than 0): " + numDimensions);
 919         }
 920         if (numDimensions > descriptor.lastIndexOf('[') + 1) {
 921             throw new IllegalArgumentException(
 922                     "Invalid dimensions (must not be greater than numDimensions(descriptor)): "
 923                             + numDimensions);
 924         }
 925         super.visitMultiANewArrayInsn(descriptor, numDimensions);
 926         ++insnCount;
 927     }
 928 
 929     @Override
 930     public AnnotationVisitor visitInsnAnnotation(
 931             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
 932         checkVisitCodeCalled();
 933         checkVisitMaxsNotCalled();
 934         int sort = new TypeReference(typeRef).getSort();
 935         if (sort != TypeReference.INSTANCEOF
 936                 && sort != TypeReference.NEW
 937                 && sort != TypeReference.CONSTRUCTOR_REFERENCE
 938                 && sort != TypeReference.METHOD_REFERENCE
 939                 && sort != TypeReference.CAST
 940                 && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
 941                 && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
 942                 && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
 943                 && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
 944             throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
 945         }
 946         CheckClassAdapter.checkTypeRef(typeRef);
 947         CheckMethodAdapter.checkDescriptor(version, descriptor, false);
 948         return new CheckAnnotationAdapter(
 949                 super.visitInsnAnnotation(typeRef, typePath, descriptor, visible));
 950     }
 951 
 952     @Override
 953     public void visitTryCatchBlock(
 954             final Label start, final Label end, final Label handler, final String type) {
 955         checkVisitCodeCalled();
 956         checkVisitMaxsNotCalled();
 957         checkLabel(start, false, START_LABEL);
 958         checkLabel(end, false, END_LABEL);
 959         checkLabel(handler, false, "handler label");
 960         if (labelInsnIndices.get(start) != null
 961                 || labelInsnIndices.get(end) != null
 962                 || labelInsnIndices.get(handler) != null) {
 963             throw new IllegalStateException("Try catch blocks must be visited before their labels");
 964         }
 965         if (type != null) {
 966             checkInternalName(version, type, "type");
 967         }
 968         super.visitTryCatchBlock(start, end, handler, type);
 969         handlers.add(start);
 970         handlers.add(end);
 971     }
 972 
 973     @Override
 974     public AnnotationVisitor visitTryCatchAnnotation(
 975             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
 976         checkVisitCodeCalled();
 977         checkVisitMaxsNotCalled();
 978         int sort = new TypeReference(typeRef).getSort();
 979         if (sort != TypeReference.EXCEPTION_PARAMETER) {
 980             throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
 981         }
 982         CheckClassAdapter.checkTypeRef(typeRef);
 983         CheckMethodAdapter.checkDescriptor(version, descriptor, false);
 984         return new CheckAnnotationAdapter(
 985                 super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible));
 986     }
 987 
 988     @Override
 989     public void visitLocalVariable(
 990             final String name,
 991             final String descriptor,
 992             final String signature,
 993             final Label start,
 994             final Label end,
 995             final int index) {
 996         checkVisitCodeCalled();
 997         checkVisitMaxsNotCalled();
 998         checkUnqualifiedName(version, name, "name");
 999         checkDescriptor(version, descriptor, false);
1000         checkLabel(start, true, START_LABEL);
1001         checkLabel(end, true, END_LABEL);
1002         checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX);
1003         int startInsnIndex = labelInsnIndices.get(start).intValue();
1004         int endInsnIndex = labelInsnIndices.get(end).intValue();
1005         if (endInsnIndex < startInsnIndex) {
1006             throw new IllegalArgumentException(
1007                     "Invalid start and end labels (end must be greater than start)");
1008         }
1009         super.visitLocalVariable(name, descriptor, signature, start, end, index);
1010     }
1011 
1012     @Override
1013     public AnnotationVisitor visitLocalVariableAnnotation(
1014             final int typeRef,
1015             final TypePath typePath,
1016             final Label[] start,
1017             final Label[] end,
1018             final int[] index,
1019             final String descriptor,
1020             final boolean visible) {
1021         checkVisitCodeCalled();
1022         checkVisitMaxsNotCalled();
1023         int sort = new TypeReference(typeRef).getSort();
1024         if (sort != TypeReference.LOCAL_VARIABLE && sort != TypeReference.RESOURCE_VARIABLE) {
1025             throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
1026         }
1027         CheckClassAdapter.checkTypeRef(typeRef);
1028         checkDescriptor(version, descriptor, false);
1029         if (start == null
1030                 || end == null
1031                 || index == null
1032                 || end.length != start.length
1033                 || index.length != start.length) {
1034             throw new IllegalArgumentException(
1035                     "Invalid start, end and index arrays (must be non null and of identical length");
1036         }
1037         for (int i = 0; i < start.length; ++i) {
1038             checkLabel(start[i], true, START_LABEL);
1039             checkLabel(end[i], true, END_LABEL);
1040             checkUnsignedShort(index[i], INVALID_LOCAL_VARIABLE_INDEX);
1041             int startInsnIndex = labelInsnIndices.get(start[i]).intValue();
1042             int endInsnIndex = labelInsnIndices.get(end[i]).intValue();
1043             if (endInsnIndex < startInsnIndex) {
1044                 throw new IllegalArgumentException(
1045                         "Invalid start and end labels (end must be greater than start)");
1046             }
1047         }
1048         return super.visitLocalVariableAnnotation(
1049                 typeRef, typePath, start, end, index, descriptor, visible);
1050     }
1051 
1052     @Override
1053     public void visitLineNumber(final int line, final Label start) {
1054         checkVisitCodeCalled();
1055         checkVisitMaxsNotCalled();
1056         checkUnsignedShort(line, "Invalid line number");
1057         checkLabel(start, true, START_LABEL);
1058         super.visitLineNumber(line, start);
1059     }
1060 
1061     @Override
1062     public void visitMaxs(final int maxStack, final int maxLocals) {
1063         checkVisitCodeCalled();
1064         checkVisitMaxsNotCalled();
1065         visitMaxCalled = true;
1066         for (Label l : referencedLabels) {
1067             if (labelInsnIndices.get(l) == null) {
1068                 throw new IllegalStateException("Undefined label used");
1069             }
1070         }
1071         for (int i = 0; i < handlers.size(); i += 2) {
1072             Integer startInsnIndex = labelInsnIndices.get(handlers.get(i));
1073             Integer endInsnIndex = labelInsnIndices.get(handlers.get(i + 1));
1074             if (startInsnIndex == null || endInsnIndex == null) {
1075                 throw new IllegalStateException("Undefined try catch block labels");
1076             }
1077             if (endInsnIndex.intValue() <= startInsnIndex.intValue()) {
1078                 throw new IllegalStateException("Emty try catch block handler range");
1079             }
1080         }
1081         checkUnsignedShort(maxStack, "Invalid max stack");
1082         checkUnsignedShort(maxLocals, "Invalid max locals");
1083         super.visitMaxs(maxStack, maxLocals);
1084     }
1085 
1086     @Override
1087     public void visitEnd() {
1088         checkVisitEndNotCalled();
1089         visitEndCalled = true;
1090         super.visitEnd();
1091     }
1092 
1093     // -----------------------------------------------------------------------------------------------
1094     // Utility methods
1095     // -----------------------------------------------------------------------------------------------
1096 
1097     /** Checks that the {@link #visitCode} method has been called. */
1098     private void checkVisitCodeCalled() {
1099         if (!visitCodeCalled) {
1100             throw new IllegalStateException(
1101                     "Cannot visit instructions before visitCode has been called.");
1102         }
1103     }
1104 
1105     /** Checks that the {@link #visitMaxs} method has not been called. */
1106     private void checkVisitMaxsNotCalled() {
1107         if (visitMaxCalled) {
1108             throw new IllegalStateException("Cannot visit instructions after visitMaxs has been called.");
1109         }
1110     }
1111 
1112     /** Checks that the {@link #visitEnd} method has not been called. */
1113     private void checkVisitEndNotCalled() {
1114         if (visitEndCalled) {
1115             throw new IllegalStateException("Cannot visit elements after visitEnd has been called.");
1116         }
1117     }
1118 
1119     /**
1120       * Checks a stack frame value.
1121       *
1122       * @param value the value to be checked.
1123       */
1124     private void checkFrameValue(final Object value) {
1125         if (value == Opcodes.TOP
1126                 || value == Opcodes.INTEGER
1127                 || value == Opcodes.FLOAT
1128                 || value == Opcodes.LONG
1129                 || value == Opcodes.DOUBLE
1130                 || value == Opcodes.NULL
1131                 || value == Opcodes.UNINITIALIZED_THIS) {
1132             return;
1133         } else if (value instanceof String) {
1134             checkInternalName(version, (String) value, "Invalid stack frame value");
1135         } else if (value instanceof Label) {
1136             referencedLabels.add((Label) value);
1137         } else {
1138             throw new IllegalArgumentException("Invalid stack frame value: " + value);
1139         }
1140     }
1141 
1142     /**
1143       * Checks that the method to visit the given opcode is equal to the given method.
1144       *
1145       * @param opcode the opcode to be checked.
1146       * @param method the expected visit method.
1147       */
1148     private static void checkOpcodeMethod(final int opcode, final Method method) {
1149         if (opcode < Opcodes.NOP || opcode > Opcodes.IFNONNULL || OPCODE_METHODS[opcode] != method) {
1150             throw new IllegalArgumentException("Invalid opcode: " + opcode);
1151         }
1152     }
1153 
1154     /**
1155       * Checks that the given value is a signed byte.
1156       *
1157       * @param value the value to be checked.
1158       * @param message the message to use in case of error.
1159       */
1160     private static void checkSignedByte(final int value, final String message) {
1161         if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
1162             throw new IllegalArgumentException(message + " (must be a signed byte): " + value);
1163         }
1164     }
1165 
1166     /**
1167       * Checks that the given value is a signed short.
1168       *
1169       * @param value the value to be checked.
1170       * @param message the message to use in case of error.
1171       */
1172     private static void checkSignedShort(final int value, final String message) {
1173         if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
1174             throw new IllegalArgumentException(message + " (must be a signed short): " + value);
1175         }
1176     }
1177 
1178     /**
1179       * Checks that the given value is an unsigned short.
1180       *
1181       * @param value the value to be checked.
1182       * @param message the message to use in case of error.
1183       */
1184     private static void checkUnsignedShort(final int value, final String message) {
1185         if (value < 0 || value > 65535) {
1186             throw new IllegalArgumentException(message + " (must be an unsigned short): " + value);
1187         }
1188     }
1189 
1190     /**
1191       * Checks that the given value is an {@link Integer}, {@link Float}, {@link Long}, {@link Double}
1192       * or {@link String} value.
1193       *
1194       * @param value the value to be checked.
1195       */
1196     static void checkConstant(final Object value) {
1197         if (!(value instanceof Integer)
1198                 && !(value instanceof Float)
1199                 && !(value instanceof Long)
1200                 && !(value instanceof Double)
1201                 && !(value instanceof String)) {
1202             throw new IllegalArgumentException("Invalid constant: " + value);
1203         }
1204     }
1205 
1206     /**
1207       * Checks that the given value is a valid operand for the LDC instruction.
1208       *
1209       * @param value the value to be checked.
1210       */
1211     private void checkLdcConstant(final Object value) {
1212         if (value instanceof Type) {
1213             int sort = ((Type) value).getSort();
1214             if (sort != Type.OBJECT && sort != Type.ARRAY && sort != Type.METHOD) {
1215                 throw new IllegalArgumentException("Illegal LDC constant value");
1216             }
1217             if (sort != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
1218                 throw new IllegalArgumentException("ldc of a constant class requires at least version 1.5");
1219             }
1220             if (sort == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
1221                 throw new IllegalArgumentException("ldc of a method type requires at least version 1.7");
1222             }
1223         } else if (value instanceof Handle) {
1224             if ((version & 0xFFFF) < Opcodes.V1_7) {
1225                 throw new IllegalArgumentException("ldc of a Handle requires at least version 1.7");
1226             }
1227             Handle handle = (Handle) value;
1228             int tag = handle.getTag();
1229             if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
1230                 throw new IllegalArgumentException("invalid handle tag " + tag);
1231             }
1232             checkInternalName(this.version, handle.getOwner(), "handle owner");
1233             if (tag <= Opcodes.H_PUTSTATIC) {
1234                 checkDescriptor(this.version, handle.getDesc(), false);
1235             } else {
1236                 checkMethodDescriptor(this.version, handle.getDesc());
1237             }
1238             String handleName = handle.getName();
1239             if (!("<init>".equals(handleName) && tag == Opcodes.H_NEWINVOKESPECIAL)) {
1240                 checkMethodIdentifier(this.version, handleName, "handle name");
1241             }
1242         } else if (value instanceof ConstantDynamic) {
1243             if ((version & 0xFFFF) < Opcodes.V11) {
1244                 throw new IllegalArgumentException("ldc of a ConstantDynamic requires at least version 11");
1245             }
1246             ConstantDynamic constantDynamic = (ConstantDynamic) value;
1247             checkMethodIdentifier(this.version, constantDynamic.getName(), "constant dynamic name");
1248             checkDescriptor(this.version, constantDynamic.getDescriptor(), false);
1249             checkLdcConstant(constantDynamic.getBootstrapMethod());
1250             int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
1251             for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
1252                 checkLdcConstant(constantDynamic.getBootstrapMethodArgument(i));
1253             }
1254         } else {
1255             checkConstant(value);
1256         }
1257     }
1258 
1259     /**
1260       * Checks that the given string is a valid unqualified name.
1261       *
1262       * @param version the class version.
1263       * @param name the string to be checked.
1264       * @param message the message to use in case of error.
1265       */
1266     static void checkUnqualifiedName(final int version, final String name, final String message) {
1267         checkIdentifier(version, name, 0, -1, message);
1268     }
1269 
1270     /**
1271       * Checks that the given substring is a valid Java identifier.
1272       *
1273       * @param version the class version.
1274       * @param name the string to be checked.
1275       * @param startPos the index of the first character of the identifier (inclusive).
1276       * @param endPos the index of the last character of the identifier (exclusive). -1 is equivalent
1277       *     to {@code name.length()} if name is not {@literal null}.
1278       * @param message the message to use in case of error.
1279       */
1280     static void checkIdentifier(
1281             final int version,
1282             final String name,
1283             final int startPos,
1284             final int endPos,
1285             final String message) {
1286         if (name == null || (endPos == -1 ? name.length() <= startPos : endPos <= startPos)) {
1287             throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
1288         }
1289         int max = endPos == -1 ? name.length() : endPos;
1290         if ((version & 0xFFFF) >= Opcodes.V1_5) {
1291             for (int i = startPos; i < max; i = name.offsetByCodePoints(i, 1)) {
1292                 if (".;[/".indexOf(name.codePointAt(i)) != -1) {
1293                     throw new IllegalArgumentException(
1294                             INVALID + message + " (must not contain . ; [ or /): " + name);
1295                 }
1296             }
1297             return;
1298         }
1299         for (int i = startPos; i < max; i = name.offsetByCodePoints(i, 1)) {
1300             if (i == startPos
1301                     ? !Character.isJavaIdentifierStart(name.codePointAt(i))
1302                     : !Character.isJavaIdentifierPart(name.codePointAt(i))) {
1303                 throw new IllegalArgumentException(
1304                         INVALID + message + " (must be a valid Java identifier): " + name);
1305             }
1306         }
1307     }
1308 
1309     /**
1310       * Checks that the given string is a valid Java identifier.
1311       *
1312       * @param version the class version.
1313       * @param name the string to be checked.
1314       * @param message the message to use in case of error.
1315       */
1316     static void checkMethodIdentifier(final int version, final String name, final String message) {
1317         if (name == null || name.isEmpty()) {
1318             throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
1319         }
1320         if ((version & 0xFFFF) >= Opcodes.V1_5) {
1321             for (int i = 0; i < name.length(); i = name.offsetByCodePoints(i, 1)) {
1322                 if (".;[/<>".indexOf(name.codePointAt(i)) != -1) {
1323                     throw new IllegalArgumentException(
1324                             INVALID + message + " (must be a valid unqualified name): " + name);
1325                 }
1326             }
1327             return;
1328         }
1329         for (int i = 0; i < name.length(); i = name.offsetByCodePoints(i, 1)) {
1330             if (i == 0
1331                     ? !Character.isJavaIdentifierStart(name.codePointAt(i))
1332                     : !Character.isJavaIdentifierPart(name.codePointAt(i))) {
1333                 throw new IllegalArgumentException(
1334                         INVALID
1335                                 + message
1336                                 + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
1337                                 + name);
1338             }
1339         }
1340     }
1341 
1342     /**
1343       * Checks that the given string is a valid internal class name or array type descriptor.
1344       *
1345       * @param version the class version.
1346       * @param name the string to be checked.
1347       * @param message the message to use in case of error.
1348       */
1349     static void checkInternalName(final int version, final String name, final String message) {
1350         if (name == null || name.isEmpty()) {
1351             throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
1352         }
1353         if (name.charAt(0) == '[') {
1354             checkDescriptor(version, name, false);
1355         } else {
1356             checkInternalClassName(version, name, message);
1357         }
1358     }
1359 
1360     /**
1361       * Checks that the given string is a valid internal class name.
1362       *
1363       * @param version the class version.
1364       * @param name the string to be checked.
1365       * @param message the message to use in case of error.
1366       */
1367     private static void checkInternalClassName(
1368             final int version, final String name, final String message) {
1369         try {
1370             int startIndex = 0;
1371             int slashIndex;
1372             while ((slashIndex = name.indexOf('/', startIndex + 1)) != -1) {
1373                 CheckMethodAdapter.checkIdentifier(version, name, startIndex, slashIndex, null);
1374                 startIndex = slashIndex + 1;
1375             }
1376             CheckMethodAdapter.checkIdentifier(version, name, startIndex, name.length(), null);
1377         } catch (IllegalArgumentException e) {
1378             throw new IllegalArgumentException(
1379                     INVALID + message + " (must be an internal class name): " + name, e);
1380         }
1381     }
1382 
1383     /**
1384       * Checks that the given string is a valid type descriptor.
1385       *
1386       * @param version the class version.
1387       * @param descriptor the string to be checked.
1388       * @param canBeVoid {@literal true} if {@code V} can be considered valid.
1389       */
1390     static void checkDescriptor(final int version, final String descriptor, final boolean canBeVoid) {
1391         int endPos = checkDescriptor(version, descriptor, 0, canBeVoid);
1392         if (endPos != descriptor.length()) {
1393             throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1394         }
1395     }
1396 
1397     /**
1398       * Checks that a the given substring is a valid type descriptor.
1399       *
1400       * @param version the class version.
1401       * @param descriptor the string to be checked.
1402       * @param startPos the index of the first character of the type descriptor (inclusive).
1403       * @param canBeVoid whether {@code V} can be considered valid.
1404       * @return the index of the last character of the type descriptor, plus one.
1405       */
1406     private static int checkDescriptor(
1407             final int version, final String descriptor, final int startPos, final boolean canBeVoid) {
1408         if (descriptor == null || startPos >= descriptor.length()) {
1409             throw new IllegalArgumentException("Invalid type descriptor (must not be null or empty)");
1410         }
1411         switch (descriptor.charAt(startPos)) {
1412             case 'V':
1413                 if (canBeVoid) {
1414                     return startPos + 1;
1415                 } else {
1416                     throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1417                 }
1418             case 'Z':
1419             case 'C':
1420             case 'B':
1421             case 'S':
1422             case 'I':
1423             case 'F':
1424             case 'J':
1425             case 'D':
1426                 return startPos + 1;
1427             case '[':
1428                 int pos = startPos + 1;
1429                 while (pos < descriptor.length() && descriptor.charAt(pos) == '[') {
1430                     ++pos;
1431                 }
1432                 if (pos < descriptor.length()) {
1433                     return checkDescriptor(version, descriptor, pos, false);
1434                 } else {
1435                     throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1436                 }
1437             case 'L':
1438             case 'Q':
1439                 int endPos = descriptor.indexOf(';', startPos);
1440                 if (startPos == -1 || endPos - startPos < 2) {
1441                     throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1442                 }
1443                 try {
1444                     checkInternalClassName(version, descriptor.substring(startPos + 1, endPos), null);
1445                 } catch (IllegalArgumentException e) {
1446                     throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor, e);
1447                 }
1448                 return endPos + 1;
1449             default:
1450                 throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1451         }
1452     }
1453 
1454     /**
1455       * Checks that the given string is a valid method descriptor.
1456       *
1457       * @param version the class version.
1458       * @param descriptor the string to be checked.
1459       */
1460     static void checkMethodDescriptor(final int version, final String descriptor) {
1461         if (descriptor == null || descriptor.isEmpty()) {
1462             throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)");
1463         }
1464         if (descriptor.charAt(0) != '(' || descriptor.length() < 3) {
1465             throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1466         }
1467         int pos = 1;
1468         if (descriptor.charAt(pos) != ')') {
1469             do {
1470                 if (descriptor.charAt(pos) == 'V') {
1471                     throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1472                 }
1473                 pos = checkDescriptor(version, descriptor, pos, false);
1474             } while (pos < descriptor.length() && descriptor.charAt(pos) != ')');
1475         }
1476         pos = checkDescriptor(version, descriptor, pos + 1, true);
1477         if (pos != descriptor.length()) {
1478             throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
1479         }
1480     }
1481 
1482     /**
1483       * Checks that the given label is not null. This method can also check that the label has been
1484       * visited.
1485       *
1486       * @param label the label to be checked.
1487       * @param checkVisited whether to check that the label has been visited.
1488       * @param message the message to use in case of error.
1489       */
1490     private void checkLabel(final Label label, final boolean checkVisited, final String message) {
1491         if (label == null) {
1492             throw new IllegalArgumentException(INVALID + message + " (must not be null)");
1493         }
1494         if (checkVisited && labelInsnIndices.get(label) == null) {
1495             throw new IllegalArgumentException(INVALID + message + " (must be visited first)");
1496         }
1497     }
1498 }