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.FileInputStream;
  62 import java.io.PrintWriter;
  63 import java.util.ArrayList;
  64 import java.util.HashMap;
  65 import java.util.Iterator;
  66 import java.util.List;
  67 import java.util.Map;
  68 
  69 import jdk.internal.org.objectweb.asm.AnnotationVisitor;
  70 import jdk.internal.org.objectweb.asm.Attribute;
  71 import jdk.internal.org.objectweb.asm.ClassReader;
  72 import jdk.internal.org.objectweb.asm.ClassVisitor;
  73 import jdk.internal.org.objectweb.asm.FieldVisitor;
  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.ClassNode;
  81 import jdk.internal.org.objectweb.asm.tree.MethodNode;
  82 import jdk.internal.org.objectweb.asm.tree.analysis.Analyzer;
  83 import jdk.internal.org.objectweb.asm.tree.analysis.BasicValue;
  84 import jdk.internal.org.objectweb.asm.tree.analysis.Frame;
  85 import jdk.internal.org.objectweb.asm.tree.analysis.SimpleVerifier;
  86 
  87 /**
  88  * A {@link ClassVisitor} that checks that its methods are properly used. More
  89  * precisely this class adapter checks each method call individually, based
  90  * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i>
  91  * of method calls. For example, the invalid sequence
  92  * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC,
  93  * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter.
  94  *
  95  * <p>
  96  * <code>CheckClassAdapter</code> can be also used to verify bytecode
  97  * transformations in order to make sure transformed bytecode is sane. For
  98  * example:
  99  *
 100  * <pre>
 101  *   InputStream is = ...; // get bytes for the source class
 102  *   ClassReader cr = new ClassReader(is);
 103  *   ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
 104  *   ClassVisitor cv = new <b>MyClassAdapter</b>(new CheckClassAdapter(cw));
 105  *   cr.accept(cv, 0);
 106  *
 107  *   StringWriter sw = new StringWriter();
 108  *   PrintWriter pw = new PrintWriter(sw);
 109  *   CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw);
 110  *   assertTrue(sw.toString(), sw.toString().length()==0);
 111  * </pre>
 112  *
 113  * Above code runs transformed bytecode trough the
 114  * <code>CheckClassAdapter</code>. It won't be exactly the same verification as
 115  * JVM does, but it run data flow analysis for the code of each method and
 116  * checks that expectations are met for each method instruction.
 117  *
 118  * <p>
 119  * If method bytecode has errors, assertion text will show the erroneous
 120  * instruction number and dump of the failed method with information about
 121  * locals and stack slot for each instruction. For example (format is -
 122  * insnNumber locals : stack):
 123  *
 124  * <pre>
 125  * jdk.internal.org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
 126  *   at jdk.internal.org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
 127  *   at jdk.internal.org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
 128  * ...
 129  * remove()V
 130  * 00000 LinkedBlockingQueue$Itr . . . . . . . .  :
 131  *   ICONST_0
 132  * 00001 LinkedBlockingQueue$Itr . . . . . . . .  : I
 133  *   ISTORE 2
 134  * 00001 LinkedBlockingQueue$Itr <b>.</b> I . . . . . .  :
 135  * ...
 136  *
 137  * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . .  :
 138  *   ILOAD 1
 139  * 00072 <b>?</b>
 140  *   INVOKESPECIAL java/lang/Integer.&lt;init&gt; (I)V
 141  * ...
 142  * </pre>
 143  *
 144  * In the above output you can see that variable 1 loaded by
 145  * <code>ILOAD 1</code> instruction at position <code>00071</code> is not
 146  * initialized. You can also see that at the beginning of the method (code
 147  * inserted by the transformation) variable 2 is initialized.
 148  *
 149  * <p>
 150  * Note that when used like that, <code>CheckClassAdapter.verify()</code> can
 151  * trigger additional class loading, because it is using
 152  * <code>SimpleVerifier</code>.
 153  *
 154  * @author Eric Bruneton
 155  */
 156 public class CheckClassAdapter extends ClassVisitor {
 157 
 158     /**
 159      * The class version number.
 160      */
 161     private int version;
 162 
 163     /**
 164      * <tt>true</tt> if the visit method has been called.
 165      */
 166     private boolean start;
 167 
 168     /**
 169      * <tt>true</tt> if the visitSource method has been called.
 170      */
 171     private boolean source;
 172 
 173     /**
 174      * <tt>true</tt> if the visitOuterClass method has been called.
 175      */
 176     private boolean outer;
 177 
 178     /**
 179      * <tt>true</tt> if the visitEnd method has been called.
 180      */
 181     private boolean end;
 182 
 183     /**
 184      * The already visited labels. This map associate Integer values to Label
 185      * keys.
 186      */
 187     private Map<Label, Integer> labels;
 188 
 189     /**
 190      * <tt>true</tt> if the method code must be checked with a BasicVerifier.
 191      */
 192     private boolean checkDataFlow;
 193 
 194     /**
 195      * Checks a given class.
 196      * <p>
 197      * Usage: CheckClassAdapter &lt;binary class name or class file name&gt;
 198      *
 199      * @param args
 200      *            the command line arguments.
 201      *
 202      * @throws Exception
 203      *             if the class cannot be found, or if an IO exception occurs.
 204      */
 205     public static void main(final String[] args) throws Exception {
 206         if (args.length != 1) {
 207             System.err.println("Verifies the given class.");
 208             System.err.println("Usage: CheckClassAdapter "
 209                     + "<fully qualified class name or class file name>");
 210             return;
 211         }
 212         ClassReader cr;
 213         if (args[0].endsWith(".class")) {
 214             cr = new ClassReader(new FileInputStream(args[0]));
 215         } else {
 216             cr = new ClassReader(args[0]);
 217         }
 218 
 219         verify(cr, false, new PrintWriter(System.err));
 220     }
 221 
 222     /**
 223      * Checks a given class.
 224      *
 225      * @param cr
 226      *            a <code>ClassReader</code> that contains bytecode for the
 227      *            analysis.
 228      * @param loader
 229      *            a <code>ClassLoader</code> which will be used to load
 230      *            referenced classes. This is useful if you are verifiying
 231      *            multiple interdependent classes.
 232      * @param dump
 233      *            true if bytecode should be printed out not only when errors
 234      *            are found.
 235      * @param pw
 236      *            write where results going to be printed
 237      */
 238     public static void verify(final ClassReader cr, final ClassLoader loader,
 239             final boolean dump, final PrintWriter pw) {
 240         ClassNode cn = new ClassNode();
 241         cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG);
 242 
 243         Type syperType = cn.superName == null ? null : Type
 244                 .getObjectType(cn.superName);
 245         List<MethodNode> methods = cn.methods;
 246 
 247         List<Type> interfaces = new ArrayList<Type>();
 248         for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) {
 249             interfaces.add(Type.getObjectType(i.next()));
 250         }
 251 
 252         for (int i = 0; i < methods.size(); ++i) {
 253             MethodNode method = methods.get(i);
 254             SimpleVerifier verifier = new SimpleVerifier(
 255                     Type.getObjectType(cn.name), syperType, interfaces,
 256                     (cn.access & Opcodes.ACC_INTERFACE) != 0);
 257             Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier);
 258             if (loader != null) {
 259                 verifier.setClassLoader(loader);
 260             }
 261             try {
 262                 a.analyze(cn.name, method);
 263                 if (!dump) {
 264                     continue;
 265                 }
 266             } catch (Exception e) {
 267                 e.printStackTrace(pw);
 268             }
 269             printAnalyzerResult(method, a, pw);
 270         }
 271         pw.flush();
 272     }
 273 
 274     /**
 275      * Checks a given class
 276      *
 277      * @param cr
 278      *            a <code>ClassReader</code> that contains bytecode for the
 279      *            analysis.
 280      * @param dump
 281      *            true if bytecode should be printed out not only when errors
 282      *            are found.
 283      * @param pw
 284      *            write where results going to be printed
 285      */
 286     public static void verify(final ClassReader cr, final boolean dump,
 287             final PrintWriter pw) {
 288         verify(cr, null, dump, pw);
 289     }
 290 
 291     static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a,
 292             final PrintWriter pw) {
 293         Frame<BasicValue>[] frames = a.getFrames();
 294         Textifier t = new Textifier();
 295         TraceMethodVisitor mv = new TraceMethodVisitor(t);
 296 
 297         pw.println(method.name + method.desc);
 298         for (int j = 0; j < method.instructions.size(); ++j) {
 299             method.instructions.get(j).accept(mv);
 300 
 301             StringBuffer s = new StringBuffer();
 302             Frame<BasicValue> f = frames[j];
 303             if (f == null) {
 304                 s.append('?');
 305             } else {
 306                 for (int k = 0; k < f.getLocals(); ++k) {
 307                     s.append(getShortName(f.getLocal(k).toString()))
 308                             .append(' ');
 309                 }
 310                 s.append(" : ");
 311                 for (int k = 0; k < f.getStackSize(); ++k) {
 312                     s.append(getShortName(f.getStack(k).toString()))
 313                             .append(' ');
 314                 }
 315             }
 316             while (s.length() < method.maxStack + method.maxLocals + 1) {
 317                 s.append(' ');
 318             }
 319             pw.print(Integer.toString(j + 100000).substring(1));
 320             pw.print(" " + s + " : " + t.text.get(t.text.size() - 1));
 321         }
 322         for (int j = 0; j < method.tryCatchBlocks.size(); ++j) {
 323             method.tryCatchBlocks.get(j).accept(mv);
 324             pw.print(" " + t.text.get(t.text.size() - 1));
 325         }
 326         pw.println();
 327     }
 328 
 329     private static String getShortName(final String name) {
 330         int n = name.lastIndexOf('/');
 331         int k = name.length();
 332         if (name.charAt(k - 1) == ';') {
 333             k--;
 334         }
 335         return n == -1 ? name : name.substring(n + 1, k);
 336     }
 337 
 338     /**
 339      * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use
 340      * this constructor</i>. Instead, they must use the
 341      * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
 342      *
 343      * @param cv
 344      *            the class visitor to which this adapter must delegate calls.
 345      */
 346     public CheckClassAdapter(final ClassVisitor cv) {
 347         this(cv, true);
 348     }
 349 
 350     /**
 351      * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use
 352      * this constructor</i>. Instead, they must use the
 353      * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
 354      *
 355      * @param cv
 356      *            the class visitor to which this adapter must delegate calls.
 357      * @param checkDataFlow
 358      *            <tt>true</tt> to perform basic data flow checks, or
 359      *            <tt>false</tt> to not perform any data flow check (see
 360      *            {@link CheckMethodAdapter}). This option requires valid
 361      *            maxLocals and maxStack values.
 362      * @throws IllegalStateException
 363      *             If a subclass calls this constructor.
 364      */
 365     public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
 366         this(Opcodes.ASM5, cv, checkDataFlow);
 367         if (getClass() != CheckClassAdapter.class) {
 368             throw new IllegalStateException();
 369         }
 370     }
 371 
 372     /**
 373      * Constructs a new {@link CheckClassAdapter}.
 374      *
 375      * @param api
 376      *            the ASM API version implemented by this visitor. Must be one
 377      *            of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
 378      * @param cv
 379      *            the class visitor to which this adapter must delegate calls.
 380      * @param checkDataFlow
 381      *            <tt>true</tt> to perform basic data flow checks, or
 382      *            <tt>false</tt> to not perform any data flow check (see
 383      *            {@link CheckMethodAdapter}). This option requires valid
 384      *            maxLocals and maxStack values.
 385      */
 386     protected CheckClassAdapter(final int api, final ClassVisitor cv,
 387             final boolean checkDataFlow) {
 388         super(api, cv);
 389         this.labels = new HashMap<Label, Integer>();
 390         this.checkDataFlow = checkDataFlow;
 391     }
 392 
 393     // ------------------------------------------------------------------------
 394     // Implementation of the ClassVisitor interface
 395     // ------------------------------------------------------------------------
 396 
 397     @Override
 398     public void visit(final int version, final int access, final String name,
 399             final String signature, final String superName,
 400             final String[] interfaces) {
 401         if (start) {
 402             throw new IllegalStateException("visit must be called only once");
 403         }
 404         start = true;
 405         checkState();
 406         checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL
 407                 + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE
 408                 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
 409                 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM
 410                 + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
 411         if (name == null || !name.endsWith("package-info")) {
 412             CheckMethodAdapter.checkInternalName(name, "class name");
 413         }
 414         if ("java/lang/Object".equals(name)) {
 415             if (superName != null) {
 416                 throw new IllegalArgumentException(
 417                         "The super class name of the Object class must be 'null'");
 418             }
 419         } else {
 420             CheckMethodAdapter.checkInternalName(superName, "super class name");
 421         }
 422         if (signature != null) {
 423             checkClassSignature(signature);
 424         }
 425         if ((access & Opcodes.ACC_INTERFACE) != 0) {
 426             if (!"java/lang/Object".equals(superName)) {
 427                 throw new IllegalArgumentException(
 428                         "The super class name of interfaces must be 'java/lang/Object'");
 429             }
 430         }
 431         if (interfaces != null) {
 432             for (int i = 0; i < interfaces.length; ++i) {
 433                 CheckMethodAdapter.checkInternalName(interfaces[i],
 434                         "interface name at index " + i);
 435             }
 436         }
 437         this.version = version;
 438         super.visit(version, access, name, signature, superName, interfaces);
 439     }
 440 
 441     @Override
 442     public void visitSource(final String file, final String debug) {
 443         checkState();
 444         if (source) {
 445             throw new IllegalStateException(
 446                     "visitSource can be called only once.");
 447         }
 448         source = true;
 449         super.visitSource(file, debug);
 450     }
 451 
 452     @Override
 453     public void visitOuterClass(final String owner, final String name,
 454             final String desc) {
 455         checkState();
 456         if (outer) {
 457             throw new IllegalStateException(
 458                     "visitOuterClass can be called only once.");
 459         }
 460         outer = true;
 461         if (owner == null) {
 462             throw new IllegalArgumentException("Illegal outer class owner");
 463         }
 464         if (desc != null) {
 465             CheckMethodAdapter.checkMethodDesc(desc);
 466         }
 467         super.visitOuterClass(owner, name, desc);
 468     }
 469 
 470     @Override
 471     public void visitInnerClass(final String name, final String outerName,
 472             final String innerName, final int access) {
 473         checkState();
 474         CheckMethodAdapter.checkInternalName(name, "class name");
 475         if (outerName != null) {
 476             CheckMethodAdapter.checkInternalName(outerName, "outer class name");
 477         }
 478         if (innerName != null) {
 479             int start = 0;
 480             while (start < innerName.length()
 481                     && Character.isDigit(innerName.charAt(start))) {
 482                 start++;
 483             }
 484             if (start == 0 || start < innerName.length()) {
 485                 CheckMethodAdapter.checkIdentifier(innerName, start, -1,
 486                         "inner class name");
 487             }
 488         }
 489         checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
 490                 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
 491                 + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE
 492                 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
 493                 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM);
 494         super.visitInnerClass(name, outerName, innerName, access);
 495     }
 496 
 497     @Override
 498     public FieldVisitor visitField(final int access, final String name,
 499             final String desc, final String signature, final Object value) {
 500         checkState();
 501         checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
 502                 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
 503                 + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE
 504                 + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC
 505                 + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
 506         CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
 507         CheckMethodAdapter.checkDesc(desc, false);
 508         if (signature != null) {
 509             checkFieldSignature(signature);
 510         }
 511         if (value != null) {
 512             CheckMethodAdapter.checkConstant(value);
 513         }
 514         FieldVisitor av = super
 515                 .visitField(access, name, desc, signature, value);
 516         return new CheckFieldAdapter(av);
 517     }
 518 
 519     @Override
 520     public MethodVisitor visitMethod(final int access, final String name,
 521             final String desc, final String signature, final String[] exceptions) {
 522         checkState();
 523         checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
 524                 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
 525                 + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED
 526                 + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE
 527                 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT
 528                 + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
 529         if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
 530             CheckMethodAdapter.checkMethodIdentifier(version, name,
 531                     "method name");
 532         }
 533         CheckMethodAdapter.checkMethodDesc(desc);
 534         if (signature != null) {
 535             checkMethodSignature(signature);
 536         }
 537         if (exceptions != null) {
 538             for (int i = 0; i < exceptions.length; ++i) {
 539                 CheckMethodAdapter.checkInternalName(exceptions[i],
 540                         "exception name at index " + i);
 541             }
 542         }
 543         CheckMethodAdapter cma;
 544         if (checkDataFlow) {
 545             cma = new CheckMethodAdapter(access, name, desc, super.visitMethod(
 546                     access, name, desc, signature, exceptions), labels);
 547         } else {
 548             cma = new CheckMethodAdapter(super.visitMethod(access, name, desc,
 549                     signature, exceptions), labels);
 550         }
 551         cma.version = version;
 552         return cma;
 553     }
 554 
 555     @Override
 556     public AnnotationVisitor visitAnnotation(final String desc,
 557             final boolean visible) {
 558         checkState();
 559         CheckMethodAdapter.checkDesc(desc, false);
 560         return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
 561     }
 562 
 563     @Override
 564     public AnnotationVisitor visitTypeAnnotation(final int typeRef,
 565             final TypePath typePath, final String desc, final boolean visible) {
 566         checkState();
 567         int sort = typeRef >>> 24;
 568         if (sort != TypeReference.CLASS_TYPE_PARAMETER
 569                 && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND
 570                 && sort != TypeReference.CLASS_EXTENDS) {
 571             throw new IllegalArgumentException("Invalid type reference sort 0x"
 572                     + Integer.toHexString(sort));
 573         }
 574         checkTypeRefAndPath(typeRef, typePath);
 575         CheckMethodAdapter.checkDesc(desc, false);
 576         return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
 577                 typePath, desc, visible));
 578     }
 579 
 580     @Override
 581     public void visitAttribute(final Attribute attr) {
 582         checkState();
 583         if (attr == null) {
 584             throw new IllegalArgumentException(
 585                     "Invalid attribute (must not be null)");
 586         }
 587         super.visitAttribute(attr);
 588     }
 589 
 590     @Override
 591     public void visitEnd() {
 592         checkState();
 593         end = true;
 594         super.visitEnd();
 595     }
 596 
 597     // ------------------------------------------------------------------------
 598     // Utility methods
 599     // ------------------------------------------------------------------------
 600 
 601     /**
 602      * Checks that the visit method has been called and that visitEnd has not
 603      * been called.
 604      */
 605     private void checkState() {
 606         if (!start) {
 607             throw new IllegalStateException(
 608                     "Cannot visit member before visit has been called.");
 609         }
 610         if (end) {
 611             throw new IllegalStateException(
 612                     "Cannot visit member after visitEnd has been called.");
 613         }
 614     }
 615 
 616     /**
 617      * Checks that the given access flags do not contain invalid flags. This
 618      * method also checks that mutually incompatible flags are not set
 619      * simultaneously.
 620      *
 621      * @param access
 622      *            the access flags to be checked
 623      * @param possibleAccess
 624      *            the valid access flags.
 625      */
 626     static void checkAccess(final int access, final int possibleAccess) {
 627         if ((access & ~possibleAccess) != 0) {
 628             throw new IllegalArgumentException("Invalid access flags: "
 629                     + access);
 630         }
 631         int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1;
 632         int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1;
 633         int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1;
 634         if (pub + pri + pro > 1) {
 635             throw new IllegalArgumentException(
 636                     "public private and protected are mutually exclusive: "
 637                             + access);
 638         }
 639         int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1;
 640         int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1;
 641         if (fin + abs > 1) {
 642             throw new IllegalArgumentException(
 643                     "final and abstract are mutually exclusive: " + access);
 644         }
 645     }
 646 
 647     /**
 648      * Checks a class signature.
 649      *
 650      * @param signature
 651      *            a string containing the signature that must be checked.
 652      */
 653     public static void checkClassSignature(final String signature) {
 654         // ClassSignature:
 655         // FormalTypeParameters? ClassTypeSignature ClassTypeSignature*
 656 
 657         int pos = 0;
 658         if (getChar(signature, 0) == '<') {
 659             pos = checkFormalTypeParameters(signature, pos);
 660         }
 661         pos = checkClassTypeSignature(signature, pos);
 662         while (getChar(signature, pos) == 'L') {
 663             pos = checkClassTypeSignature(signature, pos);
 664         }
 665         if (pos != signature.length()) {
 666             throw new IllegalArgumentException(signature + ": error at index "
 667                     + pos);
 668         }
 669     }
 670 
 671     /**
 672      * Checks a method signature.
 673      *
 674      * @param signature
 675      *            a string containing the signature that must be checked.
 676      */
 677     public static void checkMethodSignature(final String signature) {
 678         // MethodTypeSignature:
 679         // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) (
 680         // ^ClassTypeSignature | ^TypeVariableSignature )*
 681 
 682         int pos = 0;
 683         if (getChar(signature, 0) == '<') {
 684             pos = checkFormalTypeParameters(signature, pos);
 685         }
 686         pos = checkChar('(', signature, pos);
 687         while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) {
 688             pos = checkTypeSignature(signature, pos);
 689         }
 690         pos = checkChar(')', signature, pos);
 691         if (getChar(signature, pos) == 'V') {
 692             ++pos;
 693         } else {
 694             pos = checkTypeSignature(signature, pos);
 695         }
 696         while (getChar(signature, pos) == '^') {
 697             ++pos;
 698             if (getChar(signature, pos) == 'L') {
 699                 pos = checkClassTypeSignature(signature, pos);
 700             } else {
 701                 pos = checkTypeVariableSignature(signature, pos);
 702             }
 703         }
 704         if (pos != signature.length()) {
 705             throw new IllegalArgumentException(signature + ": error at index "
 706                     + pos);
 707         }
 708     }
 709 
 710     /**
 711      * Checks a field signature.
 712      *
 713      * @param signature
 714      *            a string containing the signature that must be checked.
 715      */
 716     public static void checkFieldSignature(final String signature) {
 717         int pos = checkFieldTypeSignature(signature, 0);
 718         if (pos != signature.length()) {
 719             throw new IllegalArgumentException(signature + ": error at index "
 720                     + pos);
 721         }
 722     }
 723 
 724     /**
 725      * Checks the reference to a type in a type annotation.
 726      *
 727      * @param typeRef
 728      *            a reference to an annotated type.
 729      * @param typePath
 730      *            the path to the annotated type argument, wildcard bound, array
 731      *            element type, or static inner type within 'typeRef'. May be
 732      *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
 733      */
 734     static void checkTypeRefAndPath(int typeRef, TypePath typePath) {
 735         int mask = 0;
 736         switch (typeRef >>> 24) {
 737         case TypeReference.CLASS_TYPE_PARAMETER:
 738         case TypeReference.METHOD_TYPE_PARAMETER:
 739         case TypeReference.METHOD_FORMAL_PARAMETER:
 740             mask = 0xFFFF0000;
 741             break;
 742         case TypeReference.FIELD:
 743         case TypeReference.METHOD_RETURN:
 744         case TypeReference.METHOD_RECEIVER:
 745         case TypeReference.LOCAL_VARIABLE:
 746         case TypeReference.RESOURCE_VARIABLE:
 747         case TypeReference.INSTANCEOF:
 748         case TypeReference.NEW:
 749         case TypeReference.CONSTRUCTOR_REFERENCE:
 750         case TypeReference.METHOD_REFERENCE:
 751             mask = 0xFF000000;
 752             break;
 753         case TypeReference.CLASS_EXTENDS:
 754         case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
 755         case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
 756         case TypeReference.THROWS:
 757         case TypeReference.EXCEPTION_PARAMETER:
 758             mask = 0xFFFFFF00;
 759             break;
 760         case TypeReference.CAST:
 761         case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
 762         case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
 763         case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
 764         case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
 765             mask = 0xFF0000FF;
 766             break;
 767         default:
 768             throw new IllegalArgumentException("Invalid type reference sort 0x"
 769                     + Integer.toHexString(typeRef >>> 24));
 770         }
 771         if ((typeRef & ~mask) != 0) {
 772             throw new IllegalArgumentException("Invalid type reference 0x"
 773                     + Integer.toHexString(typeRef));
 774         }
 775         if (typePath != null) {
 776             for (int i = 0; i < typePath.getLength(); ++i) {
 777                 int step = typePath.getStep(i);
 778                 if (step != TypePath.ARRAY_ELEMENT
 779                         && step != TypePath.INNER_TYPE
 780                         && step != TypePath.TYPE_ARGUMENT
 781                         && step != TypePath.WILDCARD_BOUND) {
 782                     throw new IllegalArgumentException(
 783                             "Invalid type path step " + i + " in " + typePath);
 784                 }
 785                 if (step != TypePath.TYPE_ARGUMENT
 786                         && typePath.getStepArgument(i) != 0) {
 787                     throw new IllegalArgumentException(
 788                             "Invalid type path step argument for step " + i
 789                                     + " in " + typePath);
 790                 }
 791             }
 792         }
 793     }
 794 
 795     /**
 796      * Checks the formal type parameters of a class or method signature.
 797      *
 798      * @param signature
 799      *            a string containing the signature that must be checked.
 800      * @param pos
 801      *            index of first character to be checked.
 802      * @return the index of the first character after the checked part.
 803      */
 804     private static int checkFormalTypeParameters(final String signature, int pos) {
 805         // FormalTypeParameters:
 806         // < FormalTypeParameter+ >
 807 
 808         pos = checkChar('<', signature, pos);
 809         pos = checkFormalTypeParameter(signature, pos);
 810         while (getChar(signature, pos) != '>') {
 811             pos = checkFormalTypeParameter(signature, pos);
 812         }
 813         return pos + 1;
 814     }
 815 
 816     /**
 817      * Checks a formal type parameter of a class or method signature.
 818      *
 819      * @param signature
 820      *            a string containing the signature that must be checked.
 821      * @param pos
 822      *            index of first character to be checked.
 823      * @return the index of the first character after the checked part.
 824      */
 825     private static int checkFormalTypeParameter(final String signature, int pos) {
 826         // FormalTypeParameter:
 827         // Identifier : FieldTypeSignature? (: FieldTypeSignature)*
 828 
 829         pos = checkIdentifier(signature, pos);
 830         pos = checkChar(':', signature, pos);
 831         if ("L[T".indexOf(getChar(signature, pos)) != -1) {
 832             pos = checkFieldTypeSignature(signature, pos);
 833         }
 834         while (getChar(signature, pos) == ':') {
 835             pos = checkFieldTypeSignature(signature, pos + 1);
 836         }
 837         return pos;
 838     }
 839 
 840     /**
 841      * Checks a field type signature.
 842      *
 843      * @param signature
 844      *            a string containing the signature that must be checked.
 845      * @param pos
 846      *            index of first character to be checked.
 847      * @return the index of the first character after the checked part.
 848      */
 849     private static int checkFieldTypeSignature(final String signature, int pos) {
 850         // FieldTypeSignature:
 851         // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature
 852         //
 853         // ArrayTypeSignature:
 854         // [ TypeSignature
 855 
 856         switch (getChar(signature, pos)) {
 857         case 'L':
 858             return checkClassTypeSignature(signature, pos);
 859         case '[':
 860             return checkTypeSignature(signature, pos + 1);
 861         default:
 862             return checkTypeVariableSignature(signature, pos);
 863         }
 864     }
 865 
 866     /**
 867      * Checks a class type signature.
 868      *
 869      * @param signature
 870      *            a string containing the signature that must be checked.
 871      * @param pos
 872      *            index of first character to be checked.
 873      * @return the index of the first character after the checked part.
 874      */
 875     private static int checkClassTypeSignature(final String signature, int pos) {
 876         // ClassTypeSignature:
 877         // L Identifier ( / Identifier )* TypeArguments? ( . Identifier
 878         // TypeArguments? )* ;
 879 
 880         pos = checkChar('L', signature, pos);
 881         pos = checkIdentifier(signature, pos);
 882         while (getChar(signature, pos) == '/') {
 883             pos = checkIdentifier(signature, pos + 1);
 884         }
 885         if (getChar(signature, pos) == '<') {
 886             pos = checkTypeArguments(signature, pos);
 887         }
 888         while (getChar(signature, pos) == '.') {
 889             pos = checkIdentifier(signature, pos + 1);
 890             if (getChar(signature, pos) == '<') {
 891                 pos = checkTypeArguments(signature, pos);
 892             }
 893         }
 894         return checkChar(';', signature, pos);
 895     }
 896 
 897     /**
 898      * Checks the type arguments in a class type signature.
 899      *
 900      * @param signature
 901      *            a string containing the signature that must be checked.
 902      * @param pos
 903      *            index of first character to be checked.
 904      * @return the index of the first character after the checked part.
 905      */
 906     private static int checkTypeArguments(final String signature, int pos) {
 907         // TypeArguments:
 908         // < TypeArgument+ >
 909 
 910         pos = checkChar('<', signature, pos);
 911         pos = checkTypeArgument(signature, pos);
 912         while (getChar(signature, pos) != '>') {
 913             pos = checkTypeArgument(signature, pos);
 914         }
 915         return pos + 1;
 916     }
 917 
 918     /**
 919      * Checks a type argument in a class type signature.
 920      *
 921      * @param signature
 922      *            a string containing the signature that must be checked.
 923      * @param pos
 924      *            index of first character to be checked.
 925      * @return the index of the first character after the checked part.
 926      */
 927     private static int checkTypeArgument(final String signature, int pos) {
 928         // TypeArgument:
 929         // * | ( ( + | - )? FieldTypeSignature )
 930 
 931         char c = getChar(signature, pos);
 932         if (c == '*') {
 933             return pos + 1;
 934         } else if (c == '+' || c == '-') {
 935             pos++;
 936         }
 937         return checkFieldTypeSignature(signature, pos);
 938     }
 939 
 940     /**
 941      * Checks a type variable signature.
 942      *
 943      * @param signature
 944      *            a string containing the signature that must be checked.
 945      * @param pos
 946      *            index of first character to be checked.
 947      * @return the index of the first character after the checked part.
 948      */
 949     private static int checkTypeVariableSignature(final String signature,
 950             int pos) {
 951         // TypeVariableSignature:
 952         // T Identifier ;
 953 
 954         pos = checkChar('T', signature, pos);
 955         pos = checkIdentifier(signature, pos);
 956         return checkChar(';', signature, pos);
 957     }
 958 
 959     /**
 960      * Checks a type signature.
 961      *
 962      * @param signature
 963      *            a string containing the signature that must be checked.
 964      * @param pos
 965      *            index of first character to be checked.
 966      * @return the index of the first character after the checked part.
 967      */
 968     private static int checkTypeSignature(final String signature, int pos) {
 969         // TypeSignature:
 970         // Z | C | B | S | I | F | J | D | FieldTypeSignature
 971 
 972         switch (getChar(signature, pos)) {
 973         case 'Z':
 974         case 'C':
 975         case 'B':
 976         case 'S':
 977         case 'I':
 978         case 'F':
 979         case 'J':
 980         case 'D':
 981             return pos + 1;
 982         default:
 983             return checkFieldTypeSignature(signature, pos);
 984         }
 985     }
 986 
 987     /**
 988      * Checks an identifier.
 989      *
 990      * @param signature
 991      *            a string containing the signature that must be checked.
 992      * @param pos
 993      *            index of first character to be checked.
 994      * @return the index of the first character after the checked part.
 995      */
 996     private static int checkIdentifier(final String signature, int pos) {
 997         if (!Character.isJavaIdentifierStart(getChar(signature, pos))) {
 998             throw new IllegalArgumentException(signature
 999                     + ": identifier expected at index " + pos);
1000         }
1001         ++pos;
1002         while (Character.isJavaIdentifierPart(getChar(signature, pos))) {
1003             ++pos;
1004         }
1005         return pos;
1006     }
1007 
1008     /**
1009      * Checks a single character.
1010      *
1011      * @param signature
1012      *            a string containing the signature that must be checked.
1013      * @param pos
1014      *            index of first character to be checked.
1015      * @return the index of the first character after the checked part.
1016      */
1017     private static int checkChar(final char c, final String signature, int pos) {
1018         if (getChar(signature, pos) == c) {
1019             return pos + 1;
1020         }
1021         throw new IllegalArgumentException(signature + ": '" + c
1022                 + "' expected at index " + pos);
1023     }
1024 
1025     /**
1026      * Returns the signature car at the given index.
1027      *
1028      * @param signature
1029      *            a signature.
1030      * @param pos
1031      *            an index in signature.
1032      * @return the character at the given index, or 0 if there is no such
1033      *         character.
1034      */
1035     private static char getChar(final String signature, int pos) {
1036         return pos < signature.length() ? signature.charAt(pos) : (char) 0;
1037     }
1038 }