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