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;
  60 
  61 /**
  62  * A {@link MethodVisitor} that generates methods in bytecode form. Each visit
  63  * method of this class appends the bytecode corresponding to the visited
  64  * instruction to a byte vector, in the order these methods are called.
  65  *
  66  * @author Eric Bruneton
  67  * @author Eugene Kuleshov
  68  */
  69 class MethodWriter extends MethodVisitor {
  70 
  71     /**
  72      * Pseudo access flag used to denote constructors.
  73      */
  74     static final int ACC_CONSTRUCTOR = 0x80000;
  75 
  76     /**
  77      * Frame has exactly the same locals as the previous stack map frame and
  78      * number of stack items is zero.
  79      */
  80     static final int SAME_FRAME = 0; // to 63 (0-3f)
  81 
  82     /**
  83      * Frame has exactly the same locals as the previous stack map frame and
  84      * number of stack items is 1
  85      */
  86     static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
  87 
  88     /**
  89      * Reserved for future use
  90      */
  91     static final int RESERVED = 128;
  92 
  93     /**
  94      * Frame has exactly the same locals as the previous stack map frame and
  95      * number of stack items is 1. Offset is bigger then 63;
  96      */
  97     static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
  98 
  99     /**
 100      * Frame where current locals are the same as the locals in the previous
 101      * frame, except that the k last locals are absent. The value of k is given
 102      * by the formula 251-frame_type.
 103      */
 104     static final int CHOP_FRAME = 248; // to 250 (f8-fA)
 105 
 106     /**
 107      * Frame has exactly the same locals as the previous stack map frame and
 108      * number of stack items is zero. Offset is bigger then 63;
 109      */
 110     static final int SAME_FRAME_EXTENDED = 251; // fb
 111 
 112     /**
 113      * Frame where current locals are the same as the locals in the previous
 114      * frame, except that k additional locals are defined. The value of k is
 115      * given by the formula frame_type-251.
 116      */
 117     static final int APPEND_FRAME = 252; // to 254 // fc-fe
 118 
 119     /**
 120      * Full frame
 121      */
 122     static final int FULL_FRAME = 255; // ff
 123 
 124     /**
 125      * Indicates that the stack map frames must be recomputed from scratch. In
 126      * this case the maximum stack size and number of local variables is also
 127      * recomputed from scratch.
 128      *
 129      * @see #compute
 130      */
 131     static final int FRAMES = 0;
 132 
 133     /**
 134      * Indicates that the stack map frames of type F_INSERT must be computed.
 135      * The other frames are not (re)computed. They should all be of type F_NEW
 136      * and should be sufficient to compute the content of the F_INSERT frames,
 137      * together with the bytecode instructions between a F_NEW and a F_INSERT
 138      * frame - and without any knowledge of the type hierarchy (by definition of
 139      * F_INSERT).
 140      *
 141      * @see #compute
 142      */
 143     static final int INSERTED_FRAMES = 1;
 144 
 145     /**
 146      * Indicates that the maximum stack size and number of local variables must
 147      * be automatically computed.
 148      *
 149      * @see #compute
 150      */
 151     static final int MAXS = 2;
 152 
 153     /**
 154      * Indicates that nothing must be automatically computed.
 155      *
 156      * @see #compute
 157      */
 158     static final int NOTHING = 3;
 159 
 160     /**
 161      * The class writer to which this method must be added.
 162      */
 163     final ClassWriter cw;
 164 
 165     /**
 166      * Access flags of this method.
 167      */
 168     private int access;
 169 
 170     /**
 171      * The index of the constant pool item that contains the name of this
 172      * method.
 173      */
 174     private final int name;
 175 
 176     /**
 177      * The index of the constant pool item that contains the descriptor of this
 178      * method.
 179      */
 180     private final int desc;
 181 
 182     /**
 183      * The descriptor of this method.
 184      */
 185     private final String descriptor;
 186 
 187     /**
 188      * The signature of this method.
 189      */
 190     String signature;
 191 
 192     /**
 193      * If not zero, indicates that the code of this method must be copied from
 194      * the ClassReader associated to this writer in <code>cw.cr</code>. More
 195      * precisely, this field gives the index of the first byte to copied from
 196      * <code>cw.cr.b</code>.
 197      */
 198     int classReaderOffset;
 199 
 200     /**
 201      * If not zero, indicates that the code of this method must be copied from
 202      * the ClassReader associated to this writer in <code>cw.cr</code>. More
 203      * precisely, this field gives the number of bytes to copied from
 204      * <code>cw.cr.b</code>.
 205      */
 206     int classReaderLength;
 207 
 208     /**
 209      * Number of exceptions that can be thrown by this method.
 210      */
 211     int exceptionCount;
 212 
 213     /**
 214      * The exceptions that can be thrown by this method. More precisely, this
 215      * array contains the indexes of the constant pool items that contain the
 216      * internal names of these exception classes.
 217      */
 218     int[] exceptions;
 219 
 220     /**
 221      * The annotation default attribute of this method. May be <tt>null</tt>.
 222      */
 223     private ByteVector annd;
 224 
 225     /**
 226      * The runtime visible annotations of this method. May be <tt>null</tt>.
 227      */
 228     private AnnotationWriter anns;
 229 
 230     /**
 231      * The runtime invisible annotations of this method. May be <tt>null</tt>.
 232      */
 233     private AnnotationWriter ianns;
 234 
 235     /**
 236      * The runtime visible type annotations of this method. May be <tt>null</tt>
 237      * .
 238      */
 239     private AnnotationWriter tanns;
 240 
 241     /**
 242      * The runtime invisible type annotations of this method. May be
 243      * <tt>null</tt>.
 244      */
 245     private AnnotationWriter itanns;
 246 
 247     /**
 248      * The runtime visible parameter annotations of this method. May be
 249      * <tt>null</tt>.
 250      */
 251     private AnnotationWriter[] panns;
 252 
 253     /**
 254      * The runtime invisible parameter annotations of this method. May be
 255      * <tt>null</tt>.
 256      */
 257     private AnnotationWriter[] ipanns;
 258 
 259     /**
 260      * The number of synthetic parameters of this method.
 261      */
 262     private int synthetics;
 263 
 264     /**
 265      * The non standard attributes of the method.
 266      */
 267     private Attribute attrs;
 268 
 269     /**
 270      * The bytecode of this method.
 271      */
 272     private ByteVector code = new ByteVector();
 273 
 274     /**
 275      * Maximum stack size of this method.
 276      */
 277     private int maxStack;
 278 
 279     /**
 280      * Maximum number of local variables for this method.
 281      */
 282     private int maxLocals;
 283 
 284     /**
 285      * Number of local variables in the current stack map frame.
 286      */
 287     private int currentLocals;
 288 
 289     /**
 290      * Number of stack map frames in the StackMapTable attribute.
 291      */
 292     int frameCount;
 293 
 294     /**
 295      * The StackMapTable attribute.
 296      */
 297     private ByteVector stackMap;
 298 
 299     /**
 300      * The offset of the last frame that was written in the StackMapTable
 301      * attribute.
 302      */
 303     private int previousFrameOffset;
 304 
 305     /**
 306      * The last frame that was written in the StackMapTable attribute.
 307      *
 308      * @see #frame
 309      */
 310     private int[] previousFrame;
 311 
 312     /**
 313      * The current stack map frame. The first element contains the offset of the
 314      * instruction to which the frame corresponds, the second element is the
 315      * number of locals and the third one is the number of stack elements. The
 316      * local variables start at index 3 and are followed by the operand stack
 317      * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] =
 318      * nStack, frame[3] = nLocal. All types are encoded as integers, with the
 319      * same format as the one used in {@link Label}, but limited to BASE types.
 320      */
 321     private int[] frame;
 322 
 323     /**
 324      * Number of elements in the exception handler list.
 325      */
 326     private int handlerCount;
 327 
 328     /**
 329      * The first element in the exception handler list.
 330      */
 331     private Handler firstHandler;
 332 
 333     /**
 334      * The last element in the exception handler list.
 335      */
 336     private Handler lastHandler;
 337 
 338     /**
 339      * Number of entries in the MethodParameters attribute.
 340      */
 341     private int methodParametersCount;
 342 
 343     /**
 344      * The MethodParameters attribute.
 345      */
 346     private ByteVector methodParameters;
 347 
 348     /**
 349      * Number of entries in the LocalVariableTable attribute.
 350      */
 351     private int localVarCount;
 352 
 353     /**
 354      * The LocalVariableTable attribute.
 355      */
 356     private ByteVector localVar;
 357 
 358     /**
 359      * Number of entries in the LocalVariableTypeTable attribute.
 360      */
 361     private int localVarTypeCount;
 362 
 363     /**
 364      * The LocalVariableTypeTable attribute.
 365      */
 366     private ByteVector localVarType;
 367 
 368     /**
 369      * Number of entries in the LineNumberTable attribute.
 370      */
 371     private int lineNumberCount;
 372 
 373     /**
 374      * The LineNumberTable attribute.
 375      */
 376     private ByteVector lineNumber;
 377 
 378     /**
 379      * The start offset of the last visited instruction.
 380      */
 381     private int lastCodeOffset;
 382 
 383     /**
 384      * The runtime visible type annotations of the code. May be <tt>null</tt>.
 385      */
 386     private AnnotationWriter ctanns;
 387 
 388     /**
 389      * The runtime invisible type annotations of the code. May be <tt>null</tt>.
 390      */
 391     private AnnotationWriter ictanns;
 392 
 393     /**
 394      * The non standard attributes of the method's code.
 395      */
 396     private Attribute cattrs;
 397 
 398     /**
 399      * The number of subroutines in this method.
 400      */
 401     private int subroutines;
 402 
 403     // ------------------------------------------------------------------------
 404 
 405     /*
 406      * Fields for the control flow graph analysis algorithm (used to compute the
 407      * maximum stack size). A control flow graph contains one node per "basic
 408      * block", and one edge per "jump" from one basic block to another. Each
 409      * node (i.e., each basic block) is represented by the Label object that
 410      * corresponds to the first instruction of this basic block. Each node also
 411      * stores the list of its successors in the graph, as a linked list of Edge
 412      * objects.
 413      */
 414 
 415     /**
 416      * Indicates what must be automatically computed.
 417      *
 418      * @see #FRAMES
 419      * @see #INSERTED_FRAMES
 420      * @see #MAXS
 421      * @see #NOTHING
 422      */
 423     private final int compute;
 424 
 425     /**
 426      * A list of labels. This list is the list of basic blocks in the method,
 427      * i.e. a list of Label objects linked to each other by their
 428      * {@link Label#successor} field, in the order they are visited by
 429      * {@link MethodVisitor#visitLabel}, and starting with the first basic
 430      * block.
 431      */
 432     private Label labels;
 433 
 434     /**
 435      * The previous basic block.
 436      */
 437     private Label previousBlock;
 438 
 439     /**
 440      * The current basic block.
 441      */
 442     private Label currentBlock;
 443 
 444     /**
 445      * The (relative) stack size after the last visited instruction. This size
 446      * is relative to the beginning of the current basic block, i.e., the true
 447      * stack size after the last visited instruction is equal to the
 448      * {@link Label#inputStackTop beginStackSize} of the current basic block
 449      * plus <tt>stackSize</tt>.
 450      */
 451     private int stackSize;
 452 
 453     /**
 454      * The (relative) maximum stack size after the last visited instruction.
 455      * This size is relative to the beginning of the current basic block, i.e.,
 456      * the true maximum stack size after the last visited instruction is equal
 457      * to the {@link Label#inputStackTop beginStackSize} of the current basic
 458      * block plus <tt>stackSize</tt>.
 459      */
 460     private int maxStackSize;
 461 
 462     // ------------------------------------------------------------------------
 463     // Constructor
 464     // ------------------------------------------------------------------------
 465 
 466     /**
 467      * Constructs a new {@link MethodWriter}.
 468      *
 469      * @param cw
 470      *            the class writer in which the method must be added.
 471      * @param access
 472      *            the method's access flags (see {@link Opcodes}).
 473      * @param name
 474      *            the method's name.
 475      * @param desc
 476      *            the method's descriptor (see {@link Type}).
 477      * @param signature
 478      *            the method's signature. May be <tt>null</tt>.
 479      * @param exceptions
 480      *            the internal names of the method's exceptions. May be
 481      *            <tt>null</tt>.
 482      * @param compute
 483      *            Indicates what must be automatically computed (see #compute).
 484      */
 485     MethodWriter(final ClassWriter cw, final int access, final String name,
 486             final String desc, final String signature,
 487             final String[] exceptions, final int compute) {
 488         super(Opcodes.ASM6);
 489         if (cw.firstMethod == null) {
 490             cw.firstMethod = this;
 491         } else {
 492             cw.lastMethod.mv = this;
 493         }
 494         cw.lastMethod = this;
 495         this.cw = cw;
 496         this.access = access;
 497         if ("<init>".equals(name)) {
 498             this.access |= ACC_CONSTRUCTOR;
 499         }
 500         this.name = cw.newUTF8(name);
 501         this.desc = cw.newUTF8(desc);
 502         this.descriptor = desc;
 503         this.signature = signature;
 504         if (exceptions != null && exceptions.length > 0) {
 505             exceptionCount = exceptions.length;
 506             this.exceptions = new int[exceptionCount];
 507             for (int i = 0; i < exceptionCount; ++i) {
 508                 this.exceptions[i] = cw.newClass(exceptions[i]);
 509             }
 510         }
 511         this.compute = compute;
 512         if (compute != NOTHING) {
 513             // updates maxLocals
 514             int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
 515             if ((access & Opcodes.ACC_STATIC) != 0) {
 516                 --size;
 517             }
 518             maxLocals = size;
 519             currentLocals = size;
 520             // creates and visits the label for the first basic block
 521             labels = new Label();
 522             labels.status |= Label.PUSHED;
 523             visitLabel(labels);
 524         }
 525     }
 526 
 527     // ------------------------------------------------------------------------
 528     // Implementation of the MethodVisitor abstract class
 529     // ------------------------------------------------------------------------
 530 
 531     @Override
 532     public void visitParameter(String name, int access) {
 533         if (methodParameters == null) {
 534             methodParameters = new ByteVector();
 535         }
 536         ++methodParametersCount;
 537         methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
 538                 .putShort(access);
 539     }
 540 
 541     @Override
 542     public AnnotationVisitor visitAnnotationDefault() {
 543         annd = new ByteVector();
 544         return new AnnotationWriter(cw, false, annd, null, 0);
 545     }
 546 
 547     @Override
 548     public AnnotationVisitor visitAnnotation(final String desc,
 549             final boolean visible) {
 550         ByteVector bv = new ByteVector();
 551         // write type, and reserve space for values count
 552         bv.putShort(cw.newUTF8(desc)).putShort(0);
 553         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
 554         if (visible) {
 555             aw.next = anns;
 556             anns = aw;
 557         } else {
 558             aw.next = ianns;
 559             ianns = aw;
 560         }
 561         return aw;
 562     }
 563 
 564     @Override
 565     public AnnotationVisitor visitTypeAnnotation(final int typeRef,
 566             final TypePath typePath, final String desc, final boolean visible) {
 567         ByteVector bv = new ByteVector();
 568         // write target_type and target_info
 569         AnnotationWriter.putTarget(typeRef, typePath, bv);
 570         // write type, and reserve space for values count
 571         bv.putShort(cw.newUTF8(desc)).putShort(0);
 572         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
 573                 bv.length - 2);
 574         if (visible) {
 575             aw.next = tanns;
 576             tanns = aw;
 577         } else {
 578             aw.next = itanns;
 579             itanns = aw;
 580         }
 581         return aw;
 582     }
 583 
 584     @Override
 585     public AnnotationVisitor visitParameterAnnotation(final int parameter,
 586             final String desc, final boolean visible) {
 587         ByteVector bv = new ByteVector();
 588         if ("Ljava/lang/Synthetic;".equals(desc)) {
 589             // workaround for a bug in javac with synthetic parameters
 590             // see ClassReader.readParameterAnnotations
 591             synthetics = Math.max(synthetics, parameter + 1);
 592             return new AnnotationWriter(cw, false, bv, null, 0);
 593         }
 594         // write type, and reserve space for values count
 595         bv.putShort(cw.newUTF8(desc)).putShort(0);
 596         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
 597         if (visible) {
 598             if (panns == null) {
 599                 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
 600             }
 601             aw.next = panns[parameter];
 602             panns[parameter] = aw;
 603         } else {
 604             if (ipanns == null) {
 605                 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
 606             }
 607             aw.next = ipanns[parameter];
 608             ipanns[parameter] = aw;
 609         }
 610         return aw;
 611     }
 612 
 613     @Override
 614     public void visitAttribute(final Attribute attr) {
 615         if (attr.isCodeAttribute()) {
 616             attr.next = cattrs;
 617             cattrs = attr;
 618         } else {
 619             attr.next = attrs;
 620             attrs = attr;
 621         }
 622     }
 623 
 624     @Override
 625     public void visitCode() {
 626     }
 627 
 628     @Override
 629     public void visitFrame(final int type, final int nLocal,
 630             final Object[] local, final int nStack, final Object[] stack) {
 631         if (compute == FRAMES) {
 632             return;
 633         }
 634 
 635         if (compute == INSERTED_FRAMES) {
 636             if (currentBlock.frame == null) {
 637                 // This should happen only once, for the implicit first frame
 638                 // (which is explicitly visited in ClassReader if the
 639                 // EXPAND_ASM_INSNS option is used).
 640                 currentBlock.frame = new CurrentFrame();
 641                 currentBlock.frame.owner = currentBlock;
 642                 currentBlock.frame.initInputFrame(cw, access,
 643                         Type.getArgumentTypes(descriptor), nLocal);
 644                 visitImplicitFirstFrame();
 645             } else {
 646                 if (type == Opcodes.F_NEW) {
 647                     currentBlock.frame.set(cw, nLocal, local, nStack, stack);
 648                 } else {
 649                     // In this case type is equal to F_INSERT by hypothesis, and
 650                     // currentBlock.frame contains the stack map frame at the
 651                     // current instruction, computed from the last F_NEW frame
 652                     // and the bytecode instructions in between (via calls to
 653                     // CurrentFrame#execute).
 654                 }
 655                 visitFrame(currentBlock.frame);
 656             }
 657         } else if (type == Opcodes.F_NEW) {
 658             if (previousFrame == null) {
 659                 visitImplicitFirstFrame();
 660             }
 661             currentLocals = nLocal;
 662             int frameIndex = startFrame(code.length, nLocal, nStack);
 663             for (int i = 0; i < nLocal; ++i) {
 664                 if (local[i] instanceof String) {
 665                     String desc = Type.getObjectType((String) local[i]).getDescriptor();
 666                     frame[frameIndex++] = Frame.type(cw, desc);
 667                 } else if (local[i] instanceof Integer) {
 668                     frame[frameIndex++] = Frame.BASE | ((Integer) local[i]).intValue();
 669                 } else {
 670                     frame[frameIndex++] = Frame.UNINITIALIZED
 671                             | cw.addUninitializedType("",
 672                                     ((Label) local[i]).position);
 673                 }
 674             }
 675             for (int i = 0; i < nStack; ++i) {
 676                 if (stack[i] instanceof String) {
 677                     String desc = Type.getObjectType((String) stack[i]).getDescriptor();
 678                     frame[frameIndex++] = Frame.type(cw, desc);
 679                 } else if (stack[i] instanceof Integer) {
 680                     frame[frameIndex++] = Frame.BASE | ((Integer) stack[i]).intValue();
 681                 } else {
 682                     frame[frameIndex++] = Frame.UNINITIALIZED
 683                             | cw.addUninitializedType("",
 684                                     ((Label) stack[i]).position);
 685                 }
 686             }
 687             endFrame();
 688         } else {
 689             int delta;
 690             if (stackMap == null) {
 691                 stackMap = new ByteVector();
 692                 delta = code.length;
 693             } else {
 694                 delta = code.length - previousFrameOffset - 1;
 695                 if (delta < 0) {
 696                     if (type == Opcodes.F_SAME) {
 697                         return;
 698                     } else {
 699                         throw new IllegalStateException();
 700                     }
 701                 }
 702             }
 703 
 704             switch (type) {
 705             case Opcodes.F_FULL:
 706                 currentLocals = nLocal;
 707                 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal);
 708                 for (int i = 0; i < nLocal; ++i) {
 709                     writeFrameType(local[i]);
 710                 }
 711                 stackMap.putShort(nStack);
 712                 for (int i = 0; i < nStack; ++i) {
 713                     writeFrameType(stack[i]);
 714                 }
 715                 break;
 716             case Opcodes.F_APPEND:
 717                 currentLocals += nLocal;
 718                 stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta);
 719                 for (int i = 0; i < nLocal; ++i) {
 720                     writeFrameType(local[i]);
 721                 }
 722                 break;
 723             case Opcodes.F_CHOP:
 724                 currentLocals -= nLocal;
 725                 stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta);
 726                 break;
 727             case Opcodes.F_SAME:
 728                 if (delta < 64) {
 729                     stackMap.putByte(delta);
 730                 } else {
 731                     stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
 732                 }
 733                 break;
 734             case Opcodes.F_SAME1:
 735                 if (delta < 64) {
 736                     stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
 737                 } else {
 738                     stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
 739                             .putShort(delta);
 740                 }
 741                 writeFrameType(stack[0]);
 742                 break;
 743             }
 744 
 745             previousFrameOffset = code.length;
 746             ++frameCount;
 747         }
 748 
 749         maxStack = Math.max(maxStack, nStack);
 750         maxLocals = Math.max(maxLocals, currentLocals);
 751     }
 752 
 753     @Override
 754     public void visitInsn(final int opcode) {
 755         lastCodeOffset = code.length;
 756         // adds the instruction to the bytecode of the method
 757         code.putByte(opcode);
 758         // update currentBlock
 759         // Label currentBlock = this.currentBlock;
 760         if (currentBlock != null) {
 761             if (compute == FRAMES || compute == INSERTED_FRAMES) {
 762                 currentBlock.frame.execute(opcode, 0, null, null);
 763             } else {
 764                 // updates current and max stack sizes
 765                 int size = stackSize + Frame.SIZE[opcode];
 766                 if (size > maxStackSize) {
 767                     maxStackSize = size;
 768                 }
 769                 stackSize = size;
 770             }
 771             // if opcode == ATHROW or xRETURN, ends current block (no successor)
 772             if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
 773                     || opcode == Opcodes.ATHROW) {
 774                 noSuccessor();
 775             }
 776         }
 777     }
 778 
 779     @Override
 780     public void visitIntInsn(final int opcode, final int operand) {
 781         lastCodeOffset = code.length;
 782         // Label currentBlock = this.currentBlock;
 783         if (currentBlock != null) {
 784             if (compute == FRAMES || compute == INSERTED_FRAMES) {
 785                 currentBlock.frame.execute(opcode, operand, null, null);
 786             } else if (opcode != Opcodes.NEWARRAY) {
 787                 // updates current and max stack sizes only for NEWARRAY
 788                 // (stack size variation = 0 for BIPUSH or SIPUSH)
 789                 int size = stackSize + 1;
 790                 if (size > maxStackSize) {
 791                     maxStackSize = size;
 792                 }
 793                 stackSize = size;
 794             }
 795         }
 796         // adds the instruction to the bytecode of the method
 797         if (opcode == Opcodes.SIPUSH) {
 798             code.put12(opcode, operand);
 799         } else { // BIPUSH or NEWARRAY
 800             code.put11(opcode, operand);
 801         }
 802     }
 803 
 804     @Override
 805     public void visitVarInsn(final int opcode, final int var) {
 806         lastCodeOffset = code.length;
 807         // Label currentBlock = this.currentBlock;
 808         if (currentBlock != null) {
 809             if (compute == FRAMES || compute == INSERTED_FRAMES) {
 810                 currentBlock.frame.execute(opcode, var, null, null);
 811             } else {
 812                 // updates current and max stack sizes
 813                 if (opcode == Opcodes.RET) {
 814                     // no stack change, but end of current block (no successor)
 815                     currentBlock.status |= Label.RET;
 816                     // save 'stackSize' here for future use
 817                     // (see {@link #findSubroutineSuccessors})
 818                     currentBlock.inputStackTop = stackSize;
 819                     noSuccessor();
 820                 } else { // xLOAD or xSTORE
 821                     int size = stackSize + Frame.SIZE[opcode];
 822                     if (size > maxStackSize) {
 823                         maxStackSize = size;
 824                     }
 825                     stackSize = size;
 826                 }
 827             }
 828         }
 829         if (compute != NOTHING) {
 830             // updates max locals
 831             int n;
 832             if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
 833                     || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) {
 834                 n = var + 2;
 835             } else {
 836                 n = var + 1;
 837             }
 838             if (n > maxLocals) {
 839                 maxLocals = n;
 840             }
 841         }
 842         // adds the instruction to the bytecode of the method
 843         if (var < 4 && opcode != Opcodes.RET) {
 844             int opt;
 845             if (opcode < Opcodes.ISTORE) {
 846                 /* ILOAD_0 */
 847                 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
 848             } else {
 849                 /* ISTORE_0 */
 850                 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
 851             }
 852             code.putByte(opt);
 853         } else if (var >= 256) {
 854             code.putByte(196 /* WIDE */).put12(opcode, var);
 855         } else {
 856             code.put11(opcode, var);
 857         }
 858         if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
 859             visitLabel(new Label());
 860         }
 861     }
 862 
 863     @Override
 864     public void visitTypeInsn(final int opcode, final String type) {
 865         lastCodeOffset = code.length;
 866         Item i = cw.newStringishItem(ClassWriter.CLASS, type);
 867         // Label currentBlock = this.currentBlock;
 868         if (currentBlock != null) {
 869             if (compute == FRAMES || compute == INSERTED_FRAMES) {
 870                 currentBlock.frame.execute(opcode, code.length, cw, i);
 871             } else if (opcode == Opcodes.NEW) {
 872                 // updates current and max stack sizes only if opcode == NEW
 873                 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
 874                 int size = stackSize + 1;
 875                 if (size > maxStackSize) {
 876                     maxStackSize = size;
 877                 }
 878                 stackSize = size;
 879             }
 880         }
 881         // adds the instruction to the bytecode of the method
 882         code.put12(opcode, i.index);
 883     }
 884 
 885     @Override
 886     public void visitFieldInsn(final int opcode, final String owner,
 887             final String name, final String desc) {
 888         lastCodeOffset = code.length;
 889         Item i = cw.newFieldItem(owner, name, desc);
 890         // Label currentBlock = this.currentBlock;
 891         if (currentBlock != null) {
 892             if (compute == FRAMES || compute == INSERTED_FRAMES) {
 893                 currentBlock.frame.execute(opcode, 0, cw, i);
 894             } else {
 895                 int size;
 896                 // computes the stack size variation
 897                 char c = desc.charAt(0);
 898                 switch (opcode) {
 899                 case Opcodes.GETSTATIC:
 900                     size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
 901                     break;
 902                 case Opcodes.PUTSTATIC:
 903                     size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
 904                     break;
 905                 case Opcodes.GETFIELD:
 906                     size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
 907                     break;
 908                 // case Constants.PUTFIELD:
 909                 default:
 910                     size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
 911                     break;
 912                 }
 913                 // updates current and max stack sizes
 914                 if (size > maxStackSize) {
 915                     maxStackSize = size;
 916                 }
 917                 stackSize = size;
 918             }
 919         }
 920         // adds the instruction to the bytecode of the method
 921         code.put12(opcode, i.index);
 922     }
 923 
 924     @Override
 925     public void visitMethodInsn(final int opcode, final String owner,
 926             final String name, final String desc, final boolean itf) {
 927         lastCodeOffset = code.length;
 928         Item i = cw.newMethodItem(owner, name, desc, itf);
 929         int argSize = i.intVal;
 930         // Label currentBlock = this.currentBlock;
 931         if (currentBlock != null) {
 932             if (compute == FRAMES || compute == INSERTED_FRAMES) {
 933                 currentBlock.frame.execute(opcode, 0, cw, i);
 934             } else {
 935                 /*
 936                  * computes the stack size variation. In order not to recompute
 937                  * several times this variation for the same Item, we use the
 938                  * intVal field of this item to store this variation, once it
 939                  * has been computed. More precisely this intVal field stores
 940                  * the sizes of the arguments and of the return value
 941                  * corresponding to desc.
 942                  */
 943                 if (argSize == 0) {
 944                     // the above sizes have not been computed yet,
 945                     // so we compute them...
 946                     argSize = Type.getArgumentsAndReturnSizes(desc);
 947                     // ... and we save them in order
 948                     // not to recompute them in the future
 949                     i.intVal = argSize;
 950                 }
 951                 int size;
 952                 if (opcode == Opcodes.INVOKESTATIC) {
 953                     size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
 954                 } else {
 955                     size = stackSize - (argSize >> 2) + (argSize & 0x03);
 956                 }
 957                 // updates current and max stack sizes
 958                 if (size > maxStackSize) {
 959                     maxStackSize = size;
 960                 }
 961                 stackSize = size;
 962             }
 963         }
 964         // adds the instruction to the bytecode of the method
 965         if (opcode == Opcodes.INVOKEINTERFACE) {
 966             if (argSize == 0) {
 967                 argSize = Type.getArgumentsAndReturnSizes(desc);
 968                 i.intVal = argSize;
 969             }
 970             code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
 971         } else {
 972             code.put12(opcode, i.index);
 973         }
 974     }
 975 
 976     @Override
 977     public void visitInvokeDynamicInsn(final String name, final String desc,
 978             final Handle bsm, final Object... bsmArgs) {
 979         lastCodeOffset = code.length;
 980         Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
 981         int argSize = i.intVal;
 982         // Label currentBlock = this.currentBlock;
 983         if (currentBlock != null) {
 984             if (compute == FRAMES || compute == INSERTED_FRAMES) {
 985                 currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i);
 986             } else {
 987                 /*
 988                  * computes the stack size variation. In order not to recompute
 989                  * several times this variation for the same Item, we use the
 990                  * intVal field of this item to store this variation, once it
 991                  * has been computed. More precisely this intVal field stores
 992                  * the sizes of the arguments and of the return value
 993                  * corresponding to desc.
 994                  */
 995                 if (argSize == 0) {
 996                     // the above sizes have not been computed yet,
 997                     // so we compute them...
 998                     argSize = Type.getArgumentsAndReturnSizes(desc);
 999                     // ... and we save them in order
1000                     // not to recompute them in the future
1001                     i.intVal = argSize;
1002                 }
1003                 int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
1004 
1005                 // updates current and max stack sizes
1006                 if (size > maxStackSize) {
1007                     maxStackSize = size;
1008                 }
1009                 stackSize = size;
1010             }
1011         }
1012         // adds the instruction to the bytecode of the method
1013         code.put12(Opcodes.INVOKEDYNAMIC, i.index);
1014         code.putShort(0);
1015     }
1016 
1017     @Override
1018     public void visitJumpInsn(int opcode, final Label label) {
1019         boolean isWide = opcode >= 200; // GOTO_W
1020         opcode = isWide ? opcode - 33 : opcode;
1021         lastCodeOffset = code.length;
1022         Label nextInsn = null;
1023         // Label currentBlock = this.currentBlock;
1024         if (currentBlock != null) {
1025             if (compute == FRAMES) {
1026                 currentBlock.frame.execute(opcode, 0, null, null);
1027                 // 'label' is the target of a jump instruction
1028                 label.getFirst().status |= Label.TARGET;
1029                 // adds 'label' as a successor of this basic block
1030                 addSuccessor(Edge.NORMAL, label);
1031                 if (opcode != Opcodes.GOTO) {
1032                     // creates a Label for the next basic block
1033                     nextInsn = new Label();
1034                 }
1035             } else if (compute == INSERTED_FRAMES) {
1036                 currentBlock.frame.execute(opcode, 0, null, null);
1037             } else {
1038                 if (opcode == Opcodes.JSR) {
1039                     if ((label.status & Label.SUBROUTINE) == 0) {
1040                         label.status |= Label.SUBROUTINE;
1041                         ++subroutines;
1042                     }
1043                     currentBlock.status |= Label.JSR;
1044                     addSuccessor(stackSize + 1, label);
1045                     // creates a Label for the next basic block
1046                     nextInsn = new Label();
1047                     /*
1048                      * note that, by construction in this method, a JSR block
1049                      * has at least two successors in the control flow graph:
1050                      * the first one leads the next instruction after the JSR,
1051                      * while the second one leads to the JSR target.
1052                      */
1053                 } else {
1054                     // updates current stack size (max stack size unchanged
1055                     // because stack size variation always negative in this
1056                     // case)
1057                     stackSize += Frame.SIZE[opcode];
1058                     addSuccessor(stackSize, label);
1059                 }
1060             }
1061         }
1062         // adds the instruction to the bytecode of the method
1063         if ((label.status & Label.RESOLVED) != 0
1064                 && label.position - code.length < Short.MIN_VALUE) {
1065             /*
1066              * case of a backward jump with an offset < -32768. In this case we
1067              * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
1068              * <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is the
1069              * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <L>
1070              * designates the instruction just after the GOTO_W.
1071              */
1072             if (opcode == Opcodes.GOTO) {
1073                 code.putByte(200); // GOTO_W
1074             } else if (opcode == Opcodes.JSR) {
1075                 code.putByte(201); // JSR_W
1076             } else {
1077                 // if the IF instruction is transformed into IFNOT GOTO_W the
1078                 // next instruction becomes the target of the IFNOT instruction
1079                 if (nextInsn != null) {
1080                     nextInsn.status |= Label.TARGET;
1081                 }
1082                 code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
1083                         : opcode ^ 1);
1084                 code.putShort(8); // jump offset
1085                 // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real
1086                 // GOTO_W because we might need to insert a frame just after (as
1087                 // the target of the IFNOTxxx jump instruction).
1088                 code.putByte(220);
1089                 cw.hasAsmInsns = true;
1090             }
1091             label.put(this, code, code.length - 1, true);
1092         } else if (isWide) {
1093             /*
1094              * case of a GOTO_W or JSR_W specified by the user (normally
1095              * ClassReader when used to resize instructions). In this case we
1096              * keep the original instruction.
1097              */
1098             code.putByte(opcode + 33);
1099             label.put(this, code, code.length - 1, true);
1100         } else {
1101             /*
1102              * case of a backward jump with an offset >= -32768, or of a forward
1103              * jump with, of course, an unknown offset. In these cases we store
1104              * the offset in 2 bytes (which will be increased in
1105              * resizeInstructions, if needed).
1106              */
1107             code.putByte(opcode);
1108             label.put(this, code, code.length - 1, false);
1109         }
1110         if (currentBlock != null) {
1111             if (nextInsn != null) {
1112                 // if the jump instruction is not a GOTO, the next instruction
1113                 // is also a successor of this instruction. Calling visitLabel
1114                 // adds the label of this next instruction as a successor of the
1115                 // current block, and starts a new basic block
1116                 visitLabel(nextInsn);
1117             }
1118             if (opcode == Opcodes.GOTO) {
1119                 noSuccessor();
1120             }
1121         }
1122     }
1123 
1124     @Override
1125     public void visitLabel(final Label label) {
1126         // resolves previous forward references to label, if any
1127         cw.hasAsmInsns |= label.resolve(this, code.length, code.data);
1128         // updates currentBlock
1129         if ((label.status & Label.DEBUG) != 0) {
1130             return;
1131         }
1132         if (compute == FRAMES) {
1133             if (currentBlock != null) {
1134                 if (label.position == currentBlock.position) {
1135                     // successive labels, do not start a new basic block
1136                     currentBlock.status |= (label.status & Label.TARGET);
1137                     label.frame = currentBlock.frame;
1138                     return;
1139                 }
1140                 // ends current block (with one new successor)
1141                 addSuccessor(Edge.NORMAL, label);
1142             }
1143             // begins a new current block
1144             currentBlock = label;
1145             if (label.frame == null) {
1146                 label.frame = new Frame();
1147                 label.frame.owner = label;
1148             }
1149             // updates the basic block list
1150             if (previousBlock != null) {
1151                 if (label.position == previousBlock.position) {
1152                     previousBlock.status |= (label.status & Label.TARGET);
1153                     label.frame = previousBlock.frame;
1154                     currentBlock = previousBlock;
1155                     return;
1156                 }
1157                 previousBlock.successor = label;
1158             }
1159             previousBlock = label;
1160         } else if (compute == INSERTED_FRAMES) {
1161             if (currentBlock == null) {
1162                 // This case should happen only once, for the visitLabel call in
1163                 // the constructor. Indeed, if compute is equal to
1164                 // INSERTED_FRAMES currentBlock can not be set back to null (see
1165                 // #noSuccessor).
1166                 currentBlock = label;
1167             } else {
1168                 // Updates the frame owner so that a correct frame offset is
1169                 // computed in visitFrame(Frame).
1170                 currentBlock.frame.owner = label;
1171             }
1172         } else if (compute == MAXS) {
1173             if (currentBlock != null) {
1174                 // ends current block (with one new successor)
1175                 currentBlock.outputStackMax = maxStackSize;
1176                 addSuccessor(stackSize, label);
1177             }
1178             // begins a new current block
1179             currentBlock = label;
1180             // resets the relative current and max stack sizes
1181             stackSize = 0;
1182             maxStackSize = 0;
1183             // updates the basic block list
1184             if (previousBlock != null) {
1185                 previousBlock.successor = label;
1186             }
1187             previousBlock = label;
1188         }
1189     }
1190 
1191     @Override
1192     public void visitLdcInsn(final Object cst) {
1193         lastCodeOffset = code.length;
1194         Item i = cw.newConstItem(cst);
1195         // Label currentBlock = this.currentBlock;
1196         if (currentBlock != null) {
1197             if (compute == FRAMES || compute == INSERTED_FRAMES) {
1198                 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
1199             } else {
1200                 int size;
1201                 // computes the stack size variation
1202                 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1203                     size = stackSize + 2;
1204                 } else {
1205                     size = stackSize + 1;
1206                 }
1207                 // updates current and max stack sizes
1208                 if (size > maxStackSize) {
1209                     maxStackSize = size;
1210                 }
1211                 stackSize = size;
1212             }
1213         }
1214         // adds the instruction to the bytecode of the method
1215         int index = i.index;
1216         if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1217             code.put12(20 /* LDC2_W */, index);
1218         } else if (index >= 256) {
1219             code.put12(19 /* LDC_W */, index);
1220         } else {
1221             code.put11(Opcodes.LDC, index);
1222         }
1223     }
1224 
1225     @Override
1226     public void visitIincInsn(final int var, final int increment) {
1227         lastCodeOffset = code.length;
1228         if (currentBlock != null) {
1229             if (compute == FRAMES || compute == INSERTED_FRAMES) {
1230                 currentBlock.frame.execute(Opcodes.IINC, var, null, null);
1231             }
1232         }
1233         if (compute != NOTHING) {
1234             // updates max locals
1235             int n = var + 1;
1236             if (n > maxLocals) {
1237                 maxLocals = n;
1238             }
1239         }
1240         // adds the instruction to the bytecode of the method
1241         if ((var > 255) || (increment > 127) || (increment < -128)) {
1242             code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
1243                     .putShort(increment);
1244         } else {
1245             code.putByte(Opcodes.IINC).put11(var, increment);
1246         }
1247     }
1248 
1249     @Override
1250     public void visitTableSwitchInsn(final int min, final int max,
1251             final Label dflt, final Label... labels) {
1252         lastCodeOffset = code.length;
1253         // adds the instruction to the bytecode of the method
1254         int source = code.length;
1255         code.putByte(Opcodes.TABLESWITCH);
1256         code.putByteArray(null, 0, (4 - code.length % 4) % 4);
1257         dflt.put(this, code, source, true);
1258         code.putInt(min).putInt(max);
1259         for (int i = 0; i < labels.length; ++i) {
1260             labels[i].put(this, code, source, true);
1261         }
1262         // updates currentBlock
1263         visitSwitchInsn(dflt, labels);
1264     }
1265 
1266     @Override
1267     public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
1268             final Label[] labels) {
1269         lastCodeOffset = code.length;
1270         // adds the instruction to the bytecode of the method
1271         int source = code.length;
1272         code.putByte(Opcodes.LOOKUPSWITCH);
1273         code.putByteArray(null, 0, (4 - code.length % 4) % 4);
1274         dflt.put(this, code, source, true);
1275         code.putInt(labels.length);
1276         for (int i = 0; i < labels.length; ++i) {
1277             code.putInt(keys[i]);
1278             labels[i].put(this, code, source, true);
1279         }
1280         // updates currentBlock
1281         visitSwitchInsn(dflt, labels);
1282     }
1283 
1284     private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1285         // Label currentBlock = this.currentBlock;
1286         if (currentBlock != null) {
1287             if (compute == FRAMES) {
1288                 currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1289                 // adds current block successors
1290                 addSuccessor(Edge.NORMAL, dflt);
1291                 dflt.getFirst().status |= Label.TARGET;
1292                 for (int i = 0; i < labels.length; ++i) {
1293                     addSuccessor(Edge.NORMAL, labels[i]);
1294                     labels[i].getFirst().status |= Label.TARGET;
1295                 }
1296             } else {
1297                 // updates current stack size (max stack size unchanged)
1298                 --stackSize;
1299                 // adds current block successors
1300                 addSuccessor(stackSize, dflt);
1301                 for (int i = 0; i < labels.length; ++i) {
1302                     addSuccessor(stackSize, labels[i]);
1303                 }
1304             }
1305             // ends current block
1306             noSuccessor();
1307         }
1308     }
1309 
1310     @Override
1311     public void visitMultiANewArrayInsn(final String desc, final int dims) {
1312         lastCodeOffset = code.length;
1313         Item i = cw.newStringishItem(ClassWriter.CLASS, desc);
1314         // Label currentBlock = this.currentBlock;
1315         if (currentBlock != null) {
1316             if (compute == FRAMES || compute == INSERTED_FRAMES) {
1317                 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
1318             } else {
1319                 // updates current stack size (max stack size unchanged because
1320                 // stack size variation always negative or null)
1321                 stackSize += 1 - dims;
1322             }
1323         }
1324         // adds the instruction to the bytecode of the method
1325         code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
1326     }
1327 
1328     @Override
1329     public AnnotationVisitor visitInsnAnnotation(int typeRef,
1330             TypePath typePath, String desc, boolean visible) {
1331         ByteVector bv = new ByteVector();
1332         // write target_type and target_info
1333         typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
1334         AnnotationWriter.putTarget(typeRef, typePath, bv);
1335         // write type, and reserve space for values count
1336         bv.putShort(cw.newUTF8(desc)).putShort(0);
1337         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1338                 bv.length - 2);
1339         if (visible) {
1340             aw.next = ctanns;
1341             ctanns = aw;
1342         } else {
1343             aw.next = ictanns;
1344             ictanns = aw;
1345         }
1346         return aw;
1347     }
1348 
1349     @Override
1350     public void visitTryCatchBlock(final Label start, final Label end,
1351             final Label handler, final String type) {
1352         ++handlerCount;
1353         Handler h = new Handler();
1354         h.start = start;
1355         h.end = end;
1356         h.handler = handler;
1357         h.desc = type;
1358         h.type = type != null ? cw.newClass(type) : 0;
1359         if (lastHandler == null) {
1360             firstHandler = h;
1361         } else {
1362             lastHandler.next = h;
1363         }
1364         lastHandler = h;
1365     }
1366 
1367     @Override
1368     public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
1369             TypePath typePath, String desc, boolean visible) {
1370         ByteVector bv = new ByteVector();
1371         // write target_type and target_info
1372         AnnotationWriter.putTarget(typeRef, typePath, bv);
1373         // write type, and reserve space for values count
1374         bv.putShort(cw.newUTF8(desc)).putShort(0);
1375         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1376                 bv.length - 2);
1377         if (visible) {
1378             aw.next = ctanns;
1379             ctanns = aw;
1380         } else {
1381             aw.next = ictanns;
1382             ictanns = aw;
1383         }
1384         return aw;
1385     }
1386 
1387     @Override
1388     public void visitLocalVariable(final String name, final String desc,
1389             final String signature, final Label start, final Label end,
1390             final int index) {
1391         if (signature != null) {
1392             if (localVarType == null) {
1393                 localVarType = new ByteVector();
1394             }
1395             ++localVarTypeCount;
1396             localVarType.putShort(start.position)
1397                     .putShort(end.position - start.position)
1398                     .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature))
1399                     .putShort(index);
1400         }
1401         if (localVar == null) {
1402             localVar = new ByteVector();
1403         }
1404         ++localVarCount;
1405         localVar.putShort(start.position)
1406                 .putShort(end.position - start.position)
1407                 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc))
1408                 .putShort(index);
1409         if (compute != NOTHING) {
1410             // updates max locals
1411             char c = desc.charAt(0);
1412             int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1413             if (n > maxLocals) {
1414                 maxLocals = n;
1415             }
1416         }
1417     }
1418 
1419     @Override
1420     public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
1421             TypePath typePath, Label[] start, Label[] end, int[] index,
1422             String desc, boolean visible) {
1423         ByteVector bv = new ByteVector();
1424         // write target_type and target_info
1425         bv.putByte(typeRef >>> 24).putShort(start.length);
1426         for (int i = 0; i < start.length; ++i) {
1427             bv.putShort(start[i].position)
1428                     .putShort(end[i].position - start[i].position)
1429                     .putShort(index[i]);
1430         }
1431         if (typePath == null) {
1432             bv.putByte(0);
1433         } else {
1434             int length = typePath.b[typePath.offset] * 2 + 1;
1435             bv.putByteArray(typePath.b, typePath.offset, length);
1436         }
1437         // write type, and reserve space for values count
1438         bv.putShort(cw.newUTF8(desc)).putShort(0);
1439         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1440                 bv.length - 2);
1441         if (visible) {
1442             aw.next = ctanns;
1443             ctanns = aw;
1444         } else {
1445             aw.next = ictanns;
1446             ictanns = aw;
1447         }
1448         return aw;
1449     }
1450 
1451     @Override
1452     public void visitLineNumber(final int line, final Label start) {
1453         if (lineNumber == null) {
1454             lineNumber = new ByteVector();
1455         }
1456         ++lineNumberCount;
1457         lineNumber.putShort(start.position);
1458         lineNumber.putShort(line);
1459     }
1460 
1461     @Override
1462     public void visitMaxs(final int maxStack, final int maxLocals) {
1463         if (compute == FRAMES) {
1464             // completes the control flow graph with exception handler blocks
1465             Handler handler = firstHandler;
1466             while (handler != null) {
1467                 Label l = handler.start.getFirst();
1468                 Label h = handler.handler.getFirst();
1469                 Label e = handler.end.getFirst();
1470                 // computes the kind of the edges to 'h'
1471                 String t = handler.desc == null ? "java/lang/Throwable"
1472                         : handler.desc;
1473                 int kind = Frame.OBJECT | cw.addType(t);
1474                 // h is an exception handler
1475                 h.status |= Label.TARGET;
1476                 // adds 'h' as a successor of labels between 'start' and 'end'
1477                 while (l != e) {
1478                     // creates an edge to 'h'
1479                     Edge b = new Edge();
1480                     b.info = kind;
1481                     b.successor = h;
1482                     // adds it to the successors of 'l'
1483                     b.next = l.successors;
1484                     l.successors = b;
1485                     // goes to the next label
1486                     l = l.successor;
1487                 }
1488                 handler = handler.next;
1489             }
1490 
1491             // creates and visits the first (implicit) frame
1492             Frame f = labels.frame;
1493             f.initInputFrame(cw, access, Type.getArgumentTypes(descriptor),
1494                     this.maxLocals);
1495             visitFrame(f);
1496 
1497             /*
1498              * fix point algorithm: mark the first basic block as 'changed'
1499              * (i.e. put it in the 'changed' list) and, while there are changed
1500              * basic blocks, choose one, mark it as unchanged, and update its
1501              * successors (which can be changed in the process).
1502              */
1503             int max = 0;
1504             Label changed = labels;
1505             while (changed != null) {
1506                 // removes a basic block from the list of changed basic blocks
1507                 Label l = changed;
1508                 changed = changed.next;
1509                 l.next = null;
1510                 f = l.frame;
1511                 // a reachable jump target must be stored in the stack map
1512                 if ((l.status & Label.TARGET) != 0) {
1513                     l.status |= Label.STORE;
1514                 }
1515                 // all visited labels are reachable, by definition
1516                 l.status |= Label.REACHABLE;
1517                 // updates the (absolute) maximum stack size
1518                 int blockMax = f.inputStack.length + l.outputStackMax;
1519                 if (blockMax > max) {
1520                     max = blockMax;
1521                 }
1522                 // updates the successors of the current basic block
1523                 Edge e = l.successors;
1524                 while (e != null) {
1525                     Label n = e.successor.getFirst();
1526                     boolean change = f.merge(cw, n.frame, e.info);
1527                     if (change && n.next == null) {
1528                         // if n has changed and is not already in the 'changed'
1529                         // list, adds it to this list
1530                         n.next = changed;
1531                         changed = n;
1532                     }
1533                     e = e.next;
1534                 }
1535             }
1536 
1537             // visits all the frames that must be stored in the stack map
1538             Label l = labels;
1539             while (l != null) {
1540                 f = l.frame;
1541                 if ((l.status & Label.STORE) != 0) {
1542                     visitFrame(f);
1543                 }
1544                 if ((l.status & Label.REACHABLE) == 0) {
1545                     // finds start and end of dead basic block
1546                     Label k = l.successor;
1547                     int start = l.position;
1548                     int end = (k == null ? code.length : k.position) - 1;
1549                     // if non empty basic block
1550                     if (end >= start) {
1551                         max = Math.max(max, 1);
1552                         // replaces instructions with NOP ... NOP ATHROW
1553                         for (int i = start; i < end; ++i) {
1554                             code.data[i] = Opcodes.NOP;
1555                         }
1556                         code.data[end] = (byte) Opcodes.ATHROW;
1557                         // emits a frame for this unreachable block
1558                         int frameIndex = startFrame(start, 0, 1);
1559                         frame[frameIndex] = Frame.OBJECT
1560                                 | cw.addType("java/lang/Throwable");
1561                         endFrame();
1562                         // removes the start-end range from the exception
1563                         // handlers
1564                         firstHandler = Handler.remove(firstHandler, l, k);
1565                     }
1566                 }
1567                 l = l.successor;
1568             }
1569 
1570             handler = firstHandler;
1571             handlerCount = 0;
1572             while (handler != null) {
1573                 handlerCount += 1;
1574                 handler = handler.next;
1575             }
1576 
1577             this.maxStack = max;
1578         } else if (compute == MAXS) {
1579             // completes the control flow graph with exception handler blocks
1580             Handler handler = firstHandler;
1581             while (handler != null) {
1582                 Label l = handler.start;
1583                 Label h = handler.handler;
1584                 Label e = handler.end;
1585                 // adds 'h' as a successor of labels between 'start' and 'end'
1586                 while (l != e) {
1587                     // creates an edge to 'h'
1588                     Edge b = new Edge();
1589                     b.info = Edge.EXCEPTION;
1590                     b.successor = h;
1591                     // adds it to the successors of 'l'
1592                     if ((l.status & Label.JSR) == 0) {
1593                         b.next = l.successors;
1594                         l.successors = b;
1595                     } else {
1596                         // if l is a JSR block, adds b after the first two edges
1597                         // to preserve the hypothesis about JSR block successors
1598                         // order (see {@link #visitJumpInsn})
1599                         b.next = l.successors.next.next;
1600                         l.successors.next.next = b;
1601                     }
1602                     // goes to the next label
1603                     l = l.successor;
1604                 }
1605                 handler = handler.next;
1606             }
1607 
1608             if (subroutines > 0) {
1609                 // completes the control flow graph with the RET successors
1610                 /*
1611                  * first step: finds the subroutines. This step determines, for
1612                  * each basic block, to which subroutine(s) it belongs.
1613                  */
1614                 // finds the basic blocks that belong to the "main" subroutine
1615                 int id = 0;
1616                 labels.visitSubroutine(null, 1, subroutines);
1617                 // finds the basic blocks that belong to the real subroutines
1618                 Label l = labels;
1619                 while (l != null) {
1620                     if ((l.status & Label.JSR) != 0) {
1621                         // the subroutine is defined by l's TARGET, not by l
1622                         Label subroutine = l.successors.next.successor;
1623                         // if this subroutine has not been visited yet...
1624                         if ((subroutine.status & Label.VISITED) == 0) {
1625                             // ...assigns it a new id and finds its basic blocks
1626                             id += 1;
1627                             subroutine.visitSubroutine(null, (id / 32L) << 32
1628                                     | (1L << (id % 32)), subroutines);
1629                         }
1630                     }
1631                     l = l.successor;
1632                 }
1633                 // second step: finds the successors of RET blocks
1634                 l = labels;
1635                 while (l != null) {
1636                     if ((l.status & Label.JSR) != 0) {
1637                         Label L = labels;
1638                         while (L != null) {
1639                             L.status &= ~Label.VISITED2;
1640                             L = L.successor;
1641                         }
1642                         // the subroutine is defined by l's TARGET, not by l
1643                         Label subroutine = l.successors.next.successor;
1644                         subroutine.visitSubroutine(l, 0, subroutines);
1645                     }
1646                     l = l.successor;
1647                 }
1648             }
1649 
1650             /*
1651              * control flow analysis algorithm: while the block stack is not
1652              * empty, pop a block from this stack, update the max stack size,
1653              * compute the true (non relative) begin stack size of the
1654              * successors of this block, and push these successors onto the
1655              * stack (unless they have already been pushed onto the stack).
1656              * Note: by hypothesis, the {@link Label#inputStackTop} of the
1657              * blocks in the block stack are the true (non relative) beginning
1658              * stack sizes of these blocks.
1659              */
1660             int max = 0;
1661             Label stack = labels;
1662             while (stack != null) {
1663                 // pops a block from the stack
1664                 Label l = stack;
1665                 stack = stack.next;
1666                 // computes the true (non relative) max stack size of this block
1667                 int start = l.inputStackTop;
1668                 int blockMax = start + l.outputStackMax;
1669                 // updates the global max stack size
1670                 if (blockMax > max) {
1671                     max = blockMax;
1672                 }
1673                 // analyzes the successors of the block
1674                 Edge b = l.successors;
1675                 if ((l.status & Label.JSR) != 0) {
1676                     // ignores the first edge of JSR blocks (virtual successor)
1677                     b = b.next;
1678                 }
1679                 while (b != null) {
1680                     l = b.successor;
1681                     // if this successor has not already been pushed...
1682                     if ((l.status & Label.PUSHED) == 0) {
1683                         // computes its true beginning stack size...
1684                         l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start
1685                                 + b.info;
1686                         // ...and pushes it onto the stack
1687                         l.status |= Label.PUSHED;
1688                         l.next = stack;
1689                         stack = l;
1690                     }
1691                     b = b.next;
1692                 }
1693             }
1694             this.maxStack = Math.max(maxStack, max);
1695         } else {
1696             this.maxStack = maxStack;
1697             this.maxLocals = maxLocals;
1698         }
1699     }
1700 
1701     @Override
1702     public void visitEnd() {
1703     }
1704 
1705     // ------------------------------------------------------------------------
1706     // Utility methods: control flow analysis algorithm
1707     // ------------------------------------------------------------------------
1708 
1709     /**
1710      * Adds a successor to the {@link #currentBlock currentBlock} block.
1711      *
1712      * @param info
1713      *            information about the control flow edge to be added.
1714      * @param successor
1715      *            the successor block to be added to the current block.
1716      */
1717     private void addSuccessor(final int info, final Label successor) {
1718         // creates and initializes an Edge object...
1719         Edge b = new Edge();
1720         b.info = info;
1721         b.successor = successor;
1722         // ...and adds it to the successor list of the currentBlock block
1723         b.next = currentBlock.successors;
1724         currentBlock.successors = b;
1725     }
1726 
1727     /**
1728      * Ends the current basic block. This method must be used in the case where
1729      * the current basic block does not have any successor.
1730      */
1731     private void noSuccessor() {
1732         if (compute == FRAMES) {
1733             Label l = new Label();
1734             l.frame = new Frame();
1735             l.frame.owner = l;
1736             l.resolve(this, code.length, code.data);
1737             previousBlock.successor = l;
1738             previousBlock = l;
1739         } else {
1740             currentBlock.outputStackMax = maxStackSize;
1741         }
1742         if (compute != INSERTED_FRAMES) {
1743             currentBlock = null;
1744         }
1745     }
1746 
1747     // ------------------------------------------------------------------------
1748     // Utility methods: stack map frames
1749     // ------------------------------------------------------------------------
1750 
1751     /**
1752      * Visits a frame that has been computed from scratch.
1753      *
1754      * @param f
1755      *            the frame that must be visited.
1756      */
1757     private void visitFrame(final Frame f) {
1758         int i, t;
1759         int nTop = 0;
1760         int nLocal = 0;
1761         int nStack = 0;
1762         int[] locals = f.inputLocals;
1763         int[] stacks = f.inputStack;
1764         // computes the number of locals (ignores TOP types that are just after
1765         // a LONG or a DOUBLE, and all trailing TOP types)
1766         for (i = 0; i < locals.length; ++i) {
1767             t = locals[i];
1768             if (t == Frame.TOP) {
1769                 ++nTop;
1770             } else {
1771                 nLocal += nTop + 1;
1772                 nTop = 0;
1773             }
1774             if (t == Frame.LONG || t == Frame.DOUBLE) {
1775                 ++i;
1776             }
1777         }
1778         // computes the stack size (ignores TOP types that are just after
1779         // a LONG or a DOUBLE)
1780         for (i = 0; i < stacks.length; ++i) {
1781             t = stacks[i];
1782             ++nStack;
1783             if (t == Frame.LONG || t == Frame.DOUBLE) {
1784                 ++i;
1785             }
1786         }
1787         // visits the frame and its content
1788         int frameIndex = startFrame(f.owner.position, nLocal, nStack);
1789         for (i = 0; nLocal > 0; ++i, --nLocal) {
1790             t = locals[i];
1791             frame[frameIndex++] = t;
1792             if (t == Frame.LONG || t == Frame.DOUBLE) {
1793                 ++i;
1794             }
1795         }
1796         for (i = 0; i < stacks.length; ++i) {
1797             t = stacks[i];
1798             frame[frameIndex++] = t;
1799             if (t == Frame.LONG || t == Frame.DOUBLE) {
1800                 ++i;
1801             }
1802         }
1803         endFrame();
1804     }
1805 
1806     /**
1807      * Visit the implicit first frame of this method.
1808      */
1809     private void visitImplicitFirstFrame() {
1810         // There can be at most descriptor.length() + 1 locals
1811         int frameIndex = startFrame(0, descriptor.length() + 1, 0);
1812         if ((access & Opcodes.ACC_STATIC) == 0) {
1813             if ((access & ACC_CONSTRUCTOR) == 0) {
1814                 frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
1815             } else {
1816                 frame[frameIndex++] = Frame.UNINITIALIZED_THIS;
1817             }
1818         }
1819         int i = 1;
1820         loop: while (true) {
1821             int j = i;
1822             switch (descriptor.charAt(i++)) {
1823             case 'Z':
1824             case 'C':
1825             case 'B':
1826             case 'S':
1827             case 'I':
1828                 frame[frameIndex++] = Frame.INTEGER;
1829                 break;
1830             case 'F':
1831                 frame[frameIndex++] = Frame.FLOAT;
1832                 break;
1833             case 'J':
1834                 frame[frameIndex++] = Frame.LONG;
1835                 break;
1836             case 'D':
1837                 frame[frameIndex++] = Frame.DOUBLE;
1838                 break;
1839             case '[':
1840                 while (descriptor.charAt(i) == '[') {
1841                     ++i;
1842                 }
1843                 if (descriptor.charAt(i) == 'L' || descriptor.charAt(i) == 'Q') {
1844                     ++i;
1845                     while (descriptor.charAt(i) != ';') {
1846                         ++i;
1847                     }
1848                 }
1849                 frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i));
1850                 break;
1851             case 'L':
1852             case 'Q':
1853                 while (descriptor.charAt(i) != ';') {
1854                     ++i;
1855                 }
1856                 frame[frameIndex++] = Frame.OBJECT
1857                         | cw.addType(descriptor.substring(j + 1, i++));
1858                 break;
1859             default:
1860                 break loop;
1861             }
1862         }
1863         frame[1] = frameIndex - 3;
1864         endFrame();
1865     }
1866 
1867     /**
1868      * Starts the visit of a stack map frame.
1869      *
1870      * @param offset
1871      *            the offset of the instruction to which the frame corresponds.
1872      * @param nLocal
1873      *            the number of local variables in the frame.
1874      * @param nStack
1875      *            the number of stack elements in the frame.
1876      * @return the index of the next element to be written in this frame.
1877      */
1878     private int startFrame(final int offset, final int nLocal, final int nStack) {
1879         int n = 3 + nLocal + nStack;
1880         if (frame == null || frame.length < n) {
1881             frame = new int[n];
1882         }
1883         frame[0] = offset;
1884         frame[1] = nLocal;
1885         frame[2] = nStack;
1886         return 3;
1887     }
1888 
1889     /**
1890      * Checks if the visit of the current frame {@link #frame} is finished, and
1891      * if yes, write it in the StackMapTable attribute.
1892      */
1893     private void endFrame() {
1894         if (previousFrame != null) { // do not write the first frame
1895             if (stackMap == null) {
1896                 stackMap = new ByteVector();
1897             }
1898             writeFrame();
1899             ++frameCount;
1900         }
1901         previousFrame = frame;
1902         frame = null;
1903     }
1904 
1905     /**
1906      * Compress and writes the current frame {@link #frame} in the StackMapTable
1907      * attribute.
1908      */
1909     private void writeFrame() {
1910         int clocalsSize = frame[1];
1911         int cstackSize = frame[2];
1912         if ((cw.version & 0xFFFF) < Opcodes.V1_6) {
1913             stackMap.putShort(frame[0]).putShort(clocalsSize);
1914             writeFrameTypes(3, 3 + clocalsSize);
1915             stackMap.putShort(cstackSize);
1916             writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1917             return;
1918         }
1919         int localsSize = previousFrame[1];
1920         int type = FULL_FRAME;
1921         int k = 0;
1922         int delta;
1923         if (frameCount == 0) {
1924             delta = frame[0];
1925         } else {
1926             delta = frame[0] - previousFrame[0] - 1;
1927         }
1928         if (cstackSize == 0) {
1929             k = clocalsSize - localsSize;
1930             switch (k) {
1931             case -3:
1932             case -2:
1933             case -1:
1934                 type = CHOP_FRAME;
1935                 localsSize = clocalsSize;
1936                 break;
1937             case 0:
1938                 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
1939                 break;
1940             case 1:
1941             case 2:
1942             case 3:
1943                 type = APPEND_FRAME;
1944                 break;
1945             }
1946         } else if (clocalsSize == localsSize && cstackSize == 1) {
1947             type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME
1948                     : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1949         }
1950         if (type != FULL_FRAME) {
1951             // verify if locals are the same
1952             int l = 3;
1953             for (int j = 0; j < localsSize; j++) {
1954                 if (frame[l] != previousFrame[l]) {
1955                     type = FULL_FRAME;
1956                     break;
1957                 }
1958                 l++;
1959             }
1960         }
1961         switch (type) {
1962         case SAME_FRAME:
1963             stackMap.putByte(delta);
1964             break;
1965         case SAME_LOCALS_1_STACK_ITEM_FRAME:
1966             stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
1967             writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1968             break;
1969         case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1970             stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(
1971                     delta);
1972             writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1973             break;
1974         case SAME_FRAME_EXTENDED:
1975             stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
1976             break;
1977         case CHOP_FRAME:
1978             stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1979             break;
1980         case APPEND_FRAME:
1981             stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1982             writeFrameTypes(3 + localsSize, 3 + clocalsSize);
1983             break;
1984         // case FULL_FRAME:
1985         default:
1986             stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize);
1987             writeFrameTypes(3, 3 + clocalsSize);
1988             stackMap.putShort(cstackSize);
1989             writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1990         }
1991     }
1992 
1993     /**
1994      * Writes some types of the current frame {@link #frame} into the
1995      * StackMapTableAttribute. This method converts types from the format used
1996      * in {@link Label} to the format used in StackMapTable attributes. In
1997      * particular, it converts type table indexes to constant pool indexes.
1998      *
1999      * @param start
2000      *            index of the first type in {@link #frame} to write.
2001      * @param end
2002      *            index of last type in {@link #frame} to write (exclusive).
2003      */
2004     private void writeFrameTypes(final int start, final int end) {
2005         for (int i = start; i < end; ++i) {
2006             int t = frame[i];
2007             int d = t & Frame.DIM;
2008             if (d == 0) {
2009                 int v = t & Frame.BASE_VALUE;
2010                 switch (t & Frame.BASE_KIND) {
2011                 case Frame.OBJECT:
2012                     stackMap.putByte(7).putShort(
2013                             cw.newClass(cw.typeTable[v].strVal1));
2014                     break;
2015                 case Frame.UNINITIALIZED:
2016                     stackMap.putByte(8).putShort(cw.typeTable[v].intVal);
2017                     break;
2018                 default:
2019                     stackMap.putByte(v);
2020                 }
2021             } else {
2022                 StringBuilder sb = new StringBuilder();
2023                 d >>= 28;
2024                 while (d-- > 0) {
2025                     sb.append('[');
2026                 }
2027                 if ((t & Frame.BASE_KIND) == Frame.OBJECT) {
2028                     sb.append('L');
2029                     sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1);
2030                     sb.append(';');
2031                 } else {
2032                     switch (t & 0xF) {
2033                     case 1:
2034                         sb.append('I');
2035                         break;
2036                     case 2:
2037                         sb.append('F');
2038                         break;
2039                     case 3:
2040                         sb.append('D');
2041                         break;
2042                     case 9:
2043                         sb.append('Z');
2044                         break;
2045                     case 10:
2046                         sb.append('B');
2047                         break;
2048                     case 11:
2049                         sb.append('C');
2050                         break;
2051                     case 12:
2052                         sb.append('S');
2053                         break;
2054                     default:
2055                         sb.append('J');
2056                     }
2057                 }
2058                 stackMap.putByte(7).putShort(cw.newClass(sb.toString()));
2059             }
2060         }
2061     }
2062 
2063     private void writeFrameType(final Object type) {
2064         if (type instanceof String) {
2065             stackMap.putByte(7).putShort(cw.newClass((String) type));
2066         } else if (type instanceof Integer) {
2067             stackMap.putByte(((Integer) type).intValue());
2068         } else {
2069             stackMap.putByte(8).putShort(((Label) type).position);
2070         }
2071     }
2072 
2073     // ------------------------------------------------------------------------
2074     // Utility methods: dump bytecode array
2075     // ------------------------------------------------------------------------
2076 
2077     /**
2078      * Returns the size of the bytecode of this method.
2079      *
2080      * @return the size of the bytecode of this method.
2081      */
2082     final int getSize() {
2083         if (classReaderOffset != 0) {
2084             return 6 + classReaderLength;
2085         }
2086         int size = 8;
2087         if (code.length > 0) {
2088             if (code.length > 65535) {
2089                 throw new RuntimeException("Method code too large!");
2090             }
2091             cw.newUTF8("Code");
2092             size += 18 + code.length + 8 * handlerCount;
2093             if (localVar != null) {
2094                 cw.newUTF8("LocalVariableTable");
2095                 size += 8 + localVar.length;
2096             }
2097             if (localVarType != null) {
2098                 cw.newUTF8("LocalVariableTypeTable");
2099                 size += 8 + localVarType.length;
2100             }
2101             if (lineNumber != null) {
2102                 cw.newUTF8("LineNumberTable");
2103                 size += 8 + lineNumber.length;
2104             }
2105             if (stackMap != null) {
2106                 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2107                 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
2108                 size += 8 + stackMap.length;
2109             }
2110             if (ctanns != null) {
2111                 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2112                 size += 8 + ctanns.getSize();
2113             }
2114             if (ictanns != null) {
2115                 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2116                 size += 8 + ictanns.getSize();
2117             }
2118             if (cattrs != null) {
2119                 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2120                         maxLocals);
2121             }
2122         }
2123         if (exceptionCount > 0) {
2124             cw.newUTF8("Exceptions");
2125             size += 8 + 2 * exceptionCount;
2126         }
2127         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2128             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2129                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2130                 cw.newUTF8("Synthetic");
2131                 size += 6;
2132             }
2133         }
2134         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2135             cw.newUTF8("Deprecated");
2136             size += 6;
2137         }
2138         if (signature != null) {
2139             cw.newUTF8("Signature");
2140             cw.newUTF8(signature);
2141             size += 8;
2142         }
2143         if (methodParameters != null) {
2144             cw.newUTF8("MethodParameters");
2145             size += 7 + methodParameters.length;
2146         }
2147         if (annd != null) {
2148             cw.newUTF8("AnnotationDefault");
2149             size += 6 + annd.length;
2150         }
2151         if (anns != null) {
2152             cw.newUTF8("RuntimeVisibleAnnotations");
2153             size += 8 + anns.getSize();
2154         }
2155         if (ianns != null) {
2156             cw.newUTF8("RuntimeInvisibleAnnotations");
2157             size += 8 + ianns.getSize();
2158         }
2159         if (tanns != null) {
2160             cw.newUTF8("RuntimeVisibleTypeAnnotations");
2161             size += 8 + tanns.getSize();
2162         }
2163         if (itanns != null) {
2164             cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2165             size += 8 + itanns.getSize();
2166         }
2167         if (panns != null) {
2168             cw.newUTF8("RuntimeVisibleParameterAnnotations");
2169             size += 7 + 2 * (panns.length - synthetics);
2170             for (int i = panns.length - 1; i >= synthetics; --i) {
2171                 size += panns[i] == null ? 0 : panns[i].getSize();
2172             }
2173         }
2174         if (ipanns != null) {
2175             cw.newUTF8("RuntimeInvisibleParameterAnnotations");
2176             size += 7 + 2 * (ipanns.length - synthetics);
2177             for (int i = ipanns.length - 1; i >= synthetics; --i) {
2178                 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
2179             }
2180         }
2181         if (attrs != null) {
2182             size += attrs.getSize(cw, null, 0, -1, -1);
2183         }
2184         return size;
2185     }
2186 
2187     /**
2188      * Puts the bytecode of this method in the given byte vector.
2189      *
2190      * @param out
2191      *            the byte vector into which the bytecode of this method must be
2192      *            copied.
2193      */
2194     final void put(final ByteVector out) {
2195         final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
2196         int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED
2197                 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
2198                 | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
2199         out.putShort(access & ~mask).putShort(name).putShort(desc);
2200         if (classReaderOffset != 0) {
2201             out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
2202             return;
2203         }
2204         int attributeCount = 0;
2205         if (code.length > 0) {
2206             ++attributeCount;
2207         }
2208         if (exceptionCount > 0) {
2209             ++attributeCount;
2210         }
2211         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2212             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2213                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2214                 ++attributeCount;
2215             }
2216         }
2217         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2218             ++attributeCount;
2219         }
2220         if (signature != null) {
2221             ++attributeCount;
2222         }
2223         if (methodParameters != null) {
2224             ++attributeCount;
2225         }
2226         if (annd != null) {
2227             ++attributeCount;
2228         }
2229         if (anns != null) {
2230             ++attributeCount;
2231         }
2232         if (ianns != null) {
2233             ++attributeCount;
2234         }
2235         if (tanns != null) {
2236             ++attributeCount;
2237         }
2238         if (itanns != null) {
2239             ++attributeCount;
2240         }
2241         if (panns != null) {
2242             ++attributeCount;
2243         }
2244         if (ipanns != null) {
2245             ++attributeCount;
2246         }
2247         if (attrs != null) {
2248             attributeCount += attrs.getCount();
2249         }
2250         out.putShort(attributeCount);
2251         if (code.length > 0) {
2252             int size = 12 + code.length + 8 * handlerCount;
2253             if (localVar != null) {
2254                 size += 8 + localVar.length;
2255             }
2256             if (localVarType != null) {
2257                 size += 8 + localVarType.length;
2258             }
2259             if (lineNumber != null) {
2260                 size += 8 + lineNumber.length;
2261             }
2262             if (stackMap != null) {
2263                 size += 8 + stackMap.length;
2264             }
2265             if (ctanns != null) {
2266                 size += 8 + ctanns.getSize();
2267             }
2268             if (ictanns != null) {
2269                 size += 8 + ictanns.getSize();
2270             }
2271             if (cattrs != null) {
2272                 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2273                         maxLocals);
2274             }
2275             out.putShort(cw.newUTF8("Code")).putInt(size);
2276             out.putShort(maxStack).putShort(maxLocals);
2277             out.putInt(code.length).putByteArray(code.data, 0, code.length);
2278             out.putShort(handlerCount);
2279             if (handlerCount > 0) {
2280                 Handler h = firstHandler;
2281                 while (h != null) {
2282                     out.putShort(h.start.position).putShort(h.end.position)
2283                             .putShort(h.handler.position).putShort(h.type);
2284                     h = h.next;
2285                 }
2286             }
2287             attributeCount = 0;
2288             if (localVar != null) {
2289                 ++attributeCount;
2290             }
2291             if (localVarType != null) {
2292                 ++attributeCount;
2293             }
2294             if (lineNumber != null) {
2295                 ++attributeCount;
2296             }
2297             if (stackMap != null) {
2298                 ++attributeCount;
2299             }
2300             if (ctanns != null) {
2301                 ++attributeCount;
2302             }
2303             if (ictanns != null) {
2304                 ++attributeCount;
2305             }
2306             if (cattrs != null) {
2307                 attributeCount += cattrs.getCount();
2308             }
2309             out.putShort(attributeCount);
2310             if (localVar != null) {
2311                 out.putShort(cw.newUTF8("LocalVariableTable"));
2312                 out.putInt(localVar.length + 2).putShort(localVarCount);
2313                 out.putByteArray(localVar.data, 0, localVar.length);
2314             }
2315             if (localVarType != null) {
2316                 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
2317                 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
2318                 out.putByteArray(localVarType.data, 0, localVarType.length);
2319             }
2320             if (lineNumber != null) {
2321                 out.putShort(cw.newUTF8("LineNumberTable"));
2322                 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
2323                 out.putByteArray(lineNumber.data, 0, lineNumber.length);
2324             }
2325             if (stackMap != null) {
2326                 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2327                 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
2328                 out.putInt(stackMap.length + 2).putShort(frameCount);
2329                 out.putByteArray(stackMap.data, 0, stackMap.length);
2330             }
2331             if (ctanns != null) {
2332                 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2333                 ctanns.put(out);
2334             }
2335             if (ictanns != null) {
2336                 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2337                 ictanns.put(out);
2338             }
2339             if (cattrs != null) {
2340                 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
2341             }
2342         }
2343         if (exceptionCount > 0) {
2344             out.putShort(cw.newUTF8("Exceptions")).putInt(
2345                     2 * exceptionCount + 2);
2346             out.putShort(exceptionCount);
2347             for (int i = 0; i < exceptionCount; ++i) {
2348                 out.putShort(exceptions[i]);
2349             }
2350         }
2351         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2352             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2353                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2354                 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
2355             }
2356         }
2357         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2358             out.putShort(cw.newUTF8("Deprecated")).putInt(0);
2359         }
2360         if (signature != null) {
2361             out.putShort(cw.newUTF8("Signature")).putInt(2)
2362                     .putShort(cw.newUTF8(signature));
2363         }
2364         if (methodParameters != null) {
2365             out.putShort(cw.newUTF8("MethodParameters"));
2366             out.putInt(methodParameters.length + 1).putByte(
2367                     methodParametersCount);
2368             out.putByteArray(methodParameters.data, 0, methodParameters.length);
2369         }
2370         if (annd != null) {
2371             out.putShort(cw.newUTF8("AnnotationDefault"));
2372             out.putInt(annd.length);
2373             out.putByteArray(annd.data, 0, annd.length);
2374         }
2375         if (anns != null) {
2376             out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2377             anns.put(out);
2378         }
2379         if (ianns != null) {
2380             out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2381             ianns.put(out);
2382         }
2383         if (tanns != null) {
2384             out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2385             tanns.put(out);
2386         }
2387         if (itanns != null) {
2388             out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2389             itanns.put(out);
2390         }
2391         if (panns != null) {
2392             out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
2393             AnnotationWriter.put(panns, synthetics, out);
2394         }
2395         if (ipanns != null) {
2396             out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
2397             AnnotationWriter.put(ipanns, synthetics, out);
2398         }
2399         if (attrs != null) {
2400             attrs.put(cw, null, 0, -1, -1, out);
2401         }
2402     }
2403 }