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