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}, {@link 538 * Frame#UNINITIALIZED_KIND} or {@link Frame#FORWARD_UNINITIALIZED_KIND} abstract types. Long and 539 * double types use only one array entry. 540 */ 541 private int[] currentFrame; 542 543 /** Whether this method contains subroutines. */ 544 private boolean hasSubroutines; 545 546 // ----------------------------------------------------------------------------------------------- 547 // Other miscellaneous status fields 548 // ----------------------------------------------------------------------------------------------- 549 550 /** Whether the bytecode of this method contains ASM specific instructions. */ 551 private boolean hasAsmInstructions; 552 553 /** 554 * The start offset of the last visited instruction. Used to set the offset field of type 555 * annotations of type 'offset_target' (see <a 556 * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS 557 * 4.7.20.1</a>). 558 */ 559 private int lastBytecodeOffset; 560 561 /** 562 * The offset in bytes in {@link SymbolTable#getSource} from which the method_info for this method 563 * (excluding its first 6 bytes) must be copied, or 0. 564 */ 565 private int sourceOffset; 566 567 /** 568 * The length in bytes in {@link SymbolTable#getSource} which must be copied to get the 569 * method_info for this method (excluding its first 6 bytes for access_flags, name_index and 570 * descriptor_index). 571 */ 572 private int sourceLength; 573 574 // ----------------------------------------------------------------------------------------------- 575 // Constructor and accessors 576 // ----------------------------------------------------------------------------------------------- 577 578 /** 579 * Constructs a new {@link MethodWriter}. 580 * 581 * @param symbolTable where the constants used in this AnnotationWriter must be stored. 582 * @param access the method's access flags (see {@link Opcodes}). 583 * @param name the method's name. 584 * @param descriptor the method's descriptor (see {@link Type}). 585 * @param signature the method's signature. May be {@literal null}. 586 * @param exceptions the internal names of the method's exceptions. May be {@literal null}. 587 * @param compute indicates what must be computed (see #compute). 588 */ MethodWriter( final SymbolTable symbolTable, final int access, final String name, final String descriptor, final String signature, final String[] exceptions, final int compute)589 MethodWriter( 590 final SymbolTable symbolTable, 591 final int access, 592 final String name, 593 final String descriptor, 594 final String signature, 595 final String[] exceptions, 596 final int compute) { 597 super(/* latest api = */ Opcodes.ASM9); 598 this.symbolTable = symbolTable; 599 this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access; 600 this.nameIndex = symbolTable.addConstantUtf8(name); 601 this.name = name; 602 this.descriptorIndex = symbolTable.addConstantUtf8(descriptor); 603 this.descriptor = descriptor; 604 this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature); 605 if (exceptions != null && exceptions.length > 0) { 606 numberOfExceptions = exceptions.length; 607 this.exceptionIndexTable = new int[numberOfExceptions]; 608 for (int i = 0; i < numberOfExceptions; ++i) { 609 this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index; 610 } 611 } else { 612 numberOfExceptions = 0; 613 this.exceptionIndexTable = null; 614 } 615 this.compute = compute; 616 if (compute != COMPUTE_NOTHING) { 617 // Update maxLocals and currentLocals. 618 int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2; 619 if ((access & Opcodes.ACC_STATIC) != 0) { 620 --argumentsSize; 621 } 622 maxLocals = argumentsSize; 623 currentLocals = argumentsSize; 624 // Create and visit the label for the first basic block. 625 firstBasicBlock = new Label(); 626 visitLabel(firstBasicBlock); 627 } 628 } 629 hasFrames()630 boolean hasFrames() { 631 return stackMapTableNumberOfEntries > 0; 632 } 633 hasAsmInstructions()634 boolean hasAsmInstructions() { 635 return hasAsmInstructions; 636 } 637 638 // ----------------------------------------------------------------------------------------------- 639 // Implementation of the MethodVisitor abstract class 640 // ----------------------------------------------------------------------------------------------- 641 642 @Override visitParameter(final String name, final int access)643 public void visitParameter(final String name, final int access) { 644 if (parameters == null) { 645 parameters = new ByteVector(); 646 } 647 ++parametersCount; 648 parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access); 649 } 650 651 @Override visitAnnotationDefault()652 public AnnotationVisitor visitAnnotationDefault() { 653 defaultValue = new ByteVector(); 654 return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null); 655 } 656 657 @Override visitAnnotation(final String descriptor, final boolean visible)658 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { 659 if (visible) { 660 return lastRuntimeVisibleAnnotation = 661 AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation); 662 } else { 663 return lastRuntimeInvisibleAnnotation = 664 AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation); 665 } 666 } 667 668 @Override visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)669 public AnnotationVisitor visitTypeAnnotation( 670 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 671 if (visible) { 672 return lastRuntimeVisibleTypeAnnotation = 673 AnnotationWriter.create( 674 symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation); 675 } else { 676 return lastRuntimeInvisibleTypeAnnotation = 677 AnnotationWriter.create( 678 symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation); 679 } 680 } 681 682 @Override visitAnnotableParameterCount(final int parameterCount, final boolean visible)683 public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) { 684 if (visible) { 685 visibleAnnotableParameterCount = parameterCount; 686 } else { 687 invisibleAnnotableParameterCount = parameterCount; 688 } 689 } 690 691 @Override visitParameterAnnotation( final int parameter, final String annotationDescriptor, final boolean visible)692 public AnnotationVisitor visitParameterAnnotation( 693 final int parameter, final String annotationDescriptor, final boolean visible) { 694 if (visible) { 695 if (lastRuntimeVisibleParameterAnnotations == null) { 696 lastRuntimeVisibleParameterAnnotations = 697 new AnnotationWriter[Type.getArgumentCount(descriptor)]; 698 } 699 return lastRuntimeVisibleParameterAnnotations[parameter] = 700 AnnotationWriter.create( 701 symbolTable, annotationDescriptor, lastRuntimeVisibleParameterAnnotations[parameter]); 702 } else { 703 if (lastRuntimeInvisibleParameterAnnotations == null) { 704 lastRuntimeInvisibleParameterAnnotations = 705 new AnnotationWriter[Type.getArgumentCount(descriptor)]; 706 } 707 return lastRuntimeInvisibleParameterAnnotations[parameter] = 708 AnnotationWriter.create( 709 symbolTable, 710 annotationDescriptor, 711 lastRuntimeInvisibleParameterAnnotations[parameter]); 712 } 713 } 714 715 @Override visitAttribute(final Attribute attribute)716 public void visitAttribute(final Attribute attribute) { 717 // Store the attributes in the <i>reverse</i> order of their visit by this method. 718 if (attribute.isCodeAttribute()) { 719 attribute.nextAttribute = firstCodeAttribute; 720 firstCodeAttribute = attribute; 721 } else { 722 attribute.nextAttribute = firstAttribute; 723 firstAttribute = attribute; 724 } 725 } 726 727 @Override visitCode()728 public void visitCode() { 729 // Nothing to do. 730 } 731 732 @Override visitFrame( final int type, final int numLocal, final Object[] local, final int numStack, final Object[] stack)733 public void visitFrame( 734 final int type, 735 final int numLocal, 736 final Object[] local, 737 final int numStack, 738 final Object[] stack) { 739 if (compute == COMPUTE_ALL_FRAMES) { 740 return; 741 } 742 743 if (compute == COMPUTE_INSERTED_FRAMES) { 744 if (currentBasicBlock.frame == null) { 745 // This should happen only once, for the implicit first frame (which is explicitly visited 746 // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES 747 // can't be set if EXPAND_ASM_INSNS is not used). 748 currentBasicBlock.frame = new CurrentFrame(currentBasicBlock); 749 currentBasicBlock.frame.setInputFrameFromDescriptor( 750 symbolTable, accessFlags, descriptor, numLocal); 751 currentBasicBlock.frame.accept(this); 752 } else { 753 if (type == Opcodes.F_NEW) { 754 currentBasicBlock.frame.setInputFrameFromApiFormat( 755 symbolTable, numLocal, local, numStack, stack); 756 } 757 // If type is not F_NEW then it is F_INSERT by hypothesis, and currentBlock.frame contains 758 // the stack map frame at the current instruction, computed from the last F_NEW frame and 759 // the bytecode instructions in between (via calls to CurrentFrame#execute). 760 currentBasicBlock.frame.accept(this); 761 } 762 } else if (type == Opcodes.F_NEW) { 763 if (previousFrame == null) { 764 int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2; 765 Frame implicitFirstFrame = new Frame(new Label()); 766 implicitFirstFrame.setInputFrameFromDescriptor( 767 symbolTable, accessFlags, descriptor, argumentsSize); 768 implicitFirstFrame.accept(this); 769 } 770 currentLocals = numLocal; 771 int frameIndex = visitFrameStart(code.length, numLocal, numStack); 772 for (int i = 0; i < numLocal; ++i) { 773 currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]); 774 } 775 for (int i = 0; i < numStack; ++i) { 776 currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]); 777 } 778 visitFrameEnd(); 779 } else { 780 if (symbolTable.getMajorVersion() < Opcodes.V1_6) { 781 throw new IllegalArgumentException("Class versions V1_5 or less must use F_NEW frames."); 782 } 783 int offsetDelta; 784 if (stackMapTableEntries == null) { 785 stackMapTableEntries = new ByteVector(); 786 offsetDelta = code.length; 787 } else { 788 offsetDelta = code.length - previousFrameOffset - 1; 789 if (offsetDelta < 0) { 790 if (type == Opcodes.F_SAME) { 791 return; 792 } else { 793 throw new IllegalStateException(); 794 } 795 } 796 } 797 798 switch (type) { 799 case Opcodes.F_FULL: 800 currentLocals = numLocal; 801 stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal); 802 for (int i = 0; i < numLocal; ++i) { 803 putFrameType(local[i]); 804 } 805 stackMapTableEntries.putShort(numStack); 806 for (int i = 0; i < numStack; ++i) { 807 putFrameType(stack[i]); 808 } 809 break; 810 case Opcodes.F_APPEND: 811 currentLocals += numLocal; 812 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + numLocal).putShort(offsetDelta); 813 for (int i = 0; i < numLocal; ++i) { 814 putFrameType(local[i]); 815 } 816 break; 817 case Opcodes.F_CHOP: 818 currentLocals -= numLocal; 819 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - numLocal).putShort(offsetDelta); 820 break; 821 case Opcodes.F_SAME: 822 if (offsetDelta < 64) { 823 stackMapTableEntries.putByte(offsetDelta); 824 } else { 825 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); 826 } 827 break; 828 case Opcodes.F_SAME1: 829 if (offsetDelta < 64) { 830 stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); 831 } else { 832 stackMapTableEntries 833 .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) 834 .putShort(offsetDelta); 835 } 836 putFrameType(stack[0]); 837 break; 838 default: 839 throw new IllegalArgumentException(); 840 } 841 842 previousFrameOffset = code.length; 843 ++stackMapTableNumberOfEntries; 844 } 845 846 if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) { 847 relativeStackSize = numStack; 848 for (int i = 0; i < numStack; ++i) { 849 if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { 850 relativeStackSize++; 851 } 852 } 853 if (relativeStackSize > maxRelativeStackSize) { 854 maxRelativeStackSize = relativeStackSize; 855 } 856 } 857 858 maxStack = Math.max(maxStack, numStack); 859 maxLocals = Math.max(maxLocals, currentLocals); 860 } 861 862 @Override visitInsn(final int opcode)863 public void visitInsn(final int opcode) { 864 lastBytecodeOffset = code.length; 865 // Add the instruction to the bytecode of the method. 866 code.putByte(opcode); 867 // If needed, update the maximum stack size and number of locals, and stack map frames. 868 if (currentBasicBlock != null) { 869 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 870 currentBasicBlock.frame.execute(opcode, 0, null, null); 871 } else { 872 int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; 873 if (size > maxRelativeStackSize) { 874 maxRelativeStackSize = size; 875 } 876 relativeStackSize = size; 877 } 878 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { 879 endCurrentBasicBlockWithNoSuccessor(); 880 } 881 } 882 } 883 884 @Override visitIntInsn(final int opcode, final int operand)885 public void visitIntInsn(final int opcode, final int operand) { 886 lastBytecodeOffset = code.length; 887 // Add the instruction to the bytecode of the method. 888 if (opcode == Opcodes.SIPUSH) { 889 code.put12(opcode, operand); 890 } else { // BIPUSH or NEWARRAY 891 code.put11(opcode, operand); 892 } 893 // If needed, update the maximum stack size and number of locals, and stack map frames. 894 if (currentBasicBlock != null) { 895 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 896 currentBasicBlock.frame.execute(opcode, operand, null, null); 897 } else if (opcode != Opcodes.NEWARRAY) { 898 // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY. 899 int size = relativeStackSize + 1; 900 if (size > maxRelativeStackSize) { 901 maxRelativeStackSize = size; 902 } 903 relativeStackSize = size; 904 } 905 } 906 } 907 908 @Override visitVarInsn(final int opcode, final int varIndex)909 public void visitVarInsn(final int opcode, final int varIndex) { 910 lastBytecodeOffset = code.length; 911 // Add the instruction to the bytecode of the method. 912 if (varIndex < 4 && opcode != Opcodes.RET) { 913 int optimizedOpcode; 914 if (opcode < Opcodes.ISTORE) { 915 optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + varIndex; 916 } else { 917 optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + varIndex; 918 } 919 code.putByte(optimizedOpcode); 920 } else if (varIndex >= 256) { 921 code.putByte(Constants.WIDE).put12(opcode, varIndex); 922 } else { 923 code.put11(opcode, varIndex); 924 } 925 // If needed, update the maximum stack size and number of locals, and stack map frames. 926 if (currentBasicBlock != null) { 927 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 928 currentBasicBlock.frame.execute(opcode, varIndex, null, null); 929 } else { 930 if (opcode == Opcodes.RET) { 931 // No stack size delta. 932 currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END; 933 currentBasicBlock.outputStackSize = (short) relativeStackSize; 934 endCurrentBasicBlockWithNoSuccessor(); 935 } else { // xLOAD or xSTORE 936 int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; 937 if (size > maxRelativeStackSize) { 938 maxRelativeStackSize = size; 939 } 940 relativeStackSize = size; 941 } 942 } 943 } 944 if (compute != COMPUTE_NOTHING) { 945 int currentMaxLocals; 946 if (opcode == Opcodes.LLOAD 947 || opcode == Opcodes.DLOAD 948 || opcode == Opcodes.LSTORE 949 || opcode == Opcodes.DSTORE) { 950 currentMaxLocals = varIndex + 2; 951 } else { 952 currentMaxLocals = varIndex + 1; 953 } 954 if (currentMaxLocals > maxLocals) { 955 maxLocals = currentMaxLocals; 956 } 957 } 958 if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) { 959 // If there are exception handler blocks, each instruction within a handler range is, in 960 // theory, a basic block (since execution can jump from this instruction to the exception 961 // handler). As a consequence, the local variable types at the beginning of the handler 962 // block should be the merge of the local variable types at all the instructions within the 963 // handler range. However, instead of creating a basic block for each instruction, we can 964 // get the same result in a more efficient way. Namely, by starting a new basic block after 965 // each xSTORE instruction, which is what we do here. 966 visitLabel(new Label()); 967 } 968 } 969 970 @Override visitTypeInsn(final int opcode, final String type)971 public void visitTypeInsn(final int opcode, final String type) { 972 lastBytecodeOffset = code.length; 973 // Add the instruction to the bytecode of the method. 974 Symbol typeSymbol = symbolTable.addConstantClass(type); 975 code.put12(opcode, typeSymbol.index); 976 // If needed, update the maximum stack size and number of locals, and stack map frames. 977 if (currentBasicBlock != null) { 978 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 979 currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable); 980 } else if (opcode == Opcodes.NEW) { 981 // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF. 982 int size = relativeStackSize + 1; 983 if (size > maxRelativeStackSize) { 984 maxRelativeStackSize = size; 985 } 986 relativeStackSize = size; 987 } 988 } 989 } 990 991 @Override visitFieldInsn( final int opcode, final String owner, final String name, final String descriptor)992 public void visitFieldInsn( 993 final int opcode, final String owner, final String name, final String descriptor) { 994 lastBytecodeOffset = code.length; 995 // Add the instruction to the bytecode of the method. 996 Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor); 997 code.put12(opcode, fieldrefSymbol.index); 998 // If needed, update the maximum stack size and number of locals, and stack map frames. 999 if (currentBasicBlock != null) { 1000 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 1001 currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable); 1002 } else { 1003 int size; 1004 char firstDescChar = descriptor.charAt(0); 1005 switch (opcode) { 1006 case Opcodes.GETSTATIC: 1007 size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1); 1008 break; 1009 case Opcodes.PUTSTATIC: 1010 size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1); 1011 break; 1012 case Opcodes.GETFIELD: 1013 size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0); 1014 break; 1015 case Opcodes.PUTFIELD: 1016 default: 1017 size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2); 1018 break; 1019 } 1020 if (size > maxRelativeStackSize) { 1021 maxRelativeStackSize = size; 1022 } 1023 relativeStackSize = size; 1024 } 1025 } 1026 } 1027 1028 @Override visitMethodInsn( final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface)1029 public void visitMethodInsn( 1030 final int opcode, 1031 final String owner, 1032 final String name, 1033 final String descriptor, 1034 final boolean isInterface) { 1035 lastBytecodeOffset = code.length; 1036 // Add the instruction to the bytecode of the method. 1037 Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface); 1038 if (opcode == Opcodes.INVOKEINTERFACE) { 1039 code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index) 1040 .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0); 1041 } else { 1042 code.put12(opcode, methodrefSymbol.index); 1043 } 1044 // If needed, update the maximum stack size and number of locals, and stack map frames. 1045 if (currentBasicBlock != null) { 1046 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 1047 currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable); 1048 } else { 1049 int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes(); 1050 int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2); 1051 int size; 1052 if (opcode == Opcodes.INVOKESTATIC) { 1053 size = relativeStackSize + stackSizeDelta + 1; 1054 } else { 1055 size = relativeStackSize + stackSizeDelta; 1056 } 1057 if (size > maxRelativeStackSize) { 1058 maxRelativeStackSize = size; 1059 } 1060 relativeStackSize = size; 1061 } 1062 } 1063 } 1064 1065 @Override visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)1066 public void visitInvokeDynamicInsn( 1067 final String name, 1068 final String descriptor, 1069 final Handle bootstrapMethodHandle, 1070 final Object... bootstrapMethodArguments) { 1071 lastBytecodeOffset = code.length; 1072 // Add the instruction to the bytecode of the method. 1073 Symbol invokeDynamicSymbol = 1074 symbolTable.addConstantInvokeDynamic( 1075 name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); 1076 code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index); 1077 code.putShort(0); 1078 // If needed, update the maximum stack size and number of locals, and stack map frames. 1079 if (currentBasicBlock != null) { 1080 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 1081 currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable); 1082 } else { 1083 int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes(); 1084 int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1; 1085 int size = relativeStackSize + stackSizeDelta; 1086 if (size > maxRelativeStackSize) { 1087 maxRelativeStackSize = size; 1088 } 1089 relativeStackSize = size; 1090 } 1091 } 1092 } 1093 1094 @Override visitJumpInsn(final int opcode, final Label label)1095 public void visitJumpInsn(final int opcode, final Label label) { 1096 lastBytecodeOffset = code.length; 1097 // Add the instruction to the bytecode of the method. 1098 // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode. 1099 int baseOpcode = 1100 opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode; 1101 boolean nextInsnIsJumpTarget = false; 1102 if ((label.flags & Label.FLAG_RESOLVED) != 0 1103 && label.bytecodeOffset - code.length < Short.MIN_VALUE) { 1104 // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO 1105 // with GOTO_W, JSR with JSR_W and IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., where 1106 // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where <L> designates 1107 // the instruction just after the GOTO_W. 1108 if (baseOpcode == Opcodes.GOTO) { 1109 code.putByte(Constants.GOTO_W); 1110 } else if (baseOpcode == Opcodes.JSR) { 1111 code.putByte(Constants.JSR_W); 1112 } else { 1113 // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least 1114 // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a 1115 // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W). 1116 code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1); 1117 code.putShort(8); 1118 // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this 1119 // method or another one, and if the class has frames, we will need to insert a frame after 1120 // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM 1121 // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W 1122 // here, which has the unfortunate effect of forcing this additional round trip (which in 1123 // some case would not have been really necessary, but we can't know this at this point). 1124 code.putByte(Constants.ASM_GOTO_W); 1125 hasAsmInstructions = true; 1126 // The instruction after the GOTO_W becomes the target of the IFNOT instruction. 1127 nextInsnIsJumpTarget = true; 1128 } 1129 label.put(code, code.length - 1, true); 1130 } else if (baseOpcode != opcode) { 1131 // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove 1132 // ASM specific instructions). In this case we keep the original instruction. 1133 code.putByte(opcode); 1134 label.put(code, code.length - 1, true); 1135 } else { 1136 // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these 1137 // cases we store the offset in 2 bytes (which will be increased via a ClassReader -> 1138 // ClassWriter round trip if it turns out that 2 bytes are not sufficient). 1139 code.putByte(baseOpcode); 1140 label.put(code, code.length - 1, false); 1141 } 1142 1143 // If needed, update the maximum stack size and number of locals, and stack map frames. 1144 if (currentBasicBlock != null) { 1145 Label nextBasicBlock = null; 1146 if (compute == COMPUTE_ALL_FRAMES) { 1147 currentBasicBlock.frame.execute(baseOpcode, 0, null, null); 1148 // Record the fact that 'label' is the target of a jump instruction. 1149 label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; 1150 // Add 'label' as a successor of the current basic block. 1151 addSuccessorToCurrentBasicBlock(Edge.JUMP, label); 1152 if (baseOpcode != Opcodes.GOTO) { 1153 // The next instruction starts a new basic block (except for GOTO: by default the code 1154 // following a goto is unreachable - unless there is an explicit label for it - and we 1155 // should not compute stack frame types for its instructions). 1156 nextBasicBlock = new Label(); 1157 } 1158 } else if (compute == COMPUTE_INSERTED_FRAMES) { 1159 currentBasicBlock.frame.execute(baseOpcode, 0, null, null); 1160 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) { 1161 // No need to update maxRelativeStackSize (the stack size delta is always negative). 1162 relativeStackSize += STACK_SIZE_DELTA[baseOpcode]; 1163 } else { 1164 if (baseOpcode == Opcodes.JSR) { 1165 // Record the fact that 'label' designates a subroutine, if not already done. 1166 if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) { 1167 label.flags |= Label.FLAG_SUBROUTINE_START; 1168 hasSubroutines = true; 1169 } 1170 currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER; 1171 // Note that, by construction in this method, a block which calls a subroutine has at 1172 // least two successors in the control flow graph: the first one (added below) leads to 1173 // the instruction after the JSR, while the second one (added here) leads to the JSR 1174 // target. Note that the first successor is virtual (it does not correspond to a possible 1175 // execution path): it is only used to compute the successors of the basic blocks ending 1176 // with a ret, in {@link Label#addSubroutineRetSuccessors}. 1177 addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label); 1178 // The instruction after the JSR starts a new basic block. 1179 nextBasicBlock = new Label(); 1180 } else { 1181 // No need to update maxRelativeStackSize (the stack size delta is always negative). 1182 relativeStackSize += STACK_SIZE_DELTA[baseOpcode]; 1183 addSuccessorToCurrentBasicBlock(relativeStackSize, label); 1184 } 1185 } 1186 // If the next instruction starts a new basic block, call visitLabel to add the label of this 1187 // instruction as a successor of the current block, and to start a new basic block. 1188 if (nextBasicBlock != null) { 1189 if (nextInsnIsJumpTarget) { 1190 nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET; 1191 } 1192 visitLabel(nextBasicBlock); 1193 } 1194 if (baseOpcode == Opcodes.GOTO) { 1195 endCurrentBasicBlockWithNoSuccessor(); 1196 } 1197 } 1198 } 1199 1200 @Override visitLabel(final Label label)1201 public void visitLabel(final Label label) { 1202 // Resolve the forward references to this label, if any. 1203 hasAsmInstructions |= label.resolve(code.data, stackMapTableEntries, code.length); 1204 // visitLabel starts a new basic block (except for debug only labels), so we need to update the 1205 // previous and current block references and list of successors. 1206 if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) { 1207 return; 1208 } 1209 if (compute == COMPUTE_ALL_FRAMES) { 1210 if (currentBasicBlock != null) { 1211 if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) { 1212 // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only 1213 // one place, but this does not work for labels which have not been visited yet. 1214 // Therefore, when we detect here two labels having the same bytecode offset, we need to 1215 // - consolidate the state scattered in these two instances into the canonical instance: 1216 currentBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET); 1217 // - make sure the two instances share the same Frame instance (the implementation of 1218 // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be 1219 // null): 1220 label.frame = currentBasicBlock.frame; 1221 // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so 1222 // that they still refer to the canonical instance for this bytecode offset. 1223 return; 1224 } 1225 // End the current basic block (with one new successor). 1226 addSuccessorToCurrentBasicBlock(Edge.JUMP, label); 1227 } 1228 // Append 'label' at the end of the basic block list. 1229 if (lastBasicBlock != null) { 1230 if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) { 1231 // Same comment as above. 1232 lastBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET); 1233 // Here label.frame should be null. 1234 label.frame = lastBasicBlock.frame; 1235 currentBasicBlock = lastBasicBlock; 1236 return; 1237 } 1238 lastBasicBlock.nextBasicBlock = label; 1239 } 1240 lastBasicBlock = label; 1241 // Make it the new current basic block. 1242 currentBasicBlock = label; 1243 // Here label.frame should be null. 1244 label.frame = new Frame(label); 1245 } else if (compute == COMPUTE_INSERTED_FRAMES) { 1246 if (currentBasicBlock == null) { 1247 // This case should happen only once, for the visitLabel call in the constructor. Indeed, if 1248 // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged. 1249 currentBasicBlock = label; 1250 } else { 1251 // Update the frame owner so that a correct frame offset is computed in Frame.accept(). 1252 currentBasicBlock.frame.owner = label; 1253 } 1254 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { 1255 if (currentBasicBlock != null) { 1256 // End the current basic block (with one new successor). 1257 currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; 1258 addSuccessorToCurrentBasicBlock(relativeStackSize, label); 1259 } 1260 // Start a new current basic block, and reset the current and maximum relative stack sizes. 1261 currentBasicBlock = label; 1262 relativeStackSize = 0; 1263 maxRelativeStackSize = 0; 1264 // Append the new basic block at the end of the basic block list. 1265 if (lastBasicBlock != null) { 1266 lastBasicBlock.nextBasicBlock = label; 1267 } 1268 lastBasicBlock = label; 1269 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES && currentBasicBlock == null) { 1270 // This case should happen only once, for the visitLabel call in the constructor. Indeed, if 1271 // compute is equal to COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES, currentBasicBlock stays 1272 // unchanged. 1273 currentBasicBlock = label; 1274 } 1275 } 1276 1277 @Override visitLdcInsn(final Object value)1278 public void visitLdcInsn(final Object value) { 1279 lastBytecodeOffset = code.length; 1280 // Add the instruction to the bytecode of the method. 1281 Symbol constantSymbol = symbolTable.addConstant(value); 1282 int constantIndex = constantSymbol.index; 1283 char firstDescriptorChar; 1284 boolean isLongOrDouble = 1285 constantSymbol.tag == Symbol.CONSTANT_LONG_TAG 1286 || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG 1287 || (constantSymbol.tag == Symbol.CONSTANT_DYNAMIC_TAG 1288 && ((firstDescriptorChar = constantSymbol.value.charAt(0)) == 'J' 1289 || firstDescriptorChar == 'D')); 1290 if (isLongOrDouble) { 1291 code.put12(Constants.LDC2_W, constantIndex); 1292 } else if (constantIndex >= 256) { 1293 code.put12(Constants.LDC_W, constantIndex); 1294 } else { 1295 code.put11(Opcodes.LDC, constantIndex); 1296 } 1297 // If needed, update the maximum stack size and number of locals, and stack map frames. 1298 if (currentBasicBlock != null) { 1299 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 1300 currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable); 1301 } else { 1302 int size = relativeStackSize + (isLongOrDouble ? 2 : 1); 1303 if (size > maxRelativeStackSize) { 1304 maxRelativeStackSize = size; 1305 } 1306 relativeStackSize = size; 1307 } 1308 } 1309 } 1310 1311 @Override visitIincInsn(final int varIndex, final int increment)1312 public void visitIincInsn(final int varIndex, final int increment) { 1313 lastBytecodeOffset = code.length; 1314 // Add the instruction to the bytecode of the method. 1315 if ((varIndex > 255) || (increment > 127) || (increment < -128)) { 1316 code.putByte(Constants.WIDE).put12(Opcodes.IINC, varIndex).putShort(increment); 1317 } else { 1318 code.putByte(Opcodes.IINC).put11(varIndex, increment); 1319 } 1320 // If needed, update the maximum stack size and number of locals, and stack map frames. 1321 if (currentBasicBlock != null 1322 && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) { 1323 currentBasicBlock.frame.execute(Opcodes.IINC, varIndex, null, null); 1324 } 1325 if (compute != COMPUTE_NOTHING) { 1326 int currentMaxLocals = varIndex + 1; 1327 if (currentMaxLocals > maxLocals) { 1328 maxLocals = currentMaxLocals; 1329 } 1330 } 1331 } 1332 1333 @Override visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label... labels)1334 public void visitTableSwitchInsn( 1335 final int min, final int max, final Label dflt, final Label... labels) { 1336 lastBytecodeOffset = code.length; 1337 // Add the instruction to the bytecode of the method. 1338 code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4); 1339 dflt.put(code, lastBytecodeOffset, true); 1340 code.putInt(min).putInt(max); 1341 for (Label label : labels) { 1342 label.put(code, lastBytecodeOffset, true); 1343 } 1344 // If needed, update the maximum stack size and number of locals, and stack map frames. 1345 visitSwitchInsn(dflt, labels); 1346 } 1347 1348 @Override visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)1349 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { 1350 lastBytecodeOffset = code.length; 1351 // Add the instruction to the bytecode of the method. 1352 code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4); 1353 dflt.put(code, lastBytecodeOffset, true); 1354 code.putInt(labels.length); 1355 for (int i = 0; i < labels.length; ++i) { 1356 code.putInt(keys[i]); 1357 labels[i].put(code, lastBytecodeOffset, true); 1358 } 1359 // If needed, update the maximum stack size and number of locals, and stack map frames. 1360 visitSwitchInsn(dflt, labels); 1361 } 1362 visitSwitchInsn(final Label dflt, final Label[] labels)1363 private void visitSwitchInsn(final Label dflt, final Label[] labels) { 1364 if (currentBasicBlock != null) { 1365 if (compute == COMPUTE_ALL_FRAMES) { 1366 currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); 1367 // Add all the labels as successors of the current basic block. 1368 addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt); 1369 dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; 1370 for (Label label : labels) { 1371 addSuccessorToCurrentBasicBlock(Edge.JUMP, label); 1372 label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; 1373 } 1374 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { 1375 // No need to update maxRelativeStackSize (the stack size delta is always negative). 1376 --relativeStackSize; 1377 // Add all the labels as successors of the current basic block. 1378 addSuccessorToCurrentBasicBlock(relativeStackSize, dflt); 1379 for (Label label : labels) { 1380 addSuccessorToCurrentBasicBlock(relativeStackSize, label); 1381 } 1382 } 1383 // End the current basic block. 1384 endCurrentBasicBlockWithNoSuccessor(); 1385 } 1386 } 1387 1388 @Override visitMultiANewArrayInsn(final String descriptor, final int numDimensions)1389 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { 1390 lastBytecodeOffset = code.length; 1391 // Add the instruction to the bytecode of the method. 1392 Symbol descSymbol = symbolTable.addConstantClass(descriptor); 1393 code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions); 1394 // If needed, update the maximum stack size and number of locals, and stack map frames. 1395 if (currentBasicBlock != null) { 1396 if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { 1397 currentBasicBlock.frame.execute( 1398 Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable); 1399 } else { 1400 // No need to update maxRelativeStackSize (the stack size delta is always negative). 1401 relativeStackSize += 1 - numDimensions; 1402 } 1403 } 1404 } 1405 1406 @Override visitInsnAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1407 public AnnotationVisitor visitInsnAnnotation( 1408 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 1409 if (visible) { 1410 return lastCodeRuntimeVisibleTypeAnnotation = 1411 AnnotationWriter.create( 1412 symbolTable, 1413 (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), 1414 typePath, 1415 descriptor, 1416 lastCodeRuntimeVisibleTypeAnnotation); 1417 } else { 1418 return lastCodeRuntimeInvisibleTypeAnnotation = 1419 AnnotationWriter.create( 1420 symbolTable, 1421 (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), 1422 typePath, 1423 descriptor, 1424 lastCodeRuntimeInvisibleTypeAnnotation); 1425 } 1426 } 1427 1428 @Override visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type)1429 public void visitTryCatchBlock( 1430 final Label start, final Label end, final Label handler, final String type) { 1431 Handler newHandler = 1432 new Handler( 1433 start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type); 1434 if (firstHandler == null) { 1435 firstHandler = newHandler; 1436 } else { 1437 lastHandler.nextHandler = newHandler; 1438 } 1439 lastHandler = newHandler; 1440 } 1441 1442 @Override visitTryCatchAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1443 public AnnotationVisitor visitTryCatchAnnotation( 1444 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 1445 if (visible) { 1446 return lastCodeRuntimeVisibleTypeAnnotation = 1447 AnnotationWriter.create( 1448 symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeVisibleTypeAnnotation); 1449 } else { 1450 return lastCodeRuntimeInvisibleTypeAnnotation = 1451 AnnotationWriter.create( 1452 symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeInvisibleTypeAnnotation); 1453 } 1454 } 1455 1456 @Override visitLocalVariable( final String name, final String descriptor, final String signature, final Label start, final Label end, final int index)1457 public void visitLocalVariable( 1458 final String name, 1459 final String descriptor, 1460 final String signature, 1461 final Label start, 1462 final Label end, 1463 final int index) { 1464 if (signature != null) { 1465 if (localVariableTypeTable == null) { 1466 localVariableTypeTable = new ByteVector(); 1467 } 1468 ++localVariableTypeTableLength; 1469 localVariableTypeTable 1470 .putShort(start.bytecodeOffset) 1471 .putShort(end.bytecodeOffset - start.bytecodeOffset) 1472 .putShort(symbolTable.addConstantUtf8(name)) 1473 .putShort(symbolTable.addConstantUtf8(signature)) 1474 .putShort(index); 1475 } 1476 if (localVariableTable == null) { 1477 localVariableTable = new ByteVector(); 1478 } 1479 ++localVariableTableLength; 1480 localVariableTable 1481 .putShort(start.bytecodeOffset) 1482 .putShort(end.bytecodeOffset - start.bytecodeOffset) 1483 .putShort(symbolTable.addConstantUtf8(name)) 1484 .putShort(symbolTable.addConstantUtf8(descriptor)) 1485 .putShort(index); 1486 if (compute != COMPUTE_NOTHING) { 1487 char firstDescChar = descriptor.charAt(0); 1488 int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1); 1489 if (currentMaxLocals > maxLocals) { 1490 maxLocals = currentMaxLocals; 1491 } 1492 } 1493 } 1494 1495 @Override visitLocalVariableAnnotation( final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, final int[] index, final String descriptor, final boolean visible)1496 public AnnotationVisitor visitLocalVariableAnnotation( 1497 final int typeRef, 1498 final TypePath typePath, 1499 final Label[] start, 1500 final Label[] end, 1501 final int[] index, 1502 final String descriptor, 1503 final boolean visible) { 1504 // Create a ByteVector to hold a 'type_annotation' JVMS structure. 1505 // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. 1506 ByteVector typeAnnotation = new ByteVector(); 1507 // Write target_type, target_info, and target_path. 1508 typeAnnotation.putByte(typeRef >>> 24).putShort(start.length); 1509 for (int i = 0; i < start.length; ++i) { 1510 typeAnnotation 1511 .putShort(start[i].bytecodeOffset) 1512 .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset) 1513 .putShort(index[i]); 1514 } 1515 TypePath.put(typePath, typeAnnotation); 1516 // Write type_index and reserve space for num_element_value_pairs. 1517 typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); 1518 if (visible) { 1519 return lastCodeRuntimeVisibleTypeAnnotation = 1520 new AnnotationWriter( 1521 symbolTable, 1522 /* useNamedValues = */ true, 1523 typeAnnotation, 1524 lastCodeRuntimeVisibleTypeAnnotation); 1525 } else { 1526 return lastCodeRuntimeInvisibleTypeAnnotation = 1527 new AnnotationWriter( 1528 symbolTable, 1529 /* useNamedValues = */ true, 1530 typeAnnotation, 1531 lastCodeRuntimeInvisibleTypeAnnotation); 1532 } 1533 } 1534 1535 @Override visitLineNumber(final int line, final Label start)1536 public void visitLineNumber(final int line, final Label start) { 1537 if (lineNumberTable == null) { 1538 lineNumberTable = new ByteVector(); 1539 } 1540 ++lineNumberTableLength; 1541 lineNumberTable.putShort(start.bytecodeOffset); 1542 lineNumberTable.putShort(line); 1543 } 1544 1545 @Override visitMaxs(final int maxStack, final int maxLocals)1546 public void visitMaxs(final int maxStack, final int maxLocals) { 1547 if (compute == COMPUTE_ALL_FRAMES) { 1548 computeAllFrames(); 1549 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { 1550 computeMaxStackAndLocal(); 1551 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) { 1552 this.maxStack = maxRelativeStackSize; 1553 } else { 1554 this.maxStack = maxStack; 1555 this.maxLocals = maxLocals; 1556 } 1557 } 1558 1559 /** Computes all the stack map frames of the method, from scratch. */ computeAllFrames()1560 private void computeAllFrames() { 1561 // Complete the control flow graph with exception handler blocks. 1562 Handler handler = firstHandler; 1563 while (handler != null) { 1564 String catchTypeDescriptor = 1565 handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor; 1566 int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor); 1567 // Mark handlerBlock as an exception handler. 1568 Label handlerBlock = handler.handlerPc.getCanonicalInstance(); 1569 handlerBlock.flags |= Label.FLAG_JUMP_TARGET; 1570 // Add handlerBlock as a successor of all the basic blocks in the exception handler range. 1571 Label handlerRangeBlock = handler.startPc.getCanonicalInstance(); 1572 Label handlerRangeEnd = handler.endPc.getCanonicalInstance(); 1573 while (handlerRangeBlock != handlerRangeEnd) { 1574 handlerRangeBlock.outgoingEdges = 1575 new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges); 1576 handlerRangeBlock = handlerRangeBlock.nextBasicBlock; 1577 } 1578 handler = handler.nextHandler; 1579 } 1580 1581 // Create and visit the first (implicit) frame. 1582 Frame firstFrame = firstBasicBlock.frame; 1583 firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals); 1584 firstFrame.accept(this); 1585 1586 // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks 1587 // whose stack map frame has changed) and, while there are blocks to process, remove one from 1588 // the list and update the stack map frames of its successor blocks in the control flow graph 1589 // (which might change them, in which case these blocks must be processed too, and are thus 1590 // added to the list of blocks to process). Also compute the maximum stack size of the method, 1591 // as a by-product. 1592 Label listOfBlocksToProcess = firstBasicBlock; 1593 listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST; 1594 int maxStackSize = 0; 1595 while (listOfBlocksToProcess != Label.EMPTY_LIST) { 1596 // Remove a basic block from the list of blocks to process. 1597 Label basicBlock = listOfBlocksToProcess; 1598 listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; 1599 basicBlock.nextListElement = null; 1600 // By definition, basicBlock is reachable. 1601 basicBlock.flags |= Label.FLAG_REACHABLE; 1602 // Update the (absolute) maximum stack size. 1603 int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax; 1604 if (maxBlockStackSize > maxStackSize) { 1605 maxStackSize = maxBlockStackSize; 1606 } 1607 // Update the successor blocks of basicBlock in the control flow graph. 1608 Edge outgoingEdge = basicBlock.outgoingEdges; 1609 while (outgoingEdge != null) { 1610 Label successorBlock = outgoingEdge.successor.getCanonicalInstance(); 1611 boolean successorBlockChanged = 1612 basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info); 1613 if (successorBlockChanged && successorBlock.nextListElement == null) { 1614 // If successorBlock has changed it must be processed. Thus, if it is not already in the 1615 // list of blocks to process, add it to this list. 1616 successorBlock.nextListElement = listOfBlocksToProcess; 1617 listOfBlocksToProcess = successorBlock; 1618 } 1619 outgoingEdge = outgoingEdge.nextEdge; 1620 } 1621 } 1622 1623 // Loop over all the basic blocks and visit the stack map frames that must be stored in the 1624 // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from 1625 // exception handler ranges. 1626 Label basicBlock = firstBasicBlock; 1627 while (basicBlock != null) { 1628 if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) 1629 == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) { 1630 basicBlock.frame.accept(this); 1631 } 1632 if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) { 1633 // Find the start and end bytecode offsets of this unreachable block. 1634 Label nextBasicBlock = basicBlock.nextBasicBlock; 1635 int startOffset = basicBlock.bytecodeOffset; 1636 int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1; 1637 if (endOffset >= startOffset) { 1638 // Replace its instructions with NOP ... NOP ATHROW. 1639 for (int i = startOffset; i < endOffset; ++i) { 1640 code.data[i] = Opcodes.NOP; 1641 } 1642 code.data[endOffset] = (byte) Opcodes.ATHROW; 1643 // Emit a frame for this unreachable block, with no local and a Throwable on the stack 1644 // (so that the ATHROW could consume this Throwable if it were reachable). 1645 int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1); 1646 currentFrame[frameIndex] = 1647 Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable"); 1648 visitFrameEnd(); 1649 // Remove this unreachable basic block from the exception handler ranges. 1650 firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock); 1651 // The maximum stack size is now at least one, because of the Throwable declared above. 1652 maxStackSize = Math.max(maxStackSize, 1); 1653 } 1654 } 1655 basicBlock = basicBlock.nextBasicBlock; 1656 } 1657 1658 this.maxStack = maxStackSize; 1659 } 1660 1661 /** Computes the maximum stack size of the method. */ computeMaxStackAndLocal()1662 private void computeMaxStackAndLocal() { 1663 // Complete the control flow graph with exception handler blocks. 1664 Handler handler = firstHandler; 1665 while (handler != null) { 1666 Label handlerBlock = handler.handlerPc; 1667 Label handlerRangeBlock = handler.startPc; 1668 Label handlerRangeEnd = handler.endPc; 1669 // Add handlerBlock as a successor of all the basic blocks in the exception handler range. 1670 while (handlerRangeBlock != handlerRangeEnd) { 1671 if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) { 1672 handlerRangeBlock.outgoingEdges = 1673 new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges); 1674 } else { 1675 // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing 1676 // edges to preserve the hypothesis about JSR block successors order (see 1677 // {@link #visitJumpInsn}). 1678 handlerRangeBlock.outgoingEdges.nextEdge.nextEdge = 1679 new Edge( 1680 Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge); 1681 } 1682 handlerRangeBlock = handlerRangeBlock.nextBasicBlock; 1683 } 1684 handler = handler.nextHandler; 1685 } 1686 1687 // Complete the control flow graph with the successor blocks of subroutines, if needed. 1688 if (hasSubroutines) { 1689 // First step: find the subroutines. This step determines, for each basic block, to which 1690 // subroutine(s) it belongs. Start with the main "subroutine": 1691 short numSubroutines = 1; 1692 firstBasicBlock.markSubroutine(numSubroutines); 1693 // Then, mark the subroutines called by the main subroutine, then the subroutines called by 1694 // those called by the main subroutine, etc. 1695 for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) { 1696 Label basicBlock = firstBasicBlock; 1697 while (basicBlock != null) { 1698 if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0 1699 && basicBlock.subroutineId == currentSubroutine) { 1700 Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor; 1701 if (jsrTarget.subroutineId == 0) { 1702 // If this subroutine has not been marked yet, find its basic blocks. 1703 jsrTarget.markSubroutine(++numSubroutines); 1704 } 1705 } 1706 basicBlock = basicBlock.nextBasicBlock; 1707 } 1708 } 1709 // Second step: find the successors in the control flow graph of each subroutine basic block 1710 // 'r' ending with a RET instruction. These successors are the virtual successors of the basic 1711 // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'. 1712 Label basicBlock = firstBasicBlock; 1713 while (basicBlock != null) { 1714 if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { 1715 // By construction, jsr targets are stored in the second outgoing edge of basic blocks 1716 // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}). 1717 Label subroutine = basicBlock.outgoingEdges.nextEdge.successor; 1718 subroutine.addSubroutineRetSuccessors(basicBlock); 1719 } 1720 basicBlock = basicBlock.nextBasicBlock; 1721 } 1722 } 1723 1724 // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks 1725 // whose input stack size has changed) and, while there are blocks to process, remove one 1726 // from the list, update the input stack size of its successor blocks in the control flow 1727 // graph, and add these blocks to the list of blocks to process (if not already done). 1728 Label listOfBlocksToProcess = firstBasicBlock; 1729 listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST; 1730 int maxStackSize = maxStack; 1731 while (listOfBlocksToProcess != Label.EMPTY_LIST) { 1732 // Remove a basic block from the list of blocks to process. Note that we don't reset 1733 // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already 1734 // processed basic blocks. 1735 Label basicBlock = listOfBlocksToProcess; 1736 listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; 1737 // Compute the (absolute) input stack size and maximum stack size of this block. 1738 int inputStackTop = basicBlock.inputStackSize; 1739 int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax; 1740 // Update the absolute maximum stack size of the method. 1741 if (maxBlockStackSize > maxStackSize) { 1742 maxStackSize = maxBlockStackSize; 1743 } 1744 // Update the input stack size of the successor blocks of basicBlock in the control flow 1745 // graph, and add these blocks to the list of blocks to process, if not already done. 1746 Edge outgoingEdge = basicBlock.outgoingEdges; 1747 if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { 1748 // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual 1749 // edges which lead to the instruction just after the jsr, and do not correspond to a 1750 // possible execution path (see {@link #visitJumpInsn} and 1751 // {@link Label#FLAG_SUBROUTINE_CALLER}). 1752 outgoingEdge = outgoingEdge.nextEdge; 1753 } 1754 while (outgoingEdge != null) { 1755 Label successorBlock = outgoingEdge.successor; 1756 if (successorBlock.nextListElement == null) { 1757 successorBlock.inputStackSize = 1758 (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info); 1759 successorBlock.nextListElement = listOfBlocksToProcess; 1760 listOfBlocksToProcess = successorBlock; 1761 } 1762 outgoingEdge = outgoingEdge.nextEdge; 1763 } 1764 } 1765 this.maxStack = maxStackSize; 1766 } 1767 1768 @Override visitEnd()1769 public void visitEnd() { 1770 // Nothing to do. 1771 } 1772 1773 // ----------------------------------------------------------------------------------------------- 1774 // Utility methods: control flow analysis algorithm 1775 // ----------------------------------------------------------------------------------------------- 1776 1777 /** 1778 * Adds a successor to {@link #currentBasicBlock} in the control flow graph. 1779 * 1780 * @param info information about the control flow edge to be added. 1781 * @param successor the successor block to be added to the current basic block. 1782 */ addSuccessorToCurrentBasicBlock(final int info, final Label successor)1783 private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) { 1784 currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges); 1785 } 1786 1787 /** 1788 * Ends the current basic block. This method must be used in the case where the current basic 1789 * block does not have any successor. 1790 * 1791 * <p>WARNING: this method must be called after the currently visited instruction has been put in 1792 * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic 1793 * block after the current instruction). 1794 */ endCurrentBasicBlockWithNoSuccessor()1795 private void endCurrentBasicBlockWithNoSuccessor() { 1796 if (compute == COMPUTE_ALL_FRAMES) { 1797 Label nextBasicBlock = new Label(); 1798 nextBasicBlock.frame = new Frame(nextBasicBlock); 1799 nextBasicBlock.resolve(code.data, stackMapTableEntries, code.length); 1800 lastBasicBlock.nextBasicBlock = nextBasicBlock; 1801 lastBasicBlock = nextBasicBlock; 1802 currentBasicBlock = null; 1803 } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { 1804 currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; 1805 currentBasicBlock = null; 1806 } 1807 } 1808 1809 // ----------------------------------------------------------------------------------------------- 1810 // Utility methods: stack map frames 1811 // ----------------------------------------------------------------------------------------------- 1812 1813 /** 1814 * Starts the visit of a new stack map frame, stored in {@link #currentFrame}. 1815 * 1816 * @param offset the bytecode offset of the instruction to which the frame corresponds. 1817 * @param numLocal the number of local variables in the frame. 1818 * @param numStack the number of stack elements in the frame. 1819 * @return the index of the next element to be written in this frame. 1820 */ visitFrameStart(final int offset, final int numLocal, final int numStack)1821 int visitFrameStart(final int offset, final int numLocal, final int numStack) { 1822 int frameLength = 3 + numLocal + numStack; 1823 if (currentFrame == null || currentFrame.length < frameLength) { 1824 currentFrame = new int[frameLength]; 1825 } 1826 currentFrame[0] = offset; 1827 currentFrame[1] = numLocal; 1828 currentFrame[2] = numStack; 1829 return 3; 1830 } 1831 1832 /** 1833 * Sets an abstract type in {@link #currentFrame}. 1834 * 1835 * @param frameIndex the index of the element to be set in {@link #currentFrame}. 1836 * @param abstractType an abstract type. 1837 */ visitAbstractType(final int frameIndex, final int abstractType)1838 void visitAbstractType(final int frameIndex, final int abstractType) { 1839 currentFrame[frameIndex] = abstractType; 1840 } 1841 1842 /** 1843 * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by 1844 * updating the StackMapTable number_of_entries (except if the current frame is the first one, 1845 * which is implicit in StackMapTable). Then resets {@link #currentFrame} to {@literal null}. 1846 */ visitFrameEnd()1847 void visitFrameEnd() { 1848 if (previousFrame != null) { 1849 if (stackMapTableEntries == null) { 1850 stackMapTableEntries = new ByteVector(); 1851 } 1852 putFrame(); 1853 ++stackMapTableNumberOfEntries; 1854 } 1855 previousFrame = currentFrame; 1856 currentFrame = null; 1857 } 1858 1859 /** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */ putFrame()1860 private void putFrame() { 1861 final int numLocal = currentFrame[1]; 1862 final int numStack = currentFrame[2]; 1863 if (symbolTable.getMajorVersion() < Opcodes.V1_6) { 1864 // Generate a StackMap attribute entry, which are always uncompressed. 1865 stackMapTableEntries.putShort(currentFrame[0]).putShort(numLocal); 1866 putAbstractTypes(3, 3 + numLocal); 1867 stackMapTableEntries.putShort(numStack); 1868 putAbstractTypes(3 + numLocal, 3 + numLocal + numStack); 1869 return; 1870 } 1871 final int offsetDelta = 1872 stackMapTableNumberOfEntries == 0 1873 ? currentFrame[0] 1874 : currentFrame[0] - previousFrame[0] - 1; 1875 final int previousNumlocal = previousFrame[1]; 1876 final int numLocalDelta = numLocal - previousNumlocal; 1877 int type = Frame.FULL_FRAME; 1878 if (numStack == 0) { 1879 switch (numLocalDelta) { 1880 case -3: 1881 case -2: 1882 case -1: 1883 type = Frame.CHOP_FRAME; 1884 break; 1885 case 0: 1886 type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED; 1887 break; 1888 case 1: 1889 case 2: 1890 case 3: 1891 type = Frame.APPEND_FRAME; 1892 break; 1893 default: 1894 // Keep the FULL_FRAME type. 1895 break; 1896 } 1897 } else if (numLocalDelta == 0 && numStack == 1) { 1898 type = 1899 offsetDelta < 63 1900 ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME 1901 : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 1902 } 1903 if (type != Frame.FULL_FRAME) { 1904 // Verify if locals are the same as in the previous frame. 1905 int frameIndex = 3; 1906 for (int i = 0; i < previousNumlocal && i < numLocal; i++) { 1907 if (currentFrame[frameIndex] != previousFrame[frameIndex]) { 1908 type = Frame.FULL_FRAME; 1909 break; 1910 } 1911 frameIndex++; 1912 } 1913 } 1914 switch (type) { 1915 case Frame.SAME_FRAME: 1916 stackMapTableEntries.putByte(offsetDelta); 1917 break; 1918 case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME: 1919 stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); 1920 putAbstractTypes(3 + numLocal, 4 + numLocal); 1921 break; 1922 case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: 1923 stackMapTableEntries 1924 .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) 1925 .putShort(offsetDelta); 1926 putAbstractTypes(3 + numLocal, 4 + numLocal); 1927 break; 1928 case Frame.SAME_FRAME_EXTENDED: 1929 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); 1930 break; 1931 case Frame.CHOP_FRAME: 1932 stackMapTableEntries 1933 .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta) 1934 .putShort(offsetDelta); 1935 break; 1936 case Frame.APPEND_FRAME: 1937 stackMapTableEntries 1938 .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta) 1939 .putShort(offsetDelta); 1940 putAbstractTypes(3 + previousNumlocal, 3 + numLocal); 1941 break; 1942 case Frame.FULL_FRAME: 1943 default: 1944 stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal); 1945 putAbstractTypes(3, 3 + numLocal); 1946 stackMapTableEntries.putShort(numStack); 1947 putAbstractTypes(3 + numLocal, 3 + numLocal + numStack); 1948 break; 1949 } 1950 } 1951 1952 /** 1953 * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the 1954 * JVMS verification_type_info format used in StackMapTable attributes. 1955 * 1956 * @param start index of the first type in {@link #currentFrame} to write. 1957 * @param end index of last type in {@link #currentFrame} to write (exclusive). 1958 */ 1959 private void putAbstractTypes(final int start, final int end) { 1960 for (int i = start; i < end; ++i) { 1961 Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries); 1962 } 1963 } 1964 1965 /** 1966 * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS 1967 * verification_type_info format used in StackMapTable attributes. 1968 * 1969 * @param type a frame element type described using the same format as in {@link 1970 * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link 1971 * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or 1972 * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating 1973 * a NEW instruction (for uninitialized types). 1974 */ 1975 private void putFrameType(final Object type) { 1976 if (type instanceof Integer) { 1977 stackMapTableEntries.putByte(((Integer) type).intValue()); 1978 } else if (type instanceof String) { 1979 stackMapTableEntries 1980 .putByte(Frame.ITEM_OBJECT) 1981 .putShort(symbolTable.addConstantClass((String) type).index); 1982 } else { 1983 stackMapTableEntries.putByte(Frame.ITEM_UNINITIALIZED); 1984 ((Label) type).put(stackMapTableEntries); 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