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 
  60 package jdk.internal.org.objectweb.asm;
  61 
  62 /**
  63  * A {@link MethodVisitor} that generates a corresponding 'method_info' structure, as defined in the
  64  * Java Virtual Machine Specification (JVMS).
  65  *
  66  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6">JVMS
  67  *     4.6</a>
  68  * @author Eric Bruneton
  69  * @author Eugene Kuleshov
  70  */
  71 final class MethodWriter extends MethodVisitor {
  72 
  73     /** Indicates that nothing must be computed. */
  74     static final int COMPUTE_NOTHING = 0;
  75 
  76     /**
  77       * Indicates that the maximum stack size and the maximum number of local variables must be
  78       * computed, from scratch.
  79       */
  80     static final int COMPUTE_MAX_STACK_AND_LOCAL = 1;
  81 
  82     /**
  83       * Indicates that the maximum stack size and the maximum number of local variables must be
  84       * computed, from the existing stack map frames. This can be done more efficiently than with the
  85       * control flow graph algorithm used for {@link #COMPUTE_MAX_STACK_AND_LOCAL}, by using a linear
  86       * scan of the bytecode instructions.
  87       */
  88     static final int COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES = 2;
  89 
  90     /**
  91       * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not
  92       * computed. They should all be of type F_NEW and should be sufficient to compute the content of
  93       * the F_INSERT frames, together with the bytecode instructions between a F_NEW and a F_INSERT
  94       * frame - and without any knowledge of the type hierarchy (by definition of F_INSERT).
  95       */
  96     static final int COMPUTE_INSERTED_FRAMES = 3;
  97 
  98     /**
  99       * Indicates that all the stack map frames must be computed. In this case the maximum stack size
 100       * and the maximum number of local variables is also computed.
 101       */
 102     static final int COMPUTE_ALL_FRAMES = 4;
 103 
 104     /** Indicates that {@link #STACK_SIZE_DELTA} is not applicable (not constant or never used). */
 105     private static final int NA = 0;
 106 
 107     /**
 108       * The stack size variation corresponding to each JVM opcode. The stack size variation for opcode
 109       * 'o' is given by the array element at index 'o'.
 110       *
 111       * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html">JVMS 6</a>
 112       */
 113     private static final int[] STACK_SIZE_DELTA = {
 114         0, // nop = 0 (0x0)
 115         1, // aconst_null = 1 (0x1)
 116         1, // iconst_m1 = 2 (0x2)
 117         1, // iconst_0 = 3 (0x3)
 118         1, // iconst_1 = 4 (0x4)
 119         1, // iconst_2 = 5 (0x5)
 120         1, // iconst_3 = 6 (0x6)
 121         1, // iconst_4 = 7 (0x7)
 122         1, // iconst_5 = 8 (0x8)
 123         2, // lconst_0 = 9 (0x9)
 124         2, // lconst_1 = 10 (0xa)
 125         1, // fconst_0 = 11 (0xb)
 126         1, // fconst_1 = 12 (0xc)
 127         1, // fconst_2 = 13 (0xd)
 128         2, // dconst_0 = 14 (0xe)
 129         2, // dconst_1 = 15 (0xf)
 130         1, // bipush = 16 (0x10)
 131         1, // sipush = 17 (0x11)
 132         1, // ldc = 18 (0x12)
 133         NA, // ldc_w = 19 (0x13)
 134         NA, // ldc2_w = 20 (0x14)
 135         1, // iload = 21 (0x15)
 136         2, // lload = 22 (0x16)
 137         1, // fload = 23 (0x17)
 138         2, // dload = 24 (0x18)
 139         1, // aload = 25 (0x19)
 140         NA, // iload_0 = 26 (0x1a)
 141         NA, // iload_1 = 27 (0x1b)
 142         NA, // iload_2 = 28 (0x1c)
 143         NA, // iload_3 = 29 (0x1d)
 144         NA, // lload_0 = 30 (0x1e)
 145         NA, // lload_1 = 31 (0x1f)
 146         NA, // lload_2 = 32 (0x20)
 147         NA, // lload_3 = 33 (0x21)
 148         NA, // fload_0 = 34 (0x22)
 149         NA, // fload_1 = 35 (0x23)
 150         NA, // fload_2 = 36 (0x24)
 151         NA, // fload_3 = 37 (0x25)
 152         NA, // dload_0 = 38 (0x26)
 153         NA, // dload_1 = 39 (0x27)
 154         NA, // dload_2 = 40 (0x28)
 155         NA, // dload_3 = 41 (0x29)
 156         NA, // aload_0 = 42 (0x2a)
 157         NA, // aload_1 = 43 (0x2b)
 158         NA, // aload_2 = 44 (0x2c)
 159         NA, // aload_3 = 45 (0x2d)
 160         -1, // iaload = 46 (0x2e)
 161         0, // laload = 47 (0x2f)
 162         -1, // faload = 48 (0x30)
 163         0, // daload = 49 (0x31)
 164         -1, // aaload = 50 (0x32)
 165         -1, // baload = 51 (0x33)
 166         -1, // caload = 52 (0x34)
 167         -1, // saload = 53 (0x35)
 168         -1, // istore = 54 (0x36)
 169         -2, // lstore = 55 (0x37)
 170         -1, // fstore = 56 (0x38)
 171         -2, // dstore = 57 (0x39)
 172         -1, // astore = 58 (0x3a)
 173         NA, // istore_0 = 59 (0x3b)
 174         NA, // istore_1 = 60 (0x3c)
 175         NA, // istore_2 = 61 (0x3d)
 176         NA, // istore_3 = 62 (0x3e)
 177         NA, // lstore_0 = 63 (0x3f)
 178         NA, // lstore_1 = 64 (0x40)
 179         NA, // lstore_2 = 65 (0x41)
 180         NA, // lstore_3 = 66 (0x42)
 181         NA, // fstore_0 = 67 (0x43)
 182         NA, // fstore_1 = 68 (0x44)
 183         NA, // fstore_2 = 69 (0x45)
 184         NA, // fstore_3 = 70 (0x46)
 185         NA, // dstore_0 = 71 (0x47)
 186         NA, // dstore_1 = 72 (0x48)
 187         NA, // dstore_2 = 73 (0x49)
 188         NA, // dstore_3 = 74 (0x4a)
 189         NA, // astore_0 = 75 (0x4b)
 190         NA, // astore_1 = 76 (0x4c)
 191         NA, // astore_2 = 77 (0x4d)
 192         NA, // astore_3 = 78 (0x4e)
 193         -3, // iastore = 79 (0x4f)
 194         -4, // lastore = 80 (0x50)
 195         -3, // fastore = 81 (0x51)
 196         -4, // dastore = 82 (0x52)
 197         -3, // aastore = 83 (0x53)
 198         -3, // bastore = 84 (0x54)
 199         -3, // castore = 85 (0x55)
 200         -3, // sastore = 86 (0x56)
 201         -1, // pop = 87 (0x57)
 202         -2, // pop2 = 88 (0x58)
 203         1, // dup = 89 (0x59)
 204         1, // dup_x1 = 90 (0x5a)
 205         1, // dup_x2 = 91 (0x5b)
 206         2, // dup2 = 92 (0x5c)
 207         2, // dup2_x1 = 93 (0x5d)
 208         2, // dup2_x2 = 94 (0x5e)
 209         0, // swap = 95 (0x5f)
 210         -1, // iadd = 96 (0x60)
 211         -2, // ladd = 97 (0x61)
 212         -1, // fadd = 98 (0x62)
 213         -2, // dadd = 99 (0x63)
 214         -1, // isub = 100 (0x64)
 215         -2, // lsub = 101 (0x65)
 216         -1, // fsub = 102 (0x66)
 217         -2, // dsub = 103 (0x67)
 218         -1, // imul = 104 (0x68)
 219         -2, // lmul = 105 (0x69)
 220         -1, // fmul = 106 (0x6a)
 221         -2, // dmul = 107 (0x6b)
 222         -1, // idiv = 108 (0x6c)
 223         -2, // ldiv = 109 (0x6d)
 224         -1, // fdiv = 110 (0x6e)
 225         -2, // ddiv = 111 (0x6f)
 226         -1, // irem = 112 (0x70)
 227         -2, // lrem = 113 (0x71)
 228         -1, // frem = 114 (0x72)
 229         -2, // drem = 115 (0x73)
 230         0, // ineg = 116 (0x74)
 231         0, // lneg = 117 (0x75)
 232         0, // fneg = 118 (0x76)
 233         0, // dneg = 119 (0x77)
 234         -1, // ishl = 120 (0x78)
 235         -1, // lshl = 121 (0x79)
 236         -1, // ishr = 122 (0x7a)
 237         -1, // lshr = 123 (0x7b)
 238         -1, // iushr = 124 (0x7c)
 239         -1, // lushr = 125 (0x7d)
 240         -1, // iand = 126 (0x7e)
 241         -2, // land = 127 (0x7f)
 242         -1, // ior = 128 (0x80)
 243         -2, // lor = 129 (0x81)
 244         -1, // ixor = 130 (0x82)
 245         -2, // lxor = 131 (0x83)
 246         0, // iinc = 132 (0x84)
 247         1, // i2l = 133 (0x85)
 248         0, // i2f = 134 (0x86)
 249         1, // i2d = 135 (0x87)
 250         -1, // l2i = 136 (0x88)
 251         -1, // l2f = 137 (0x89)
 252         0, // l2d = 138 (0x8a)
 253         0, // f2i = 139 (0x8b)
 254         1, // f2l = 140 (0x8c)
 255         1, // f2d = 141 (0x8d)
 256         -1, // d2i = 142 (0x8e)
 257         0, // d2l = 143 (0x8f)
 258         -1, // d2f = 144 (0x90)
 259         0, // i2b = 145 (0x91)
 260         0, // i2c = 146 (0x92)
 261         0, // i2s = 147 (0x93)
 262         -3, // lcmp = 148 (0x94)
 263         -1, // fcmpl = 149 (0x95)
 264         -1, // fcmpg = 150 (0x96)
 265         -3, // dcmpl = 151 (0x97)
 266         -3, // dcmpg = 152 (0x98)
 267         -1, // ifeq = 153 (0x99)
 268         -1, // ifne = 154 (0x9a)
 269         -1, // iflt = 155 (0x9b)
 270         -1, // ifge = 156 (0x9c)
 271         -1, // ifgt = 157 (0x9d)
 272         -1, // ifle = 158 (0x9e)
 273         -2, // if_icmpeq = 159 (0x9f)
 274         -2, // if_icmpne = 160 (0xa0)
 275         -2, // if_icmplt = 161 (0xa1)
 276         -2, // if_icmpge = 162 (0xa2)
 277         -2, // if_icmpgt = 163 (0xa3)
 278         -2, // if_icmple = 164 (0xa4)
 279         -2, // if_acmpeq = 165 (0xa5)
 280         -2, // if_acmpne = 166 (0xa6)
 281         0, // goto = 167 (0xa7)
 282         1, // jsr = 168 (0xa8)
 283         0, // ret = 169 (0xa9)
 284         -1, // tableswitch = 170 (0xaa)
 285         -1, // lookupswitch = 171 (0xab)
 286         -1, // ireturn = 172 (0xac)
 287         -2, // lreturn = 173 (0xad)
 288         -1, // freturn = 174 (0xae)
 289         -2, // dreturn = 175 (0xaf)
 290         -1, // areturn = 176 (0xb0)
 291         0, // return = 177 (0xb1)
 292         NA, // getstatic = 178 (0xb2)
 293         NA, // putstatic = 179 (0xb3)
 294         NA, // getfield = 180 (0xb4)
 295         NA, // putfield = 181 (0xb5)
 296         NA, // invokevirtual = 182 (0xb6)
 297         NA, // invokespecial = 183 (0xb7)
 298         NA, // invokestatic = 184 (0xb8)
 299         NA, // invokeinterface = 185 (0xb9)
 300         NA, // invokedynamic = 186 (0xba)
 301         1, // new = 187 (0xbb)
 302         0, // newarray = 188 (0xbc)
 303         0, // anewarray = 189 (0xbd)
 304         0, // arraylength = 190 (0xbe)
 305         NA, // athrow = 191 (0xbf)
 306         0, // checkcast = 192 (0xc0)
 307         0, // instanceof = 193 (0xc1)
 308         -1, // monitorenter = 194 (0xc2)
 309         -1, // monitorexit = 195 (0xc3)
 310         NA, // wide = 196 (0xc4)
 311         NA, // multianewarray = 197 (0xc5)
 312         -1, // ifnull = 198 (0xc6)
 313         -1, // ifnonnull = 199 (0xc7)
 314         NA, // goto_w = 200 (0xc8)
 315         NA, // jsr_w = 201 (0xc9)
 316         NA, // breakpoint = 202 (0xca)
 317         NA, // default = 203 (0xcb)
 318         NA, // withfield = 204 (0xcc)
 319     };
 320 
 321     /** Where the constants used in this MethodWriter must be stored. */
 322     private final SymbolTable symbolTable;
 323 
 324     // Note: fields are ordered as in the method_info structure, and those related to attributes are
 325     // ordered as in Section 4.7 of the JVMS.
 326 
 327     /**
 328       * The access_flags field of the method_info JVMS structure. This field can contain ASM specific
 329       * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
 330       * ClassFile structure.
 331       */
 332     private final int accessFlags;
 333 
 334     /** The name_index field of the method_info JVMS structure. */
 335     private final int nameIndex;
 336 
 337     /** The name of this method. */
 338     private final String name;
 339 
 340     /** The descriptor_index field of the method_info JVMS structure. */
 341     private final int descriptorIndex;
 342 
 343     /** The descriptor of this method. */
 344     private final String descriptor;
 345 
 346     // Code attribute fields and sub attributes:
 347 
 348     /** The max_stack field of the Code attribute. */
 349     private int maxStack;
 350 
 351     /** The max_locals field of the Code attribute. */
 352     private int maxLocals;
 353 
 354     /** The 'code' field of the Code attribute. */
 355     private final ByteVector code = new ByteVector();
 356 
 357     /**
 358       * The first element in the exception handler list (used to generate the exception_table of the
 359       * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May
 360       * be {@literal null}.
 361       */
 362     private Handler firstHandler;
 363 
 364     /**
 365       * The last element in the exception handler list (used to generate the exception_table of the
 366       * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May
 367       * be {@literal null}.
 368       */
 369     private Handler lastHandler;
 370 
 371     /** The line_number_table_length field of the LineNumberTable code attribute. */
 372     private int lineNumberTableLength;
 373 
 374     /** The line_number_table array of the LineNumberTable code attribute, or {@literal null}. */
 375     private ByteVector lineNumberTable;
 376 
 377     /** The local_variable_table_length field of the LocalVariableTable code attribute. */
 378     private int localVariableTableLength;
 379 
 380     /**
 381       * The local_variable_table array of the LocalVariableTable code attribute, or {@literal null}.
 382       */
 383     private ByteVector localVariableTable;
 384 
 385     /** The local_variable_type_table_length field of the LocalVariableTypeTable code attribute. */
 386     private int localVariableTypeTableLength;
 387 
 388     /**
 389       * The local_variable_type_table array of the LocalVariableTypeTable code attribute, or {@literal
 390       * null}.
 391       */
 392     private ByteVector localVariableTypeTable;
 393 
 394     /** The number_of_entries field of the StackMapTable code attribute. */
 395     private int stackMapTableNumberOfEntries;
 396 
 397     /** The 'entries' array of the StackMapTable code attribute. */
 398     private ByteVector stackMapTableEntries;
 399 
 400     /**
 401       * The last runtime visible type annotation of the Code attribute. The previous ones can be
 402       * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
 403       */
 404     private AnnotationWriter lastCodeRuntimeVisibleTypeAnnotation;
 405 
 406     /**
 407       * The last runtime invisible type annotation of the Code attribute. The previous ones can be
 408       * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
 409       */
 410     private AnnotationWriter lastCodeRuntimeInvisibleTypeAnnotation;
 411 
 412     /**
 413       * The first non standard attribute of the Code attribute. The next ones can be accessed with the
 414       * {@link Attribute#nextAttribute} field. May be {@literal null}.
 415       *
 416       * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
 417       * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
 418       * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the
 419       * reverse order specified by the user.
 420       */
 421     private Attribute firstCodeAttribute;
 422 
 423     // Other method_info attributes:
 424 
 425     /** The number_of_exceptions field of the Exceptions attribute. */
 426     private final int numberOfExceptions;
 427 
 428     /** The exception_index_table array of the Exceptions attribute, or {@literal null}. */
 429     private final int[] exceptionIndexTable;
 430 
 431     /** The signature_index field of the Signature attribute. */
 432     private final int signatureIndex;
 433 
 434     /**
 435       * The last runtime visible annotation of this method. The previous ones can be accessed with the
 436       * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
 437       */
 438     private AnnotationWriter lastRuntimeVisibleAnnotation;
 439 
 440     /**
 441       * The last runtime invisible annotation of this method. The previous ones can be accessed with
 442       * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
 443       */
 444     private AnnotationWriter lastRuntimeInvisibleAnnotation;
 445 
 446     /** The number of method parameters that can have runtime visible annotations, or 0. */
 447     private int visibleAnnotableParameterCount;
 448 
 449     /**
 450       * The runtime visible parameter annotations of this method. Each array element contains the last
 451       * annotation of a parameter (which can be {@literal null} - the previous ones can be accessed
 452       * with the {@link AnnotationWriter#previousAnnotation} field). May be {@literal null}.
 453       */
 454     private AnnotationWriter[] lastRuntimeVisibleParameterAnnotations;
 455 
 456     /** The number of method parameters that can have runtime visible annotations, or 0. */
 457     private int invisibleAnnotableParameterCount;
 458 
 459     /**
 460       * The runtime invisible parameter annotations of this method. Each array element contains the
 461       * last annotation of a parameter (which can be {@literal null} - the previous ones can be
 462       * accessed with the {@link AnnotationWriter#previousAnnotation} field). May be {@literal null}.
 463       */
 464     private AnnotationWriter[] lastRuntimeInvisibleParameterAnnotations;
 465 
 466     /**
 467       * The last runtime visible type annotation of this method. The previous ones can be accessed with
 468       * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
 469       */
 470     private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
 471 
 472     /**
 473       * The last runtime invisible type annotation of this method. The previous ones can be accessed
 474       * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
 475       */
 476     private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
 477 
 478     /** The default_value field of the AnnotationDefault attribute, or {@literal null}. */
 479     private ByteVector defaultValue;
 480 
 481     /** The parameters_count field of the MethodParameters attribute. */
 482     private int parametersCount;
 483 
 484     /** The 'parameters' array of the MethodParameters attribute, or {@literal null}. */
 485     private ByteVector parameters;
 486 
 487     /**
 488       * The first non standard attribute of this method. The next ones can be accessed with the {@link
 489       * Attribute#nextAttribute} field. May be {@literal null}.
 490       *
 491       * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
 492       * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
 493       * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the
 494       * reverse order specified by the user.
 495       */
 496     private Attribute firstAttribute;
 497 
 498     // -----------------------------------------------------------------------------------------------
 499     // Fields used to compute the maximum stack size and number of locals, and the stack map frames
 500     // -----------------------------------------------------------------------------------------------
 501 
 502     /**
 503       * Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link
 504       * #COMPUTE_INSERTED_FRAMES}, {@link COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link
 505       * #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}.
 506       */
 507     private final int compute;
 508 
 509     /**
 510       * The first basic block of the method. The next ones (in bytecode offset order) can be accessed
 511       * with the {@link Label#nextBasicBlock} field.
 512       */
 513     private Label firstBasicBlock;
 514 
 515     /**
 516       * The last basic block of the method (in bytecode offset order). This field is updated each time
 517       * a basic block is encountered, and is used to append it at the end of the basic block list.
 518       */
 519     private Label lastBasicBlock;
 520 
 521     /**
 522       * The current basic block, i.e. the basic block of the last visited instruction. When {@link
 523       * #compute} is equal to {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_ALL_FRAMES}, this
 524       * field is {@literal null} for unreachable code. When {@link #compute} is equal to {@link
 525       * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES} or {@link #COMPUTE_INSERTED_FRAMES}, this field stays
 526       * unchanged throughout the whole method (i.e. the whole code is seen as a single basic block;
 527       * indeed, the existing frames are sufficient by hypothesis to compute any intermediate frame -
 528       * and the maximum stack size as well - without using any control flow graph).
 529       */
 530     private Label currentBasicBlock;
 531 
 532     /**
 533       * The relative stack size after the last visited instruction. This size is relative to the
 534       * beginning of {@link #currentBasicBlock}, i.e. the true stack size after the last visited
 535       * instruction is equal to the {@link Label#inputStackSize} of the current basic block plus {@link
 536       * #relativeStackSize}. When {@link #compute} is equal to {@link
 537       * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of
 538       * the method, so this relative size is also equal to the absolute stack size after the last
 539       * visited instruction.
 540       */
 541     private int relativeStackSize;
 542 
 543     /**
 544       * The maximum relative stack size after the last visited instruction. This size is relative to
 545       * the beginning of {@link #currentBasicBlock}, i.e. the true maximum stack size after the last
 546       * visited instruction is equal to the {@link Label#inputStackSize} of the current basic block
 547       * plus {@link #maxRelativeStackSize}.When {@link #compute} is equal to {@link
 548       * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of
 549       * the method, so this relative size is also equal to the absolute maximum stack size after the
 550       * last visited instruction.
 551       */
 552     private int maxRelativeStackSize;
 553 
 554     /** The number of local variables in the last visited stack map frame. */
 555     private int currentLocals;
 556 
 557     /** The bytecode offset of the last frame that was written in {@link #stackMapTableEntries}. */
 558     private int previousFrameOffset;
 559 
 560     /**
 561       * The last frame that was written in {@link #stackMapTableEntries}. This field has the same
 562       * format as {@link #currentFrame}.
 563       */
 564     private int[] previousFrame;
 565 
 566     /**
 567       * The current stack map frame. The first element contains the bytecode offset of the instruction
 568       * to which the frame corresponds, the second element is the number of locals and the third one is
 569       * the number of stack elements. The local variables start at index 3 and are followed by the
 570       * operand stack elements. In summary frame[0] = offset, frame[1] = numLocal, frame[2] = numStack.
 571       * Local variables and operand stack entries contain abstract types, as defined in {@link Frame},
 572       * but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND} or {@link
 573       * Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array entry.
 574       */
 575     private int[] currentFrame;
 576 
 577     /** Whether this method contains subroutines. */
 578     private boolean hasSubroutines;
 579 
 580     // -----------------------------------------------------------------------------------------------
 581     // Other miscellaneous status fields
 582     // -----------------------------------------------------------------------------------------------
 583 
 584     /** Whether the bytecode of this method contains ASM specific instructions. */
 585     private boolean hasAsmInstructions;
 586 
 587     /**
 588       * The start offset of the last visited instruction. Used to set the offset field of type
 589       * annotations of type 'offset_target' (see <a
 590       * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS
 591       * 4.7.20.1</a>).
 592       */
 593     private int lastBytecodeOffset;
 594 
 595     /**
 596       * The offset in bytes in {@link SymbolTable#getSource} from which the method_info for this method
 597       * (excluding its first 6 bytes) must be copied, or 0.
 598       */
 599     private int sourceOffset;
 600 
 601     /**
 602       * The length in bytes in {@link SymbolTable#getSource} which must be copied to get the
 603       * method_info for this method (excluding its first 6 bytes for access_flags, name_index and
 604       * descriptor_index).
 605       */
 606     private int sourceLength;
 607 
 608     // -----------------------------------------------------------------------------------------------
 609     // Constructor and accessors
 610     // -----------------------------------------------------------------------------------------------
 611 
 612     /**
 613       * Constructs a new {@link MethodWriter}.
 614       *
 615       * @param symbolTable where the constants used in this AnnotationWriter must be stored.
 616       * @param access the method's access flags (see {@link Opcodes}).
 617       * @param name the method's name.
 618       * @param descriptor the method's descriptor (see {@link Type}).
 619       * @param signature the method's signature. May be {@literal null}.
 620       * @param exceptions the internal names of the method's exceptions. May be {@literal null}.
 621       * @param compute indicates what must be computed (see #compute).
 622       */
 623     MethodWriter(
 624             final SymbolTable symbolTable,
 625             final int access,
 626             final String name,
 627             final String descriptor,
 628             final String signature,
 629             final String[] exceptions,
 630             final int compute) {
 631         super(/* latest api = */ Opcodes.ASM9);
 632         this.symbolTable = symbolTable;
 633         this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
 634         this.nameIndex = symbolTable.addConstantUtf8(name);
 635         this.name = name;
 636         this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
 637         this.descriptor = descriptor;
 638         this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature);
 639         if (exceptions != null && exceptions.length > 0) {
 640             numberOfExceptions = exceptions.length;
 641             this.exceptionIndexTable = new int[numberOfExceptions];
 642             for (int i = 0; i < numberOfExceptions; ++i) {
 643                 this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index;
 644             }
 645         } else {
 646             numberOfExceptions = 0;
 647             this.exceptionIndexTable = null;
 648         }
 649         this.compute = compute;
 650         if (compute != COMPUTE_NOTHING) {
 651             // Update maxLocals and currentLocals.
 652             int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
 653             if ((access & Opcodes.ACC_STATIC) != 0) {
 654                 --argumentsSize;
 655             }
 656             maxLocals = argumentsSize;
 657             currentLocals = argumentsSize;
 658             // Create and visit the label for the first basic block.
 659             firstBasicBlock = new Label();
 660             visitLabel(firstBasicBlock);
 661         }
 662     }
 663 
 664     boolean hasFrames() {
 665         return stackMapTableNumberOfEntries > 0;
 666     }
 667 
 668     boolean hasAsmInstructions() {
 669         return hasAsmInstructions;
 670     }
 671 
 672     // -----------------------------------------------------------------------------------------------
 673     // Implementation of the MethodVisitor abstract class
 674     // -----------------------------------------------------------------------------------------------
 675 
 676     @Override
 677     public void visitParameter(final String name, final int access) {
 678         if (parameters == null) {
 679             parameters = new ByteVector();
 680         }
 681         ++parametersCount;
 682         parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access);
 683     }
 684 
 685     @Override
 686     public AnnotationVisitor visitAnnotationDefault() {
 687         defaultValue = new ByteVector();
 688         return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null);
 689     }
 690 
 691     @Override
 692     public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
 693         if (visible) {
 694             return lastRuntimeVisibleAnnotation =
 695                     AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
 696         } else {
 697             return lastRuntimeInvisibleAnnotation =
 698                     AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
 699         }
 700     }
 701 
 702     @Override
 703     public AnnotationVisitor visitTypeAnnotation(
 704             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
 705         if (visible) {
 706             return lastRuntimeVisibleTypeAnnotation =
 707                     AnnotationWriter.create(
 708                             symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
 709         } else {
 710             return lastRuntimeInvisibleTypeAnnotation =
 711                     AnnotationWriter.create(
 712                             symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
 713         }
 714     }
 715 
 716     @Override
 717     public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
 718         if (visible) {
 719             visibleAnnotableParameterCount = parameterCount;
 720         } else {
 721             invisibleAnnotableParameterCount = parameterCount;
 722         }
 723     }
 724 
 725     @Override
 726     public AnnotationVisitor visitParameterAnnotation(
 727             final int parameter, final String annotationDescriptor, final boolean visible) {
 728         if (visible) {
 729             if (lastRuntimeVisibleParameterAnnotations == null) {
 730                 lastRuntimeVisibleParameterAnnotations =
 731                         new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
 732             }
 733             return lastRuntimeVisibleParameterAnnotations[parameter] =
 734                     AnnotationWriter.create(
 735                             symbolTable, annotationDescriptor, lastRuntimeVisibleParameterAnnotations[parameter]);
 736         } else {
 737             if (lastRuntimeInvisibleParameterAnnotations == null) {
 738                 lastRuntimeInvisibleParameterAnnotations =
 739                         new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
 740             }
 741             return lastRuntimeInvisibleParameterAnnotations[parameter] =
 742                     AnnotationWriter.create(
 743                             symbolTable,
 744                             annotationDescriptor,
 745                             lastRuntimeInvisibleParameterAnnotations[parameter]);
 746         }
 747     }
 748 
 749     @Override
 750     public void visitAttribute(final Attribute attribute) {
 751         // Store the attributes in the <i>reverse</i> order of their visit by this method.
 752         if (attribute.isCodeAttribute()) {
 753             attribute.nextAttribute = firstCodeAttribute;
 754             firstCodeAttribute = attribute;
 755         } else {
 756             attribute.nextAttribute = firstAttribute;
 757             firstAttribute = attribute;
 758         }
 759     }
 760 
 761     @Override
 762     public void visitCode() {
 763         // Nothing to do.
 764     }
 765 
 766     @Override
 767     public void visitFrame(
 768             final int type,
 769             final int numLocal,
 770             final Object[] local,
 771             final int numStack,
 772             final Object[] stack) {
 773         if (compute == COMPUTE_ALL_FRAMES) {
 774             return;
 775         }
 776 
 777         if (compute == COMPUTE_INSERTED_FRAMES) {
 778             if (currentBasicBlock.frame == null) {
 779                 // This should happen only once, for the implicit first frame (which is explicitly visited
 780                 // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES
 781                 // can't be set if EXPAND_ASM_INSNS is not used).
 782                 currentBasicBlock.frame = new CurrentFrame(currentBasicBlock);
 783                 currentBasicBlock.frame.setInputFrameFromDescriptor(
 784                         symbolTable, accessFlags, descriptor, numLocal);
 785                 currentBasicBlock.frame.accept(this);
 786             } else {
 787                 if (type == Opcodes.F_NEW) {
 788                     currentBasicBlock.frame.setInputFrameFromApiFormat(
 789                             symbolTable, numLocal, local, numStack, stack);
 790                 }
 791                 // If type is not F_NEW then it is F_INSERT by hypothesis, and currentBlock.frame contains
 792                 // the stack map frame at the current instruction, computed from the last F_NEW frame and
 793                 // the bytecode instructions in between (via calls to CurrentFrame#execute).
 794                 currentBasicBlock.frame.accept(this);
 795             }
 796         } else if (type == Opcodes.F_NEW) {
 797             if (previousFrame == null) {
 798                 int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
 799                 Frame implicitFirstFrame = new Frame(new Label());
 800                 implicitFirstFrame.setInputFrameFromDescriptor(
 801                         symbolTable, accessFlags, descriptor, argumentsSize);
 802                 implicitFirstFrame.accept(this);
 803             }
 804             currentLocals = numLocal;
 805             int frameIndex = visitFrameStart(code.length, numLocal, numStack);
 806             for (int i = 0; i < numLocal; ++i) {
 807                 currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]);
 808             }
 809             for (int i = 0; i < numStack; ++i) {
 810                 currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]);
 811             }
 812             visitFrameEnd();
 813         } else {
 814             if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
 815                 throw new IllegalArgumentException("Class versions V1_5 or less must use F_NEW frames.");
 816             }
 817             int offsetDelta;
 818             if (stackMapTableEntries == null) {
 819                 stackMapTableEntries = new ByteVector();
 820                 offsetDelta = code.length;
 821             } else {
 822                 offsetDelta = code.length - previousFrameOffset - 1;
 823                 if (offsetDelta < 0) {
 824                     if (type == Opcodes.F_SAME) {
 825                         return;
 826                     } else {
 827                         throw new IllegalStateException();
 828                     }
 829                 }
 830             }
 831 
 832             switch (type) {
 833                 case Opcodes.F_FULL:
 834                     currentLocals = numLocal;
 835                     stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
 836                     for (int i = 0; i < numLocal; ++i) {
 837                         putFrameType(local[i]);
 838                     }
 839                     stackMapTableEntries.putShort(numStack);
 840                     for (int i = 0; i < numStack; ++i) {
 841                         putFrameType(stack[i]);
 842                     }
 843                     break;
 844                 case Opcodes.F_APPEND:
 845                     currentLocals += numLocal;
 846                     stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + numLocal).putShort(offsetDelta);
 847                     for (int i = 0; i < numLocal; ++i) {
 848                         putFrameType(local[i]);
 849                     }
 850                     break;
 851                 case Opcodes.F_CHOP:
 852                     currentLocals -= numLocal;
 853                     stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - numLocal).putShort(offsetDelta);
 854                     break;
 855                 case Opcodes.F_SAME:
 856                     if (offsetDelta < 64) {
 857                         stackMapTableEntries.putByte(offsetDelta);
 858                     } else {
 859                         stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
 860                     }
 861                     break;
 862                 case Opcodes.F_SAME1:
 863                     if (offsetDelta < 64) {
 864                         stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
 865                     } else {
 866                         stackMapTableEntries
 867                                 .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
 868                                 .putShort(offsetDelta);
 869                     }
 870                     putFrameType(stack[0]);
 871                     break;
 872                 default:
 873                     throw new IllegalArgumentException();
 874             }
 875 
 876             previousFrameOffset = code.length;
 877             ++stackMapTableNumberOfEntries;
 878         }
 879 
 880         if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
 881             relativeStackSize = numStack;
 882             for (int i = 0; i < numStack; ++i) {
 883                 if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
 884                     relativeStackSize++;
 885                 }
 886             }
 887             if (relativeStackSize > maxRelativeStackSize) {
 888                 maxRelativeStackSize = relativeStackSize;
 889             }
 890         }
 891 
 892         maxStack = Math.max(maxStack, numStack);
 893         maxLocals = Math.max(maxLocals, currentLocals);
 894     }
 895 
 896     @Override
 897     public void visitInsn(final int opcode) {
 898         lastBytecodeOffset = code.length;
 899         // Add the instruction to the bytecode of the method.
 900         code.putByte(opcode);
 901         // If needed, update the maximum stack size and number of locals, and stack map frames.
 902         if (currentBasicBlock != null) {
 903             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
 904                 currentBasicBlock.frame.execute(opcode, 0, null, null);
 905             } else {
 906                 int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
 907                 if (size > maxRelativeStackSize) {
 908                     maxRelativeStackSize = size;
 909                 }
 910                 relativeStackSize = size;
 911             }
 912             if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
 913                 endCurrentBasicBlockWithNoSuccessor();
 914             }
 915         }
 916     }
 917 
 918     @Override
 919     public void visitIntInsn(final int opcode, final int operand) {
 920         lastBytecodeOffset = code.length;
 921         // Add the instruction to the bytecode of the method.
 922         if (opcode == Opcodes.SIPUSH) {
 923             code.put12(opcode, operand);
 924         } else { // BIPUSH or NEWARRAY
 925             code.put11(opcode, operand);
 926         }
 927         // If needed, update the maximum stack size and number of locals, and stack map frames.
 928         if (currentBasicBlock != null) {
 929             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
 930                 currentBasicBlock.frame.execute(opcode, operand, null, null);
 931             } else if (opcode != Opcodes.NEWARRAY) {
 932                 // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY.
 933                 int size = relativeStackSize + 1;
 934                 if (size > maxRelativeStackSize) {
 935                     maxRelativeStackSize = size;
 936                 }
 937                 relativeStackSize = size;
 938             }
 939         }
 940     }
 941 
 942     @Override
 943     public void visitVarInsn(final int opcode, final int varIndex) {
 944         lastBytecodeOffset = code.length;
 945         // Add the instruction to the bytecode of the method.
 946         if (varIndex < 4 && opcode != Opcodes.RET) {
 947             int optimizedOpcode;
 948             if (opcode < Opcodes.ISTORE) {
 949                 optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + varIndex;
 950             } else {
 951                 optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + varIndex;
 952             }
 953             code.putByte(optimizedOpcode);
 954         } else if (varIndex >= 256) {
 955             code.putByte(Constants.WIDE).put12(opcode, varIndex);
 956         } else {
 957             code.put11(opcode, varIndex);
 958         }
 959         // If needed, update the maximum stack size and number of locals, and stack map frames.
 960         if (currentBasicBlock != null) {
 961             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
 962                 currentBasicBlock.frame.execute(opcode, varIndex, null, null);
 963             } else {
 964                 if (opcode == Opcodes.RET) {
 965                     // No stack size delta.
 966                     currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END;
 967                     currentBasicBlock.outputStackSize = (short) relativeStackSize;
 968                     endCurrentBasicBlockWithNoSuccessor();
 969                 } else { // xLOAD or xSTORE
 970                     int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
 971                     if (size > maxRelativeStackSize) {
 972                         maxRelativeStackSize = size;
 973                     }
 974                     relativeStackSize = size;
 975                 }
 976             }
 977         }
 978         if (compute != COMPUTE_NOTHING) {
 979             int currentMaxLocals;
 980             if (opcode == Opcodes.LLOAD
 981                     || opcode == Opcodes.DLOAD
 982                     || opcode == Opcodes.LSTORE
 983                     || opcode == Opcodes.DSTORE) {
 984                 currentMaxLocals = varIndex + 2;
 985             } else {
 986                 currentMaxLocals = varIndex + 1;
 987             }
 988             if (currentMaxLocals > maxLocals) {
 989                 maxLocals = currentMaxLocals;
 990             }
 991         }
 992         if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) {
 993             // If there are exception handler blocks, each instruction within a handler range is, in
 994             // theory, a basic block (since execution can jump from this instruction to the exception
 995             // handler). As a consequence, the local variable types at the beginning of the handler
 996             // block should be the merge of the local variable types at all the instructions within the
 997             // handler range. However, instead of creating a basic block for each instruction, we can
 998             // get the same result in a more efficient way. Namely, by starting a new basic block after
 999             // each xSTORE instruction, which is what we do here.
1000             visitLabel(new Label());
1001         }
1002     }
1003 
1004     @Override
1005     public void visitTypeInsn(final int opcode, final String type) {
1006         lastBytecodeOffset = code.length;
1007         // Add the instruction to the bytecode of the method.
1008         Symbol typeSymbol = symbolTable.addConstantClass(type);
1009         code.put12(opcode, typeSymbol.index);
1010         // If needed, update the maximum stack size and number of locals, and stack map frames.
1011         if (currentBasicBlock != null) {
1012             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1013                 currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable);
1014             } else if (opcode == Opcodes.NEW || opcode == Opcodes.DEFAULT) {
1015                 // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF.
1016                 int size = relativeStackSize + 1;
1017                 if (size > maxRelativeStackSize) {
1018                     maxRelativeStackSize = size;
1019                 }
1020                 relativeStackSize = size;
1021             }
1022         }
1023     }
1024 
1025     @Override
1026     public void visitFieldInsn(
1027             final int opcode, final String owner, final String name, final String descriptor) {
1028         lastBytecodeOffset = code.length;
1029         // Add the instruction to the bytecode of the method.
1030         Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor);
1031         code.put12(opcode, fieldrefSymbol.index);
1032         // If needed, update the maximum stack size and number of locals, and stack map frames.
1033         if (currentBasicBlock != null) {
1034             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1035                 currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable);
1036             } else {
1037                 int size;
1038                 char firstDescChar = descriptor.charAt(0);
1039                 switch (opcode) {
1040                     case Opcodes.WITHFIELD:
1041                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1);
1042                         break;
1043                     case Opcodes.GETSTATIC:
1044                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1);
1045                         break;
1046                     case Opcodes.PUTSTATIC:
1047                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1);
1048                         break;
1049                     case Opcodes.GETFIELD:
1050                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0);
1051                         break;
1052                     case Opcodes.PUTFIELD:
1053                     default:
1054                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2);
1055                         break;
1056                 }
1057                 if (size > maxRelativeStackSize) {
1058                     maxRelativeStackSize = size;
1059                 }
1060                 relativeStackSize = size;
1061             }
1062         }
1063     }
1064 
1065     @Override
1066     public void visitMethodInsn(
1067             final int opcode,
1068             final String owner,
1069             final String name,
1070             final String descriptor,
1071             final boolean isInterface) {
1072         lastBytecodeOffset = code.length;
1073         // Add the instruction to the bytecode of the method.
1074         Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface);
1075         if (opcode == Opcodes.INVOKEINTERFACE) {
1076             code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index)
1077                     .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0);
1078         } else {
1079             code.put12(opcode, methodrefSymbol.index);
1080         }
1081         // If needed, update the maximum stack size and number of locals, and stack map frames.
1082         if (currentBasicBlock != null) {
1083             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1084                 currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable);
1085             } else {
1086                 int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes();
1087                 int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2);
1088                 int size;
1089                 if (opcode == Opcodes.INVOKESTATIC) {
1090                     size = relativeStackSize + stackSizeDelta + 1;
1091                 } else {
1092                     size = relativeStackSize + stackSizeDelta;
1093                 }
1094                 if (size > maxRelativeStackSize) {
1095                     maxRelativeStackSize = size;
1096                 }
1097                 relativeStackSize = size;
1098             }
1099         }
1100     }
1101 
1102     @Override
1103     public void visitInvokeDynamicInsn(
1104             final String name,
1105             final String descriptor,
1106             final Handle bootstrapMethodHandle,
1107             final Object... bootstrapMethodArguments) {
1108         lastBytecodeOffset = code.length;
1109         // Add the instruction to the bytecode of the method.
1110         Symbol invokeDynamicSymbol =
1111                 symbolTable.addConstantInvokeDynamic(
1112                         name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
1113         code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index);
1114         code.putShort(0);
1115         // If needed, update the maximum stack size and number of locals, and stack map frames.
1116         if (currentBasicBlock != null) {
1117             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1118                 currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable);
1119             } else {
1120                 int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes();
1121                 int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1;
1122                 int size = relativeStackSize + stackSizeDelta;
1123                 if (size > maxRelativeStackSize) {
1124                     maxRelativeStackSize = size;
1125                 }
1126                 relativeStackSize = size;
1127             }
1128         }
1129     }
1130 
1131     @Override
1132     public void visitJumpInsn(final int opcode, final Label label) {
1133         lastBytecodeOffset = code.length;
1134         // Add the instruction to the bytecode of the method.
1135         // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode.
1136         int baseOpcode =
1137                 opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode;
1138         boolean nextInsnIsJumpTarget = false;
1139         if ((label.flags & Label.FLAG_RESOLVED) != 0
1140                 && label.bytecodeOffset - code.length < Short.MIN_VALUE) {
1141             // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO
1142             // with GOTO_W, JSR with JSR_W and IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., where
1143             // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where <L> designates
1144             // the instruction just after the GOTO_W.
1145             if (baseOpcode == Opcodes.GOTO) {
1146                 code.putByte(Constants.GOTO_W);
1147             } else if (baseOpcode == Opcodes.JSR) {
1148                 code.putByte(Constants.JSR_W);
1149             } else {
1150                 // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least
1151                 // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a
1152                 // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W).
1153                 code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1);
1154                 code.putShort(8);
1155                 // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this
1156                 // method or another one, and if the class has frames, we will need to insert a frame after
1157                 // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM
1158                 // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W
1159                 // here, which has the unfortunate effect of forcing this additional round trip (which in
1160                 // some case would not have been really necessary, but we can't know this at this point).
1161                 code.putByte(Constants.ASM_GOTO_W);
1162                 hasAsmInstructions = true;
1163                 // The instruction after the GOTO_W becomes the target of the IFNOT instruction.
1164                 nextInsnIsJumpTarget = true;
1165             }
1166             label.put(code, code.length - 1, true);
1167         } else if (baseOpcode != opcode) {
1168             // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove
1169             // ASM specific instructions). In this case we keep the original instruction.
1170             code.putByte(opcode);
1171             label.put(code, code.length - 1, true);
1172         } else {
1173             // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these
1174             // cases we store the offset in 2 bytes (which will be increased via a ClassReader ->
1175             // ClassWriter round trip if it turns out that 2 bytes are not sufficient).
1176             code.putByte(baseOpcode);
1177             label.put(code, code.length - 1, false);
1178         }
1179 
1180         // If needed, update the maximum stack size and number of locals, and stack map frames.
1181         if (currentBasicBlock != null) {
1182             Label nextBasicBlock = null;
1183             if (compute == COMPUTE_ALL_FRAMES) {
1184                 currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
1185                 // Record the fact that 'label' is the target of a jump instruction.
1186                 label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1187                 // Add 'label' as a successor of the current basic block.
1188                 addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1189                 if (baseOpcode != Opcodes.GOTO) {
1190                     // The next instruction starts a new basic block (except for GOTO: by default the code
1191                     // following a goto is unreachable - unless there is an explicit label for it - and we
1192                     // should not compute stack frame types for its instructions).
1193                     nextBasicBlock = new Label();
1194                 }
1195             } else if (compute == COMPUTE_INSERTED_FRAMES) {
1196                 currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
1197             } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
1198                 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1199                 relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
1200             } else {
1201                 if (baseOpcode == Opcodes.JSR) {
1202                     // Record the fact that 'label' designates a subroutine, if not already done.
1203                     if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) {
1204                         label.flags |= Label.FLAG_SUBROUTINE_START;
1205                         hasSubroutines = true;
1206                     }
1207                     currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER;
1208                     // Note that, by construction in this method, a block which calls a subroutine has at
1209                     // least two successors in the control flow graph: the first one (added below) leads to
1210                     // the instruction after the JSR, while the second one (added here) leads to the JSR
1211                     // target. Note that the first successor is virtual (it does not correspond to a possible
1212                     // execution path): it is only used to compute the successors of the basic blocks ending
1213                     // with a ret, in {@link Label#addSubroutineRetSuccessors}.
1214                     addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label);
1215                     // The instruction after the JSR starts a new basic block.
1216                     nextBasicBlock = new Label();
1217                 } else {
1218                     // No need to update maxRelativeStackSize (the stack size delta is always negative).
1219                     relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
1220                     addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1221                 }
1222             }
1223             // If the next instruction starts a new basic block, call visitLabel to add the label of this
1224             // instruction as a successor of the current block, and to start a new basic block.
1225             if (nextBasicBlock != null) {
1226                 if (nextInsnIsJumpTarget) {
1227                     nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET;
1228                 }
1229                 visitLabel(nextBasicBlock);
1230             }
1231             if (baseOpcode == Opcodes.GOTO) {
1232                 endCurrentBasicBlockWithNoSuccessor();
1233             }
1234         }
1235     }
1236 
1237     @Override
1238     public void visitLabel(final Label label) {
1239         // Resolve the forward references to this label, if any.
1240         hasAsmInstructions |= label.resolve(code.data, code.length);
1241         // visitLabel starts a new basic block (except for debug only labels), so we need to update the
1242         // previous and current block references and list of successors.
1243         if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) {
1244             return;
1245         }
1246         if (compute == COMPUTE_ALL_FRAMES) {
1247             if (currentBasicBlock != null) {
1248                 if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) {
1249                     // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only
1250                     // one place, but this does not work for labels which have not been visited yet.
1251                     // Therefore, when we detect here two labels having the same bytecode offset, we need to
1252                     // - consolidate the state scattered in these two instances into the canonical instance:
1253                     currentBasicBlock.flags |= (short) (label.flags & Label.FLAG_JUMP_TARGET);
1254                     // - make sure the two instances share the same Frame instance (the implementation of
1255                     // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be
1256                     // null):
1257                     label.frame = currentBasicBlock.frame;
1258                     // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so
1259                     // that they still refer to the canonical instance for this bytecode offset.
1260                     return;
1261                 }
1262                 // End the current basic block (with one new successor).
1263                 addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1264             }
1265             // Append 'label' at the end of the basic block list.
1266             if (lastBasicBlock != null) {
1267                 if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) {
1268                     // Same comment as above.
1269                     lastBasicBlock.flags |= (short) (label.flags & Label.FLAG_JUMP_TARGET);
1270                     // Here label.frame should be null.
1271                     label.frame = lastBasicBlock.frame;
1272                     currentBasicBlock = lastBasicBlock;
1273                     return;
1274                 }
1275                 lastBasicBlock.nextBasicBlock = label;
1276             }
1277             lastBasicBlock = label;
1278             // Make it the new current basic block.
1279             currentBasicBlock = label;
1280             // Here label.frame should be null.
1281             label.frame = new Frame(label);
1282         } else if (compute == COMPUTE_INSERTED_FRAMES) {
1283             if (currentBasicBlock == null) {
1284                 // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
1285                 // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged.
1286                 currentBasicBlock = label;
1287             } else {
1288                 // Update the frame owner so that a correct frame offset is computed in Frame.accept().
1289                 currentBasicBlock.frame.owner = label;
1290             }
1291         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1292             if (currentBasicBlock != null) {
1293                 // End the current basic block (with one new successor).
1294                 currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
1295                 addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1296             }
1297             // Start a new current basic block, and reset the current and maximum relative stack sizes.
1298             currentBasicBlock = label;
1299             relativeStackSize = 0;
1300             maxRelativeStackSize = 0;
1301             // Append the new basic block at the end of the basic block list.
1302             if (lastBasicBlock != null) {
1303                 lastBasicBlock.nextBasicBlock = label;
1304             }
1305             lastBasicBlock = label;
1306         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES && currentBasicBlock == null) {
1307             // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
1308             // compute is equal to COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES, currentBasicBlock stays
1309             // unchanged.
1310             currentBasicBlock = label;
1311         }
1312     }
1313 
1314     @Override
1315     public void visitLdcInsn(final Object value) {
1316         lastBytecodeOffset = code.length;
1317         // Add the instruction to the bytecode of the method.
1318         Symbol constantSymbol = symbolTable.addConstant(value);
1319         int constantIndex = constantSymbol.index;
1320         char firstDescriptorChar;
1321         boolean isLongOrDouble =
1322                 constantSymbol.tag == Symbol.CONSTANT_LONG_TAG
1323                         || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG
1324                         || (constantSymbol.tag == Symbol.CONSTANT_DYNAMIC_TAG
1325                                 && ((firstDescriptorChar = constantSymbol.value.charAt(0)) == 'J'
1326                                         || firstDescriptorChar == 'D'));
1327         if (isLongOrDouble) {
1328             code.put12(Constants.LDC2_W, constantIndex);
1329         } else if (constantIndex >= 256) {
1330             code.put12(Constants.LDC_W, constantIndex);
1331         } else {
1332             code.put11(Opcodes.LDC, constantIndex);
1333         }
1334         // If needed, update the maximum stack size and number of locals, and stack map frames.
1335         if (currentBasicBlock != null) {
1336             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1337                 currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable);
1338             } else {
1339                 int size = relativeStackSize + (isLongOrDouble ? 2 : 1);
1340                 if (size > maxRelativeStackSize) {
1341                     maxRelativeStackSize = size;
1342                 }
1343                 relativeStackSize = size;
1344             }
1345         }
1346     }
1347 
1348     @Override
1349     public void visitIincInsn(final int varIndex, final int increment) {
1350         lastBytecodeOffset = code.length;
1351         // Add the instruction to the bytecode of the method.
1352         if ((varIndex > 255) || (increment > 127) || (increment < -128)) {
1353             code.putByte(Constants.WIDE).put12(Opcodes.IINC, varIndex).putShort(increment);
1354         } else {
1355             code.putByte(Opcodes.IINC).put11(varIndex, increment);
1356         }
1357         // If needed, update the maximum stack size and number of locals, and stack map frames.
1358         if (currentBasicBlock != null
1359                 && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) {
1360             currentBasicBlock.frame.execute(Opcodes.IINC, varIndex, null, null);
1361         }
1362         if (compute != COMPUTE_NOTHING) {
1363             int currentMaxLocals = varIndex + 1;
1364             if (currentMaxLocals > maxLocals) {
1365                 maxLocals = currentMaxLocals;
1366             }
1367         }
1368     }
1369 
1370     @Override
1371     public void visitTableSwitchInsn(
1372             final int min, final int max, final Label dflt, final Label... labels) {
1373         lastBytecodeOffset = code.length;
1374         // Add the instruction to the bytecode of the method.
1375         code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
1376         dflt.put(code, lastBytecodeOffset, true);
1377         code.putInt(min).putInt(max);
1378         for (Label label : labels) {
1379             label.put(code, lastBytecodeOffset, true);
1380         }
1381         // If needed, update the maximum stack size and number of locals, and stack map frames.
1382         visitSwitchInsn(dflt, labels);
1383     }
1384 
1385     @Override
1386     public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
1387         lastBytecodeOffset = code.length;
1388         // Add the instruction to the bytecode of the method.
1389         code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
1390         dflt.put(code, lastBytecodeOffset, true);
1391         code.putInt(labels.length);
1392         for (int i = 0; i < labels.length; ++i) {
1393             code.putInt(keys[i]);
1394             labels[i].put(code, lastBytecodeOffset, true);
1395         }
1396         // If needed, update the maximum stack size and number of locals, and stack map frames.
1397         visitSwitchInsn(dflt, labels);
1398     }
1399 
1400     private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1401         if (currentBasicBlock != null) {
1402             if (compute == COMPUTE_ALL_FRAMES) {
1403                 currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1404                 // Add all the labels as successors of the current basic block.
1405                 addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt);
1406                 dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1407                 for (Label label : labels) {
1408                     addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1409                     label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1410                 }
1411             } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1412                 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1413                 --relativeStackSize;
1414                 // Add all the labels as successors of the current basic block.
1415                 addSuccessorToCurrentBasicBlock(relativeStackSize, dflt);
1416                 for (Label label : labels) {
1417                     addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1418                 }
1419             }
1420             // End the current basic block.
1421             endCurrentBasicBlockWithNoSuccessor();
1422         }
1423     }
1424 
1425     @Override
1426     public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
1427         lastBytecodeOffset = code.length;
1428         // Add the instruction to the bytecode of the method.
1429         Symbol descSymbol = symbolTable.addConstantClass(descriptor);
1430         code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions);
1431         // If needed, update the maximum stack size and number of locals, and stack map frames.
1432         if (currentBasicBlock != null) {
1433             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1434                 currentBasicBlock.frame.execute(
1435                         Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable);
1436             } else {
1437                 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1438                 relativeStackSize += 1 - numDimensions;
1439             }
1440         }
1441     }
1442 
1443     @Override
1444     public AnnotationVisitor visitInsnAnnotation(
1445             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1446         if (visible) {
1447             return lastCodeRuntimeVisibleTypeAnnotation =
1448                     AnnotationWriter.create(
1449                             symbolTable,
1450                             (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
1451                             typePath,
1452                             descriptor,
1453                             lastCodeRuntimeVisibleTypeAnnotation);
1454         } else {
1455             return lastCodeRuntimeInvisibleTypeAnnotation =
1456                     AnnotationWriter.create(
1457                             symbolTable,
1458                             (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
1459                             typePath,
1460                             descriptor,
1461                             lastCodeRuntimeInvisibleTypeAnnotation);
1462         }
1463     }
1464 
1465     @Override
1466     public void visitTryCatchBlock(
1467             final Label start, final Label end, final Label handler, final String type) {
1468         Handler newHandler =
1469                 new Handler(
1470                         start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type);
1471         if (firstHandler == null) {
1472             firstHandler = newHandler;
1473         } else {
1474             lastHandler.nextHandler = newHandler;
1475         }
1476         lastHandler = newHandler;
1477     }
1478 
1479     @Override
1480     public AnnotationVisitor visitTryCatchAnnotation(
1481             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1482         if (visible) {
1483             return lastCodeRuntimeVisibleTypeAnnotation =
1484                     AnnotationWriter.create(
1485                             symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeVisibleTypeAnnotation);
1486         } else {
1487             return lastCodeRuntimeInvisibleTypeAnnotation =
1488                     AnnotationWriter.create(
1489                             symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeInvisibleTypeAnnotation);
1490         }
1491     }
1492 
1493     @Override
1494     public void visitLocalVariable(
1495             final String name,
1496             final String descriptor,
1497             final String signature,
1498             final Label start,
1499             final Label end,
1500             final int index) {
1501         if (signature != null) {
1502             if (localVariableTypeTable == null) {
1503                 localVariableTypeTable = new ByteVector();
1504             }
1505             ++localVariableTypeTableLength;
1506             localVariableTypeTable
1507                     .putShort(start.bytecodeOffset)
1508                     .putShort(end.bytecodeOffset - start.bytecodeOffset)
1509                     .putShort(symbolTable.addConstantUtf8(name))
1510                     .putShort(symbolTable.addConstantUtf8(signature))
1511                     .putShort(index);
1512         }
1513         if (localVariableTable == null) {
1514             localVariableTable = new ByteVector();
1515         }
1516         ++localVariableTableLength;
1517         localVariableTable
1518                 .putShort(start.bytecodeOffset)
1519                 .putShort(end.bytecodeOffset - start.bytecodeOffset)
1520                 .putShort(symbolTable.addConstantUtf8(name))
1521                 .putShort(symbolTable.addConstantUtf8(descriptor))
1522                 .putShort(index);
1523         if (compute != COMPUTE_NOTHING) {
1524             char firstDescChar = descriptor.charAt(0);
1525             int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1);
1526             if (currentMaxLocals > maxLocals) {
1527                 maxLocals = currentMaxLocals;
1528             }
1529         }
1530     }
1531 
1532     @Override
1533     public AnnotationVisitor visitLocalVariableAnnotation(
1534             final int typeRef,
1535             final TypePath typePath,
1536             final Label[] start,
1537             final Label[] end,
1538             final int[] index,
1539             final String descriptor,
1540             final boolean visible) {
1541         // Create a ByteVector to hold a 'type_annotation' JVMS structure.
1542         // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
1543         ByteVector typeAnnotation = new ByteVector();
1544         // Write target_type, target_info, and target_path.
1545         typeAnnotation.putByte(typeRef >>> 24).putShort(start.length);
1546         for (int i = 0; i < start.length; ++i) {
1547             typeAnnotation
1548                     .putShort(start[i].bytecodeOffset)
1549                     .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset)
1550                     .putShort(index[i]);
1551         }
1552         TypePath.put(typePath, typeAnnotation);
1553         // Write type_index and reserve space for num_element_value_pairs.
1554         typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
1555         if (visible) {
1556             return lastCodeRuntimeVisibleTypeAnnotation =
1557                     new AnnotationWriter(
1558                             symbolTable,
1559                             /* useNamedValues = */ true,
1560                             typeAnnotation,
1561                             lastCodeRuntimeVisibleTypeAnnotation);
1562         } else {
1563             return lastCodeRuntimeInvisibleTypeAnnotation =
1564                     new AnnotationWriter(
1565                             symbolTable,
1566                             /* useNamedValues = */ true,
1567                             typeAnnotation,
1568                             lastCodeRuntimeInvisibleTypeAnnotation);
1569         }
1570     }
1571 
1572     @Override
1573     public void visitLineNumber(final int line, final Label start) {
1574         if (lineNumberTable == null) {
1575             lineNumberTable = new ByteVector();
1576         }
1577         ++lineNumberTableLength;
1578         lineNumberTable.putShort(start.bytecodeOffset);
1579         lineNumberTable.putShort(line);
1580     }
1581 
1582     @Override
1583     public void visitMaxs(final int maxStack, final int maxLocals) {
1584         if (compute == COMPUTE_ALL_FRAMES) {
1585             computeAllFrames();
1586         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1587             computeMaxStackAndLocal();
1588         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
1589             this.maxStack = maxRelativeStackSize;
1590         } else {
1591             this.maxStack = maxStack;
1592             this.maxLocals = maxLocals;
1593         }
1594     }
1595 
1596     /** Computes all the stack map frames of the method, from scratch. */
1597     private void computeAllFrames() {
1598         // Complete the control flow graph with exception handler blocks.
1599         Handler handler = firstHandler;
1600         while (handler != null) {
1601             String catchTypeDescriptor =
1602                     handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor;
1603             int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor);
1604             // Mark handlerBlock as an exception handler.
1605             Label handlerBlock = handler.handlerPc.getCanonicalInstance();
1606             handlerBlock.flags |= Label.FLAG_JUMP_TARGET;
1607             // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
1608             Label handlerRangeBlock = handler.startPc.getCanonicalInstance();
1609             Label handlerRangeEnd = handler.endPc.getCanonicalInstance();
1610             while (handlerRangeBlock != handlerRangeEnd) {
1611                 handlerRangeBlock.outgoingEdges =
1612                         new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges);
1613                 handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
1614             }
1615             handler = handler.nextHandler;
1616         }
1617 
1618         // Create and visit the first (implicit) frame.
1619         Frame firstFrame = firstBasicBlock.frame;
1620         firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals);
1621         firstFrame.accept(this);
1622 
1623         // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks
1624         // whose stack map frame has changed) and, while there are blocks to process, remove one from
1625         // the list and update the stack map frames of its successor blocks in the control flow graph
1626         // (which might change them, in which case these blocks must be processed too, and are thus
1627         // added to the list of blocks to process). Also compute the maximum stack size of the method,
1628         // as a by-product.
1629         Label listOfBlocksToProcess = firstBasicBlock;
1630         listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
1631         int maxStackSize = 0;
1632         while (listOfBlocksToProcess != Label.EMPTY_LIST) {
1633             // Remove a basic block from the list of blocks to process.
1634             Label basicBlock = listOfBlocksToProcess;
1635             listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
1636             basicBlock.nextListElement = null;
1637             // By definition, basicBlock is reachable.
1638             basicBlock.flags |= Label.FLAG_REACHABLE;
1639             // Update the (absolute) maximum stack size.
1640             int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax;
1641             if (maxBlockStackSize > maxStackSize) {
1642                 maxStackSize = maxBlockStackSize;
1643             }
1644             // Update the successor blocks of basicBlock in the control flow graph.
1645             Edge outgoingEdge = basicBlock.outgoingEdges;
1646             while (outgoingEdge != null) {
1647                 Label successorBlock = outgoingEdge.successor.getCanonicalInstance();
1648                 boolean successorBlockChanged =
1649                         basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info);
1650                 if (successorBlockChanged && successorBlock.nextListElement == null) {
1651                     // If successorBlock has changed it must be processed. Thus, if it is not already in the
1652                     // list of blocks to process, add it to this list.
1653                     successorBlock.nextListElement = listOfBlocksToProcess;
1654                     listOfBlocksToProcess = successorBlock;
1655                 }
1656                 outgoingEdge = outgoingEdge.nextEdge;
1657             }
1658         }
1659 
1660         // Loop over all the basic blocks and visit the stack map frames that must be stored in the
1661         // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from
1662         // exception handler ranges.
1663         Label basicBlock = firstBasicBlock;
1664         while (basicBlock != null) {
1665             if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE))
1666                     == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) {
1667                 basicBlock.frame.accept(this);
1668             }
1669             if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) {
1670                 // Find the start and end bytecode offsets of this unreachable block.
1671                 Label nextBasicBlock = basicBlock.nextBasicBlock;
1672                 int startOffset = basicBlock.bytecodeOffset;
1673                 int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1;
1674                 if (endOffset >= startOffset) {
1675                     // Replace its instructions with NOP ... NOP ATHROW.
1676                     for (int i = startOffset; i < endOffset; ++i) {
1677                         code.data[i] = Opcodes.NOP;
1678                     }
1679                     code.data[endOffset] = (byte) Opcodes.ATHROW;
1680                     // Emit a frame for this unreachable block, with no local and a Throwable on the stack
1681                     // (so that the ATHROW could consume this Throwable if it were reachable).
1682                     int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
1683                     currentFrame[frameIndex] =
1684                             Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
1685                     visitFrameEnd();
1686                     // Remove this unreachable basic block from the exception handler ranges.
1687                     firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock);
1688                     // The maximum stack size is now at least one, because of the Throwable declared above.
1689                     maxStackSize = Math.max(maxStackSize, 1);
1690                 }
1691             }
1692             basicBlock = basicBlock.nextBasicBlock;
1693         }
1694 
1695         this.maxStack = maxStackSize;
1696     }
1697 
1698     /** Computes the maximum stack size of the method. */
1699     private void computeMaxStackAndLocal() {
1700         // Complete the control flow graph with exception handler blocks.
1701         Handler handler = firstHandler;
1702         while (handler != null) {
1703             Label handlerBlock = handler.handlerPc;
1704             Label handlerRangeBlock = handler.startPc;
1705             Label handlerRangeEnd = handler.endPc;
1706             // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
1707             while (handlerRangeBlock != handlerRangeEnd) {
1708                 if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) {
1709                     handlerRangeBlock.outgoingEdges =
1710                             new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges);
1711                 } else {
1712                     // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing
1713                     // edges to preserve the hypothesis about JSR block successors order (see
1714                     // {@link #visitJumpInsn}).
1715                     handlerRangeBlock.outgoingEdges.nextEdge.nextEdge =
1716                             new Edge(
1717                                     Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge);
1718                 }
1719                 handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
1720             }
1721             handler = handler.nextHandler;
1722         }
1723 
1724         // Complete the control flow graph with the successor blocks of subroutines, if needed.
1725         if (hasSubroutines) {
1726             // First step: find the subroutines. This step determines, for each basic block, to which
1727             // subroutine(s) it belongs. Start with the main "subroutine":
1728             short numSubroutines = 1;
1729             firstBasicBlock.markSubroutine(numSubroutines);
1730             // Then, mark the subroutines called by the main subroutine, then the subroutines called by
1731             // those called by the main subroutine, etc.
1732             for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) {
1733                 Label basicBlock = firstBasicBlock;
1734                 while (basicBlock != null) {
1735                     if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0
1736                             && basicBlock.subroutineId == currentSubroutine) {
1737                         Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor;
1738                         if (jsrTarget.subroutineId == 0) {
1739                             // If this subroutine has not been marked yet, find its basic blocks.
1740                             jsrTarget.markSubroutine(++numSubroutines);
1741                         }
1742                     }
1743                     basicBlock = basicBlock.nextBasicBlock;
1744                 }
1745             }
1746             // Second step: find the successors in the control flow graph of each subroutine basic block
1747             // 'r' ending with a RET instruction. These successors are the virtual successors of the basic
1748             // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'.
1749             Label basicBlock = firstBasicBlock;
1750             while (basicBlock != null) {
1751                 if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
1752                     // By construction, jsr targets are stored in the second outgoing edge of basic blocks
1753                     // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}).
1754                     Label subroutine = basicBlock.outgoingEdges.nextEdge.successor;
1755                     subroutine.addSubroutineRetSuccessors(basicBlock);
1756                 }
1757                 basicBlock = basicBlock.nextBasicBlock;
1758             }
1759         }
1760 
1761         // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks
1762         // whose input stack size has changed) and, while there are blocks to process, remove one
1763         // from the list, update the input stack size of its successor blocks in the control flow
1764         // graph, and add these blocks to the list of blocks to process (if not already done).
1765         Label listOfBlocksToProcess = firstBasicBlock;
1766         listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
1767         int maxStackSize = maxStack;
1768         while (listOfBlocksToProcess != Label.EMPTY_LIST) {
1769             // Remove a basic block from the list of blocks to process. Note that we don't reset
1770             // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already
1771             // processed basic blocks.
1772             Label basicBlock = listOfBlocksToProcess;
1773             listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
1774             // Compute the (absolute) input stack size and maximum stack size of this block.
1775             int inputStackTop = basicBlock.inputStackSize;
1776             int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax;
1777             // Update the absolute maximum stack size of the method.
1778             if (maxBlockStackSize > maxStackSize) {
1779                 maxStackSize = maxBlockStackSize;
1780             }
1781             // Update the input stack size of the successor blocks of basicBlock in the control flow
1782             // graph, and add these blocks to the list of blocks to process, if not already done.
1783             Edge outgoingEdge = basicBlock.outgoingEdges;
1784             if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
1785                 // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual
1786                 // edges which lead to the instruction just after the jsr, and do not correspond to a
1787                 // possible execution path (see {@link #visitJumpInsn} and
1788                 // {@link Label#FLAG_SUBROUTINE_CALLER}).
1789                 outgoingEdge = outgoingEdge.nextEdge;
1790             }
1791             while (outgoingEdge != null) {
1792                 Label successorBlock = outgoingEdge.successor;
1793                 if (successorBlock.nextListElement == null) {
1794                     successorBlock.inputStackSize =
1795                             (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info);
1796                     successorBlock.nextListElement = listOfBlocksToProcess;
1797                     listOfBlocksToProcess = successorBlock;
1798                 }
1799                 outgoingEdge = outgoingEdge.nextEdge;
1800             }
1801         }
1802         this.maxStack = maxStackSize;
1803     }
1804 
1805     @Override
1806     public void visitEnd() {
1807         // Nothing to do.
1808     }
1809 
1810     // -----------------------------------------------------------------------------------------------
1811     // Utility methods: control flow analysis algorithm
1812     // -----------------------------------------------------------------------------------------------
1813 
1814     /**
1815       * Adds a successor to {@link #currentBasicBlock} in the control flow graph.
1816       *
1817       * @param info information about the control flow edge to be added.
1818       * @param successor the successor block to be added to the current basic block.
1819       */
1820     private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) {
1821         currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges);
1822     }
1823 
1824     /**
1825       * Ends the current basic block. This method must be used in the case where the current basic
1826       * block does not have any successor.
1827       *
1828       * <p>WARNING: this method must be called after the currently visited instruction has been put in
1829       * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic
1830       * block after the current instruction).
1831       */
1832     private void endCurrentBasicBlockWithNoSuccessor() {
1833         if (compute == COMPUTE_ALL_FRAMES) {
1834             Label nextBasicBlock = new Label();
1835             nextBasicBlock.frame = new Frame(nextBasicBlock);
1836             nextBasicBlock.resolve(code.data, code.length);
1837             lastBasicBlock.nextBasicBlock = nextBasicBlock;
1838             lastBasicBlock = nextBasicBlock;
1839             currentBasicBlock = null;
1840         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1841             currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
1842             currentBasicBlock = null;
1843         }
1844     }
1845 
1846     // -----------------------------------------------------------------------------------------------
1847     // Utility methods: stack map frames
1848     // -----------------------------------------------------------------------------------------------
1849 
1850     /**
1851       * Starts the visit of a new stack map frame, stored in {@link #currentFrame}.
1852       *
1853       * @param offset the bytecode offset of the instruction to which the frame corresponds.
1854       * @param numLocal the number of local variables in the frame.
1855       * @param numStack the number of stack elements in the frame.
1856       * @return the index of the next element to be written in this frame.
1857       */
1858     int visitFrameStart(final int offset, final int numLocal, final int numStack) {
1859         int frameLength = 3 + numLocal + numStack;
1860         if (currentFrame == null || currentFrame.length < frameLength) {
1861             currentFrame = new int[frameLength];
1862         }
1863         currentFrame[0] = offset;
1864         currentFrame[1] = numLocal;
1865         currentFrame[2] = numStack;
1866         return 3;
1867     }
1868 
1869     /**
1870       * Sets an abstract type in {@link #currentFrame}.
1871       *
1872       * @param frameIndex the index of the element to be set in {@link #currentFrame}.
1873       * @param abstractType an abstract type.
1874       */
1875     void visitAbstractType(final int frameIndex, final int abstractType) {
1876         currentFrame[frameIndex] = abstractType;
1877     }
1878 
1879     /**
1880       * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by
1881       * updating the StackMapTable number_of_entries (except if the current frame is the first one,
1882       * which is implicit in StackMapTable). Then resets {@link #currentFrame} to {@literal null}.
1883       */
1884     void visitFrameEnd() {
1885         if (previousFrame != null) {
1886             if (stackMapTableEntries == null) {
1887                 stackMapTableEntries = new ByteVector();
1888             }
1889             putFrame();
1890             ++stackMapTableNumberOfEntries;
1891         }
1892         previousFrame = currentFrame;
1893         currentFrame = null;
1894     }
1895 
1896     /** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */
1897     private void putFrame() {
1898         final int numLocal = currentFrame[1];
1899         final int numStack = currentFrame[2];
1900         if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
1901             // Generate a StackMap attribute entry, which are always uncompressed.
1902             stackMapTableEntries.putShort(currentFrame[0]).putShort(numLocal);
1903             putAbstractTypes(3, 3 + numLocal);
1904             stackMapTableEntries.putShort(numStack);
1905             putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
1906             return;
1907         }
1908         final int offsetDelta =
1909                 stackMapTableNumberOfEntries == 0
1910                         ? currentFrame[0]
1911                         : currentFrame[0] - previousFrame[0] - 1;
1912         final int previousNumlocal = previousFrame[1];
1913         final int numLocalDelta = numLocal - previousNumlocal;
1914         int type = Frame.FULL_FRAME;
1915         if (numStack == 0) {
1916             switch (numLocalDelta) {
1917                 case -3:
1918                 case -2:
1919                 case -1:
1920                     type = Frame.CHOP_FRAME;
1921                     break;
1922                 case 0:
1923                     type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED;
1924                     break;
1925                 case 1:
1926                 case 2:
1927                 case 3:
1928                     type = Frame.APPEND_FRAME;
1929                     break;
1930                 default:
1931                     // Keep the FULL_FRAME type.
1932                     break;
1933             }
1934         } else if (numLocalDelta == 0 && numStack == 1) {
1935             type =
1936                     offsetDelta < 63
1937                             ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME
1938                             : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1939         }
1940         if (type != Frame.FULL_FRAME) {
1941             // Verify if locals are the same as in the previous frame.
1942             int frameIndex = 3;
1943             for (int i = 0; i < previousNumlocal && i < numLocal; i++) {
1944                 if (currentFrame[frameIndex] != previousFrame[frameIndex]) {
1945                     type = Frame.FULL_FRAME;
1946                     break;
1947                 }
1948                 frameIndex++;
1949             }
1950         }
1951         switch (type) {
1952             case Frame.SAME_FRAME:
1953                 stackMapTableEntries.putByte(offsetDelta);
1954                 break;
1955             case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME:
1956                 stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
1957                 putAbstractTypes(3 + numLocal, 4 + numLocal);
1958                 break;
1959             case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1960                 stackMapTableEntries
1961                         .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
1962                         .putShort(offsetDelta);
1963                 putAbstractTypes(3 + numLocal, 4 + numLocal);
1964                 break;
1965             case Frame.SAME_FRAME_EXTENDED:
1966                 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
1967                 break;
1968             case Frame.CHOP_FRAME:
1969                 stackMapTableEntries
1970                         .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
1971                         .putShort(offsetDelta);
1972                 break;
1973             case Frame.APPEND_FRAME:
1974                 stackMapTableEntries
1975                         .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
1976                         .putShort(offsetDelta);
1977                 putAbstractTypes(3 + previousNumlocal, 3 + numLocal);
1978                 break;
1979             case Frame.FULL_FRAME:
1980             default:
1981                 stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
1982                 putAbstractTypes(3, 3 + numLocal);
1983                 stackMapTableEntries.putShort(numStack);
1984                 putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
1985                 break;
1986         }
1987     }
1988 
1989     /**
1990       * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the
1991       * JVMS verification_type_info format used in StackMapTable attributes.
1992       *
1993       * @param start index of the first type in {@link #currentFrame} to write.
1994       * @param end index of last type in {@link #currentFrame} to write (exclusive).
1995       */
1996     private void putAbstractTypes(final int start, final int end) {
1997         for (int i = start; i < end; ++i) {
1998             Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries);
1999         }
2000     }
2001 
2002     /**
2003       * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS
2004       * verification_type_info format used in StackMapTable attributes.
2005       *
2006       * @param type a frame element type described using the same format as in {@link
2007       *     MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
2008       *     Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or
2009       *     {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating
2010       *     a NEW instruction (for uninitialized types).
2011       */
2012     private void putFrameType(final Object type) {
2013         if (type instanceof Integer) {
2014             stackMapTableEntries.putByte(((Integer) type).intValue());
2015         } else if (type instanceof String) {
2016             stackMapTableEntries
2017                     .putByte(Frame.ITEM_OBJECT)
2018                     .putShort(symbolTable.addConstantClass((String) type).index);
2019         } else {
2020             stackMapTableEntries
2021                     .putByte(Frame.ITEM_UNINITIALIZED)
2022                     .putShort(((Label) type).bytecodeOffset);
2023         }
2024     }
2025 
2026     // -----------------------------------------------------------------------------------------------
2027     // Utility methods
2028     // -----------------------------------------------------------------------------------------------
2029 
2030     /**
2031       * Returns whether the attributes of this method can be copied from the attributes of the given
2032       * method (assuming there is no method visitor between the given ClassReader and this
2033       * MethodWriter). This method should only be called just after this MethodWriter has been created,
2034       * and before any content is visited. It returns true if the attributes corresponding to the
2035       * constructor arguments (at most a Signature, an Exception, a Deprecated and a Synthetic
2036       * attribute) are the same as the corresponding attributes in the given method.
2037       *
2038       * @param source the source ClassReader from which the attributes of this method might be copied.
2039       * @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes
2040       *     of this method might be copied contains a Synthetic attribute.
2041       * @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes
2042       *     of this method might be copied contains a Deprecated attribute.
2043       * @param descriptorIndex the descriptor_index field of the method_info JVMS structure from which
2044       *     the attributes of this method might be copied.
2045       * @param signatureIndex the constant pool index contained in the Signature attribute of the
2046       *     method_info JVMS structure from which the attributes of this method might be copied, or 0.
2047       * @param exceptionsOffset the offset in 'source.b' of the Exceptions attribute of the method_info
2048       *     JVMS structure from which the attributes of this method might be copied, or 0.
2049       * @return whether the attributes of this method can be copied from the attributes of the
2050       *     method_info JVMS structure in 'source.b', between 'methodInfoOffset' and 'methodInfoOffset'
2051       *     + 'methodInfoLength'.
2052       */
2053     boolean canCopyMethodAttributes(
2054             final ClassReader source,
2055             final boolean hasSyntheticAttribute,
2056             final boolean hasDeprecatedAttribute,
2057             final int descriptorIndex,
2058             final int signatureIndex,
2059             final int exceptionsOffset) {
2060         // If the method descriptor has changed, with more locals than the max_locals field of the
2061         // original Code attribute, if any, then the original method attributes can't be copied. A
2062         // conservative check on the descriptor changes alone ensures this (being more precise is not
2063         // worth the additional complexity, because these cases should be rare -- if a transform changes
2064         // a method descriptor, most of the time it needs to change the method's code too).
2065         if (source != symbolTable.getSource()
2066                 || descriptorIndex != this.descriptorIndex
2067                 || signatureIndex != this.signatureIndex
2068                 || hasDeprecatedAttribute != ((accessFlags & Opcodes.ACC_DEPRECATED) != 0)) {
2069             return false;
2070         }
2071         boolean needSyntheticAttribute =
2072                 symbolTable.getMajorVersion() < Opcodes.V1_5 && (accessFlags & Opcodes.ACC_SYNTHETIC) != 0;
2073         if (hasSyntheticAttribute != needSyntheticAttribute) {
2074             return false;
2075         }
2076         if (exceptionsOffset == 0) {
2077             if (numberOfExceptions != 0) {
2078                 return false;
2079             }
2080         } else if (source.readUnsignedShort(exceptionsOffset) == numberOfExceptions) {
2081             int currentExceptionOffset = exceptionsOffset + 2;
2082             for (int i = 0; i < numberOfExceptions; ++i) {
2083                 if (source.readUnsignedShort(currentExceptionOffset) != exceptionIndexTable[i]) {
2084                     return false;
2085                 }
2086                 currentExceptionOffset += 2;
2087             }
2088         }
2089         return true;
2090     }
2091 
2092     /**
2093       * Sets the source from which the attributes of this method will be copied.
2094       *
2095       * @param methodInfoOffset the offset in 'symbolTable.getSource()' of the method_info JVMS
2096       *     structure from which the attributes of this method will be copied.
2097       * @param methodInfoLength the length in 'symbolTable.getSource()' of the method_info JVMS
2098       *     structure from which the attributes of this method will be copied.
2099       */
2100     void setMethodAttributesSource(final int methodInfoOffset, final int methodInfoLength) {
2101         // Don't copy the attributes yet, instead store their location in the source class reader so
2102         // they can be copied later, in {@link #putMethodInfo}. Note that we skip the 6 header bytes
2103         // of the method_info JVMS structure.
2104         this.sourceOffset = methodInfoOffset + 6;
2105         this.sourceLength = methodInfoLength - 6;
2106     }
2107 
2108     /**
2109       * Returns the size of the method_info JVMS structure generated by this MethodWriter. Also add the
2110       * names of the attributes of this method in the constant pool.
2111       *
2112       * @return the size in bytes of the method_info JVMS structure.
2113       */
2114     int computeMethodInfoSize() {
2115         // If this method_info must be copied from an existing one, the size computation is trivial.
2116         if (sourceOffset != 0) {
2117             // sourceLength excludes the first 6 bytes for access_flags, name_index and descriptor_index.
2118             return 6 + sourceLength;
2119         }
2120         // 2 bytes each for access_flags, name_index, descriptor_index and attributes_count.
2121         int size = 8;
2122         // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2123         if (code.length > 0) {
2124             if (code.length > 65535) {
2125                 throw new MethodTooLargeException(
2126                         symbolTable.getClassName(), name, descriptor, code.length);
2127             }
2128             symbolTable.addConstantUtf8(Constants.CODE);
2129             // The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack,
2130             // max_locals, code_length and attributes_count, plus the bytecode and the exception table.
2131             size += 16 + code.length + Handler.getExceptionTableSize(firstHandler);
2132             if (stackMapTableEntries != null) {
2133                 boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;
2134                 symbolTable.addConstantUtf8(useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap");
2135                 // 6 header bytes and 2 bytes for number_of_entries.
2136                 size += 8 + stackMapTableEntries.length;
2137             }
2138             if (lineNumberTable != null) {
2139                 symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE);
2140                 // 6 header bytes and 2 bytes for line_number_table_length.
2141                 size += 8 + lineNumberTable.length;
2142             }
2143             if (localVariableTable != null) {
2144                 symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE);
2145                 // 6 header bytes and 2 bytes for local_variable_table_length.
2146                 size += 8 + localVariableTable.length;
2147             }
2148             if (localVariableTypeTable != null) {
2149                 symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE);
2150                 // 6 header bytes and 2 bytes for local_variable_type_table_length.
2151                 size += 8 + localVariableTypeTable.length;
2152             }
2153             if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2154                 size +=
2155                         lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
2156                                 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
2157             }
2158             if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2159                 size +=
2160                         lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
2161                                 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
2162             }
2163             if (firstCodeAttribute != null) {
2164                 size +=
2165                         firstCodeAttribute.computeAttributesSize(
2166                                 symbolTable, code.data, code.length, maxStack, maxLocals);
2167             }
2168         }
2169         if (numberOfExceptions > 0) {
2170             symbolTable.addConstantUtf8(Constants.EXCEPTIONS);
2171             size += 8 + 2 * numberOfExceptions;
2172         }
2173         size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex);
2174         size +=
2175                 AnnotationWriter.computeAnnotationsSize(
2176                         lastRuntimeVisibleAnnotation,
2177                         lastRuntimeInvisibleAnnotation,
2178                         lastRuntimeVisibleTypeAnnotation,
2179                         lastRuntimeInvisibleTypeAnnotation);
2180         if (lastRuntimeVisibleParameterAnnotations != null) {
2181             size +=
2182                     AnnotationWriter.computeParameterAnnotationsSize(
2183                             Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
2184                             lastRuntimeVisibleParameterAnnotations,
2185                             visibleAnnotableParameterCount == 0
2186                                     ? lastRuntimeVisibleParameterAnnotations.length
2187                                     : visibleAnnotableParameterCount);
2188         }
2189         if (lastRuntimeInvisibleParameterAnnotations != null) {
2190             size +=
2191                     AnnotationWriter.computeParameterAnnotationsSize(
2192                             Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,
2193                             lastRuntimeInvisibleParameterAnnotations,
2194                             invisibleAnnotableParameterCount == 0
2195                                     ? lastRuntimeInvisibleParameterAnnotations.length
2196                                     : invisibleAnnotableParameterCount);
2197         }
2198         if (defaultValue != null) {
2199             symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT);
2200             size += 6 + defaultValue.length;
2201         }
2202         if (parameters != null) {
2203             symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS);
2204             // 6 header bytes and 1 byte for parameters_count.
2205             size += 7 + parameters.length;
2206         }
2207         if (firstAttribute != null) {
2208             size += firstAttribute.computeAttributesSize(symbolTable);
2209         }
2210         return size;
2211     }
2212 
2213     /**
2214       * Puts the content of the method_info JVMS structure generated by this MethodWriter into the
2215       * given ByteVector.
2216       *
2217       * @param output where the method_info structure must be put.
2218       */
2219     void putMethodInfo(final ByteVector output) {
2220         boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
2221         int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
2222         output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
2223         // If this method_info must be copied from an existing one, copy it now and return early.
2224         if (sourceOffset != 0) {
2225             output.putByteArray(symbolTable.getSource().classFileBuffer, sourceOffset, sourceLength);
2226             return;
2227         }
2228         // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2229         int attributeCount = 0;
2230         if (code.length > 0) {
2231             ++attributeCount;
2232         }
2233         if (numberOfExceptions > 0) {
2234             ++attributeCount;
2235         }
2236         if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
2237             ++attributeCount;
2238         }
2239         if (signatureIndex != 0) {
2240             ++attributeCount;
2241         }
2242         if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
2243             ++attributeCount;
2244         }
2245         if (lastRuntimeVisibleAnnotation != null) {
2246             ++attributeCount;
2247         }
2248         if (lastRuntimeInvisibleAnnotation != null) {
2249             ++attributeCount;
2250         }
2251         if (lastRuntimeVisibleParameterAnnotations != null) {
2252             ++attributeCount;
2253         }
2254         if (lastRuntimeInvisibleParameterAnnotations != null) {
2255             ++attributeCount;
2256         }
2257         if (lastRuntimeVisibleTypeAnnotation != null) {
2258             ++attributeCount;
2259         }
2260         if (lastRuntimeInvisibleTypeAnnotation != null) {
2261             ++attributeCount;
2262         }
2263         if (defaultValue != null) {
2264             ++attributeCount;
2265         }
2266         if (parameters != null) {
2267             ++attributeCount;
2268         }
2269         if (firstAttribute != null) {
2270             attributeCount += firstAttribute.getAttributeCount();
2271         }
2272         // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2273         output.putShort(attributeCount);
2274         if (code.length > 0) {
2275             // 2, 2, 4 and 2 bytes respectively for max_stack, max_locals, code_length and
2276             // attributes_count, plus the bytecode and the exception table.
2277             int size = 10 + code.length + Handler.getExceptionTableSize(firstHandler);
2278             int codeAttributeCount = 0;
2279             if (stackMapTableEntries != null) {
2280                 // 6 header bytes and 2 bytes for number_of_entries.
2281                 size += 8 + stackMapTableEntries.length;
2282                 ++codeAttributeCount;
2283             }
2284             if (lineNumberTable != null) {
2285                 // 6 header bytes and 2 bytes for line_number_table_length.
2286                 size += 8 + lineNumberTable.length;
2287                 ++codeAttributeCount;
2288             }
2289             if (localVariableTable != null) {
2290                 // 6 header bytes and 2 bytes for local_variable_table_length.
2291                 size += 8 + localVariableTable.length;
2292                 ++codeAttributeCount;
2293             }
2294             if (localVariableTypeTable != null) {
2295                 // 6 header bytes and 2 bytes for local_variable_type_table_length.
2296                 size += 8 + localVariableTypeTable.length;
2297                 ++codeAttributeCount;
2298             }
2299             if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2300                 size +=
2301                         lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
2302                                 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
2303                 ++codeAttributeCount;
2304             }
2305             if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2306                 size +=
2307                         lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
2308                                 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
2309                 ++codeAttributeCount;
2310             }
2311             if (firstCodeAttribute != null) {
2312                 size +=
2313                         firstCodeAttribute.computeAttributesSize(
2314                                 symbolTable, code.data, code.length, maxStack, maxLocals);
2315                 codeAttributeCount += firstCodeAttribute.getAttributeCount();
2316             }
2317             output
2318                     .putShort(symbolTable.addConstantUtf8(Constants.CODE))
2319                     .putInt(size)
2320                     .putShort(maxStack)
2321                     .putShort(maxLocals)
2322                     .putInt(code.length)
2323                     .putByteArray(code.data, 0, code.length);
2324             Handler.putExceptionTable(firstHandler, output);
2325             output.putShort(codeAttributeCount);
2326             if (stackMapTableEntries != null) {
2327                 boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;
2328                 output
2329                         .putShort(
2330                                 symbolTable.addConstantUtf8(
2331                                         useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap"))
2332                         .putInt(2 + stackMapTableEntries.length)
2333                         .putShort(stackMapTableNumberOfEntries)
2334                         .putByteArray(stackMapTableEntries.data, 0, stackMapTableEntries.length);
2335             }
2336             if (lineNumberTable != null) {
2337                 output
2338                         .putShort(symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE))
2339                         .putInt(2 + lineNumberTable.length)
2340                         .putShort(lineNumberTableLength)
2341                         .putByteArray(lineNumberTable.data, 0, lineNumberTable.length);
2342             }
2343             if (localVariableTable != null) {
2344                 output
2345                         .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE))
2346                         .putInt(2 + localVariableTable.length)
2347                         .putShort(localVariableTableLength)
2348                         .putByteArray(localVariableTable.data, 0, localVariableTable.length);
2349             }
2350             if (localVariableTypeTable != null) {
2351                 output
2352                         .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE))
2353                         .putInt(2 + localVariableTypeTable.length)
2354                         .putShort(localVariableTypeTableLength)
2355                         .putByteArray(localVariableTypeTable.data, 0, localVariableTypeTable.length);
2356             }
2357             if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2358                 lastCodeRuntimeVisibleTypeAnnotation.putAnnotations(
2359                         symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
2360             }
2361             if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2362                 lastCodeRuntimeInvisibleTypeAnnotation.putAnnotations(
2363                         symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
2364             }
2365             if (firstCodeAttribute != null) {
2366                 firstCodeAttribute.putAttributes(
2367                         symbolTable, code.data, code.length, maxStack, maxLocals, output);
2368             }
2369         }
2370         if (numberOfExceptions > 0) {
2371             output
2372                     .putShort(symbolTable.addConstantUtf8(Constants.EXCEPTIONS))
2373                     .putInt(2 + 2 * numberOfExceptions)
2374                     .putShort(numberOfExceptions);
2375             for (int exceptionIndex : exceptionIndexTable) {
2376                 output.putShort(exceptionIndex);
2377             }
2378         }
2379         Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
2380         AnnotationWriter.putAnnotations(
2381                 symbolTable,
2382                 lastRuntimeVisibleAnnotation,
2383                 lastRuntimeInvisibleAnnotation,
2384                 lastRuntimeVisibleTypeAnnotation,
2385                 lastRuntimeInvisibleTypeAnnotation,
2386                 output);
2387         if (lastRuntimeVisibleParameterAnnotations != null) {
2388             AnnotationWriter.putParameterAnnotations(
2389                     symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS),
2390                     lastRuntimeVisibleParameterAnnotations,
2391                     visibleAnnotableParameterCount == 0
2392                             ? lastRuntimeVisibleParameterAnnotations.length
2393                             : visibleAnnotableParameterCount,
2394                     output);
2395         }
2396         if (lastRuntimeInvisibleParameterAnnotations != null) {
2397             AnnotationWriter.putParameterAnnotations(
2398                     symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS),
2399                     lastRuntimeInvisibleParameterAnnotations,
2400                     invisibleAnnotableParameterCount == 0
2401                             ? lastRuntimeInvisibleParameterAnnotations.length
2402                             : invisibleAnnotableParameterCount,
2403                     output);
2404         }
2405         if (defaultValue != null) {
2406             output
2407                     .putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT))
2408                     .putInt(defaultValue.length)
2409                     .putByteArray(defaultValue.data, 0, defaultValue.length);
2410         }
2411         if (parameters != null) {
2412             output
2413                     .putShort(symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS))
2414                     .putInt(1 + parameters.length)
2415                     .putByte(parametersCount)
2416                     .putByteArray(parameters.data, 0, parameters.length);
2417         }
2418         if (firstAttribute != null) {
2419             firstAttribute.putAttributes(symbolTable, output);
2420         }
2421     }
2422 
2423     /**
2424       * Collects the attributes of this method into the given set of attribute prototypes.
2425       *
2426       * @param attributePrototypes a set of attribute prototypes.
2427       */
2428     final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
2429         attributePrototypes.addAttributes(firstAttribute);
2430         attributePrototypes.addAttributes(firstCodeAttribute);
2431     }
2432 }
--- EOF ---