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 }