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