1 /*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2007 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package org.mockito.asm; 31 32 /** 33 * A {@link MethodVisitor} that generates methods in bytecode form. Each visit 34 * method of this class appends the bytecode corresponding to the visited 35 * instruction to a byte vector, in the order these methods are called. 36 * 37 * @author Eric Bruneton 38 * @author Eugene Kuleshov 39 */ 40 class MethodWriter implements MethodVisitor { 41 42 /** 43 * Pseudo access flag used to denote constructors. 44 */ 45 static final int ACC_CONSTRUCTOR = 262144; 46 47 /** 48 * Frame has exactly the same locals as the previous stack map frame and 49 * number of stack items is zero. 50 */ 51 static final int SAME_FRAME = 0; // to 63 (0-3f) 52 53 /** 54 * Frame has exactly the same locals as the previous stack map frame and 55 * number of stack items is 1 56 */ 57 static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f) 58 59 /** 60 * Reserved for future use 61 */ 62 static final int RESERVED = 128; 63 64 /** 65 * Frame has exactly the same locals as the previous stack map frame and 66 * number of stack items is 1. Offset is bigger then 63; 67 */ 68 static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 69 70 /** 71 * Frame where current locals are the same as the locals in the previous 72 * frame, except that the k last locals are absent. The value of k is given 73 * by the formula 251-frame_type. 74 */ 75 static final int CHOP_FRAME = 248; // to 250 (f8-fA) 76 77 /** 78 * Frame has exactly the same locals as the previous stack map frame and 79 * number of stack items is zero. Offset is bigger then 63; 80 */ 81 static final int SAME_FRAME_EXTENDED = 251; // fb 82 83 /** 84 * Frame where current locals are the same as the locals in the previous 85 * frame, except that k additional locals are defined. The value of k is 86 * given by the formula frame_type-251. 87 */ 88 static final int APPEND_FRAME = 252; // to 254 // fc-fe 89 90 /** 91 * Full frame 92 */ 93 static final int FULL_FRAME = 255; // ff 94 95 /** 96 * Indicates that the stack map frames must be recomputed from scratch. In 97 * this case the maximum stack size and number of local variables is also 98 * recomputed from scratch. 99 * 100 * @see #compute 101 */ 102 private static final int FRAMES = 0; 103 104 /** 105 * Indicates that the maximum stack size and number of local variables must 106 * be automatically computed. 107 * 108 * @see #compute 109 */ 110 private static final int MAXS = 1; 111 112 /** 113 * Indicates that nothing must be automatically computed. 114 * 115 * @see #compute 116 */ 117 private static final int NOTHING = 2; 118 119 /** 120 * Next method writer (see {@link ClassWriter#firstMethod firstMethod}). 121 */ 122 MethodWriter next; 123 124 /** 125 * The class writer to which this method must be added. 126 */ 127 final ClassWriter cw; 128 129 /** 130 * Access flags of this method. 131 */ 132 private int access; 133 134 /** 135 * The index of the constant pool item that contains the name of this 136 * method. 137 */ 138 private final int name; 139 140 /** 141 * The index of the constant pool item that contains the descriptor of this 142 * method. 143 */ 144 private final int desc; 145 146 /** 147 * The descriptor of this method. 148 */ 149 private final String descriptor; 150 151 /** 152 * The signature of this method. 153 */ 154 String signature; 155 156 /** 157 * If not zero, indicates that the code of this method must be copied from 158 * the ClassReader associated to this writer in <code>cw.cr</code>. More 159 * precisely, this field gives the index of the first byte to copied from 160 * <code>cw.cr.b</code>. 161 */ 162 int classReaderOffset; 163 164 /** 165 * If not zero, indicates that the code of this method must be copied from 166 * the ClassReader associated to this writer in <code>cw.cr</code>. More 167 * precisely, this field gives the number of bytes to copied from 168 * <code>cw.cr.b</code>. 169 */ 170 int classReaderLength; 171 172 /** 173 * Number of exceptions that can be thrown by this method. 174 */ 175 int exceptionCount; 176 177 /** 178 * The exceptions that can be thrown by this method. More precisely, this 179 * array contains the indexes of the constant pool items that contain the 180 * internal names of these exception classes. 181 */ 182 int[] exceptions; 183 184 /** 185 * The annotation default attribute of this method. May be <tt>null</tt>. 186 */ 187 private ByteVector annd; 188 189 /** 190 * The runtime visible annotations of this method. May be <tt>null</tt>. 191 */ 192 private AnnotationWriter anns; 193 194 /** 195 * The runtime invisible annotations of this method. May be <tt>null</tt>. 196 */ 197 private AnnotationWriter ianns; 198 199 /** 200 * The runtime visible parameter annotations of this method. May be 201 * <tt>null</tt>. 202 */ 203 private AnnotationWriter[] panns; 204 205 /** 206 * The runtime invisible parameter annotations of this method. May be 207 * <tt>null</tt>. 208 */ 209 private AnnotationWriter[] ipanns; 210 211 /** 212 * The number of synthetic parameters of this method. 213 */ 214 private int synthetics; 215 216 /** 217 * The non standard attributes of the method. 218 */ 219 private Attribute attrs; 220 221 /** 222 * The bytecode of this method. 223 */ 224 private ByteVector code = new ByteVector(); 225 226 /** 227 * Maximum stack size of this method. 228 */ 229 private int maxStack; 230 231 /** 232 * Maximum number of local variables for this method. 233 */ 234 private int maxLocals; 235 236 /** 237 * Number of stack map frames in the StackMapTable attribute. 238 */ 239 private int frameCount; 240 241 /** 242 * The StackMapTable attribute. 243 */ 244 private ByteVector stackMap; 245 246 /** 247 * The offset of the last frame that was written in the StackMapTable 248 * attribute. 249 */ 250 private int previousFrameOffset; 251 252 /** 253 * The last frame that was written in the StackMapTable attribute. 254 * 255 * @see #frame 256 */ 257 private int[] previousFrame; 258 259 /** 260 * Index of the next element to be added in {@link #frame}. 261 */ 262 private int frameIndex; 263 264 /** 265 * The current stack map frame. The first element contains the offset of the 266 * instruction to which the frame corresponds, the second element is the 267 * number of locals and the third one is the number of stack elements. The 268 * local variables start at index 3 and are followed by the operand stack 269 * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = 270 * nStack, frame[3] = nLocal. All types are encoded as integers, with the 271 * same format as the one used in {@link Label}, but limited to BASE types. 272 */ 273 private int[] frame; 274 275 /** 276 * Number of elements in the exception handler list. 277 */ 278 private int handlerCount; 279 280 /** 281 * The first element in the exception handler list. 282 */ 283 private Handler firstHandler; 284 285 /** 286 * The last element in the exception handler list. 287 */ 288 private Handler lastHandler; 289 290 /** 291 * Number of entries in the LocalVariableTable attribute. 292 */ 293 private int localVarCount; 294 295 /** 296 * The LocalVariableTable attribute. 297 */ 298 private ByteVector localVar; 299 300 /** 301 * Number of entries in the LocalVariableTypeTable attribute. 302 */ 303 private int localVarTypeCount; 304 305 /** 306 * The LocalVariableTypeTable attribute. 307 */ 308 private ByteVector localVarType; 309 310 /** 311 * Number of entries in the LineNumberTable attribute. 312 */ 313 private int lineNumberCount; 314 315 /** 316 * The LineNumberTable attribute. 317 */ 318 private ByteVector lineNumber; 319 320 /** 321 * The non standard attributes of the method's code. 322 */ 323 private Attribute cattrs; 324 325 /** 326 * Indicates if some jump instructions are too small and need to be resized. 327 */ 328 private boolean resize; 329 330 /** 331 * The number of subroutines in this method. 332 */ 333 private int subroutines; 334 335 // ------------------------------------------------------------------------ 336 337 /* 338 * Fields for the control flow graph analysis algorithm (used to compute the 339 * maximum stack size). A control flow graph contains one node per "basic 340 * block", and one edge per "jump" from one basic block to another. Each 341 * node (i.e., each basic block) is represented by the Label object that 342 * corresponds to the first instruction of this basic block. Each node also 343 * stores the list of its successors in the graph, as a linked list of Edge 344 * objects. 345 */ 346 347 /** 348 * Indicates what must be automatically computed. 349 * 350 * @see #FRAMES 351 * @see #MAXS 352 * @see #NOTHING 353 */ 354 private final int compute; 355 356 /** 357 * A list of labels. This list is the list of basic blocks in the method, 358 * i.e. a list of Label objects linked to each other by their 359 * {@link Label#successor} field, in the order they are visited by 360 * {@link MethodVisitor#visitLabel}, and starting with the first basic block. 361 */ 362 private Label labels; 363 364 /** 365 * The previous basic block. 366 */ 367 private Label previousBlock; 368 369 /** 370 * The current basic block. 371 */ 372 private Label currentBlock; 373 374 /** 375 * The (relative) stack size after the last visited instruction. This size 376 * is relative to the beginning of the current basic block, i.e., the true 377 * stack size after the last visited instruction is equal to the 378 * {@link Label#inputStackTop beginStackSize} of the current basic block 379 * plus <tt>stackSize</tt>. 380 */ 381 private int stackSize; 382 383 /** 384 * The (relative) maximum stack size after the last visited instruction. 385 * This size is relative to the beginning of the current basic block, i.e., 386 * the true maximum stack size after the last visited instruction is equal 387 * to the {@link Label#inputStackTop beginStackSize} of the current basic 388 * block plus <tt>stackSize</tt>. 389 */ 390 private int maxStackSize; 391 392 // ------------------------------------------------------------------------ 393 // Constructor 394 // ------------------------------------------------------------------------ 395 396 /** 397 * Constructs a new {@link MethodWriter}. 398 * 399 * @param cw the class writer in which the method must be added. 400 * @param access the method's access flags (see {@link Opcodes}). 401 * @param name the method's name. 402 * @param desc the method's descriptor (see {@link Type}). 403 * @param signature the method's signature. May be <tt>null</tt>. 404 * @param exceptions the internal names of the method's exceptions. May be 405 * <tt>null</tt>. 406 * @param computeMaxs <tt>true</tt> if the maximum stack size and number 407 * of local variables must be automatically computed. 408 * @param computeFrames <tt>true</tt> if the stack map tables must be 409 * recomputed from scratch. 410 */ MethodWriter( final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions, final boolean computeMaxs, final boolean computeFrames)411 MethodWriter( 412 final ClassWriter cw, 413 final int access, 414 final String name, 415 final String desc, 416 final String signature, 417 final String[] exceptions, 418 final boolean computeMaxs, 419 final boolean computeFrames) 420 { 421 if (cw.firstMethod == null) { 422 cw.firstMethod = this; 423 } else { 424 cw.lastMethod.next = this; 425 } 426 cw.lastMethod = this; 427 this.cw = cw; 428 this.access = access; 429 this.name = cw.newUTF8(name); 430 this.desc = cw.newUTF8(desc); 431 this.descriptor = desc; 432 if (ClassReader.SIGNATURES) { 433 this.signature = signature; 434 } 435 if (exceptions != null && exceptions.length > 0) { 436 exceptionCount = exceptions.length; 437 this.exceptions = new int[exceptionCount]; 438 for (int i = 0; i < exceptionCount; ++i) { 439 this.exceptions[i] = cw.newClass(exceptions[i]); 440 } 441 } 442 this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); 443 if (computeMaxs || computeFrames) { 444 if (computeFrames && "<init>".equals(name)) { 445 this.access |= ACC_CONSTRUCTOR; 446 } 447 // updates maxLocals 448 int size = getArgumentsAndReturnSizes(descriptor) >> 2; 449 if ((access & Opcodes.ACC_STATIC) != 0) { 450 --size; 451 } 452 maxLocals = size; 453 // creates and visits the label for the first basic block 454 labels = new Label(); 455 labels.status |= Label.PUSHED; 456 visitLabel(labels); 457 } 458 } 459 460 // ------------------------------------------------------------------------ 461 // Implementation of the MethodVisitor interface 462 // ------------------------------------------------------------------------ 463 visitAnnotationDefault()464 public AnnotationVisitor visitAnnotationDefault() { 465 if (!ClassReader.ANNOTATIONS) { 466 return null; 467 } 468 annd = new ByteVector(); 469 return new AnnotationWriter(cw, false, annd, null, 0); 470 } 471 visitAnnotation( final String desc, final boolean visible)472 public AnnotationVisitor visitAnnotation( 473 final String desc, 474 final boolean visible) 475 { 476 if (!ClassReader.ANNOTATIONS) { 477 return null; 478 } 479 ByteVector bv = new ByteVector(); 480 // write type, and reserve space for values count 481 bv.putShort(cw.newUTF8(desc)).putShort(0); 482 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); 483 if (visible) { 484 aw.next = anns; 485 anns = aw; 486 } else { 487 aw.next = ianns; 488 ianns = aw; 489 } 490 return aw; 491 } 492 visitParameterAnnotation( final int parameter, final String desc, final boolean visible)493 public AnnotationVisitor visitParameterAnnotation( 494 final int parameter, 495 final String desc, 496 final boolean visible) 497 { 498 if (!ClassReader.ANNOTATIONS) { 499 return null; 500 } 501 ByteVector bv = new ByteVector(); 502 if ("Ljava/lang/Synthetic;".equals(desc)) { 503 // workaround for a bug in javac with synthetic parameters 504 // see ClassReader.readParameterAnnotations 505 synthetics = Math.max(synthetics, parameter + 1); 506 return new AnnotationWriter(cw, false, bv, null, 0); 507 } 508 // write type, and reserve space for values count 509 bv.putShort(cw.newUTF8(desc)).putShort(0); 510 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); 511 if (visible) { 512 if (panns == null) { 513 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; 514 } 515 aw.next = panns[parameter]; 516 panns[parameter] = aw; 517 } else { 518 if (ipanns == null) { 519 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; 520 } 521 aw.next = ipanns[parameter]; 522 ipanns[parameter] = aw; 523 } 524 return aw; 525 } 526 visitAttribute(final Attribute attr)527 public void visitAttribute(final Attribute attr) { 528 if (attr.isCodeAttribute()) { 529 attr.next = cattrs; 530 cattrs = attr; 531 } else { 532 attr.next = attrs; 533 attrs = attr; 534 } 535 } 536 visitCode()537 public void visitCode() { 538 } 539 visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack)540 public void visitFrame( 541 final int type, 542 final int nLocal, 543 final Object[] local, 544 final int nStack, 545 final Object[] stack) 546 { 547 if (!ClassReader.FRAMES || compute == FRAMES) { 548 return; 549 } 550 551 if (type == Opcodes.F_NEW) { 552 startFrame(code.length, nLocal, nStack); 553 for (int i = 0; i < nLocal; ++i) { 554 if (local[i] instanceof String) { 555 frame[frameIndex++] = Frame.OBJECT 556 | cw.addType((String) local[i]); 557 } else if (local[i] instanceof Integer) { 558 frame[frameIndex++] = ((Integer) local[i]).intValue(); 559 } else { 560 frame[frameIndex++] = Frame.UNINITIALIZED 561 | cw.addUninitializedType("", 562 ((Label) local[i]).position); 563 } 564 } 565 for (int i = 0; i < nStack; ++i) { 566 if (stack[i] instanceof String) { 567 frame[frameIndex++] = Frame.OBJECT 568 | cw.addType((String) stack[i]); 569 } else if (stack[i] instanceof Integer) { 570 frame[frameIndex++] = ((Integer) stack[i]).intValue(); 571 } else { 572 frame[frameIndex++] = Frame.UNINITIALIZED 573 | cw.addUninitializedType("", 574 ((Label) stack[i]).position); 575 } 576 } 577 endFrame(); 578 } else { 579 int delta; 580 if (stackMap == null) { 581 stackMap = new ByteVector(); 582 delta = code.length; 583 } else { 584 delta = code.length - previousFrameOffset - 1; 585 } 586 587 switch (type) { 588 case Opcodes.F_FULL: 589 stackMap.putByte(FULL_FRAME) 590 .putShort(delta) 591 .putShort(nLocal); 592 for (int i = 0; i < nLocal; ++i) { 593 writeFrameType(local[i]); 594 } 595 stackMap.putShort(nStack); 596 for (int i = 0; i < nStack; ++i) { 597 writeFrameType(stack[i]); 598 } 599 break; 600 case Opcodes.F_APPEND: 601 stackMap.putByte(SAME_FRAME_EXTENDED + nLocal) 602 .putShort(delta); 603 for (int i = 0; i < nLocal; ++i) { 604 writeFrameType(local[i]); 605 } 606 break; 607 case Opcodes.F_CHOP: 608 stackMap.putByte(SAME_FRAME_EXTENDED - nLocal) 609 .putShort(delta); 610 break; 611 case Opcodes.F_SAME: 612 if (delta < 64) { 613 stackMap.putByte(delta); 614 } else { 615 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); 616 } 617 break; 618 case Opcodes.F_SAME1: 619 if (delta < 64) { 620 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); 621 } else { 622 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) 623 .putShort(delta); 624 } 625 writeFrameType(stack[0]); 626 break; 627 } 628 629 previousFrameOffset = code.length; 630 ++frameCount; 631 } 632 } 633 visitInsn(final int opcode)634 public void visitInsn(final int opcode) { 635 // adds the instruction to the bytecode of the method 636 code.putByte(opcode); 637 // update currentBlock 638 // Label currentBlock = this.currentBlock; 639 if (currentBlock != null) { 640 if (compute == FRAMES) { 641 currentBlock.frame.execute(opcode, 0, null, null); 642 } else { 643 // updates current and max stack sizes 644 int size = stackSize + Frame.SIZE[opcode]; 645 if (size > maxStackSize) { 646 maxStackSize = size; 647 } 648 stackSize = size; 649 } 650 // if opcode == ATHROW or xRETURN, ends current block (no successor) 651 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) 652 || opcode == Opcodes.ATHROW) 653 { 654 noSuccessor(); 655 } 656 } 657 } 658 visitIntInsn(final int opcode, final int operand)659 public void visitIntInsn(final int opcode, final int operand) { 660 // Label currentBlock = this.currentBlock; 661 if (currentBlock != null) { 662 if (compute == FRAMES) { 663 currentBlock.frame.execute(opcode, operand, null, null); 664 } else if (opcode != Opcodes.NEWARRAY) { 665 // updates current and max stack sizes only for NEWARRAY 666 // (stack size variation = 0 for BIPUSH or SIPUSH) 667 int size = stackSize + 1; 668 if (size > maxStackSize) { 669 maxStackSize = size; 670 } 671 stackSize = size; 672 } 673 } 674 // adds the instruction to the bytecode of the method 675 if (opcode == Opcodes.SIPUSH) { 676 code.put12(opcode, operand); 677 } else { // BIPUSH or NEWARRAY 678 code.put11(opcode, operand); 679 } 680 } 681 visitVarInsn(final int opcode, final int var)682 public void visitVarInsn(final int opcode, final int var) { 683 // Label currentBlock = this.currentBlock; 684 if (currentBlock != null) { 685 if (compute == FRAMES) { 686 currentBlock.frame.execute(opcode, var, null, null); 687 } else { 688 // updates current and max stack sizes 689 if (opcode == Opcodes.RET) { 690 // no stack change, but end of current block (no successor) 691 currentBlock.status |= Label.RET; 692 // save 'stackSize' here for future use 693 // (see {@link #findSubroutineSuccessors}) 694 currentBlock.inputStackTop = stackSize; 695 noSuccessor(); 696 } else { // xLOAD or xSTORE 697 int size = stackSize + Frame.SIZE[opcode]; 698 if (size > maxStackSize) { 699 maxStackSize = size; 700 } 701 stackSize = size; 702 } 703 } 704 } 705 if (compute != NOTHING) { 706 // updates max locals 707 int n; 708 if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD 709 || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) 710 { 711 n = var + 2; 712 } else { 713 n = var + 1; 714 } 715 if (n > maxLocals) { 716 maxLocals = n; 717 } 718 } 719 // adds the instruction to the bytecode of the method 720 if (var < 4 && opcode != Opcodes.RET) { 721 int opt; 722 if (opcode < Opcodes.ISTORE) { 723 /* ILOAD_0 */ 724 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; 725 } else { 726 /* ISTORE_0 */ 727 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; 728 } 729 code.putByte(opt); 730 } else if (var >= 256) { 731 code.putByte(196 /* WIDE */).put12(opcode, var); 732 } else { 733 code.put11(opcode, var); 734 } 735 if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) { 736 visitLabel(new Label()); 737 } 738 } 739 visitTypeInsn(final int opcode, final String type)740 public void visitTypeInsn(final int opcode, final String type) { 741 Item i = cw.newClassItem(type); 742 // Label currentBlock = this.currentBlock; 743 if (currentBlock != null) { 744 if (compute == FRAMES) { 745 currentBlock.frame.execute(opcode, code.length, cw, i); 746 } else if (opcode == Opcodes.NEW) { 747 // updates current and max stack sizes only if opcode == NEW 748 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF) 749 int size = stackSize + 1; 750 if (size > maxStackSize) { 751 maxStackSize = size; 752 } 753 stackSize = size; 754 } 755 } 756 // adds the instruction to the bytecode of the method 757 code.put12(opcode, i.index); 758 } 759 visitFieldInsn( final int opcode, final String owner, final String name, final String desc)760 public void visitFieldInsn( 761 final int opcode, 762 final String owner, 763 final String name, 764 final String desc) 765 { 766 Item i = cw.newFieldItem(owner, name, desc); 767 // Label currentBlock = this.currentBlock; 768 if (currentBlock != null) { 769 if (compute == FRAMES) { 770 currentBlock.frame.execute(opcode, 0, cw, i); 771 } else { 772 int size; 773 // computes the stack size variation 774 char c = desc.charAt(0); 775 switch (opcode) { 776 case Opcodes.GETSTATIC: 777 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); 778 break; 779 case Opcodes.PUTSTATIC: 780 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); 781 break; 782 case Opcodes.GETFIELD: 783 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); 784 break; 785 // case Constants.PUTFIELD: 786 default: 787 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); 788 break; 789 } 790 // updates current and max stack sizes 791 if (size > maxStackSize) { 792 maxStackSize = size; 793 } 794 stackSize = size; 795 } 796 } 797 // adds the instruction to the bytecode of the method 798 code.put12(opcode, i.index); 799 } 800 visitMethodInsn( final int opcode, final String owner, final String name, final String desc)801 public void visitMethodInsn( 802 final int opcode, 803 final String owner, 804 final String name, 805 final String desc) 806 { 807 boolean itf = opcode == Opcodes.INVOKEINTERFACE; 808 Item i = cw.newMethodItem(owner, name, desc, itf); 809 int argSize = i.intVal; 810 // Label currentBlock = this.currentBlock; 811 if (currentBlock != null) { 812 if (compute == FRAMES) { 813 currentBlock.frame.execute(opcode, 0, cw, i); 814 } else { 815 /* 816 * computes the stack size variation. In order not to recompute 817 * several times this variation for the same Item, we use the 818 * intVal field of this item to store this variation, once it 819 * has been computed. More precisely this intVal field stores 820 * the sizes of the arguments and of the return value 821 * corresponding to desc. 822 */ 823 if (argSize == 0) { 824 // the above sizes have not been computed yet, 825 // so we compute them... 826 argSize = getArgumentsAndReturnSizes(desc); 827 // ... and we save them in order 828 // not to recompute them in the future 829 i.intVal = argSize; 830 } 831 int size; 832 if (opcode == Opcodes.INVOKESTATIC) { 833 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; 834 } else { 835 size = stackSize - (argSize >> 2) + (argSize & 0x03); 836 } 837 // updates current and max stack sizes 838 if (size > maxStackSize) { 839 maxStackSize = size; 840 } 841 stackSize = size; 842 } 843 } 844 // adds the instruction to the bytecode of the method 845 if (itf) { 846 if (argSize == 0) { 847 argSize = getArgumentsAndReturnSizes(desc); 848 i.intVal = argSize; 849 } 850 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); 851 } else { 852 code.put12(opcode, i.index); 853 } 854 } 855 visitJumpInsn(final int opcode, final Label label)856 public void visitJumpInsn(final int opcode, final Label label) { 857 Label nextInsn = null; 858 // Label currentBlock = this.currentBlock; 859 if (currentBlock != null) { 860 if (compute == FRAMES) { 861 currentBlock.frame.execute(opcode, 0, null, null); 862 // 'label' is the target of a jump instruction 863 label.getFirst().status |= Label.TARGET; 864 // adds 'label' as a successor of this basic block 865 addSuccessor(Edge.NORMAL, label); 866 if (opcode != Opcodes.GOTO) { 867 // creates a Label for the next basic block 868 nextInsn = new Label(); 869 } 870 } else { 871 if (opcode == Opcodes.JSR) { 872 if ((label.status & Label.SUBROUTINE) == 0) { 873 label.status |= Label.SUBROUTINE; 874 ++subroutines; 875 } 876 currentBlock.status |= Label.JSR; 877 addSuccessor(stackSize + 1, label); 878 // creates a Label for the next basic block 879 nextInsn = new Label(); 880 /* 881 * note that, by construction in this method, a JSR block 882 * has at least two successors in the control flow graph: 883 * the first one leads the next instruction after the JSR, 884 * while the second one leads to the JSR target. 885 */ 886 } else { 887 // updates current stack size (max stack size unchanged 888 // because stack size variation always negative in this 889 // case) 890 stackSize += Frame.SIZE[opcode]; 891 addSuccessor(stackSize, label); 892 } 893 } 894 } 895 // adds the instruction to the bytecode of the method 896 if ((label.status & Label.RESOLVED) != 0 897 && label.position - code.length < Short.MIN_VALUE) 898 { 899 /* 900 * case of a backward jump with an offset < -32768. In this case we 901 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx 902 * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the 903 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'> 904 * designates the instruction just after the GOTO_W. 905 */ 906 if (opcode == Opcodes.GOTO) { 907 code.putByte(200); // GOTO_W 908 } else if (opcode == Opcodes.JSR) { 909 code.putByte(201); // JSR_W 910 } else { 911 // if the IF instruction is transformed into IFNOT GOTO_W the 912 // next instruction becomes the target of the IFNOT instruction 913 if (nextInsn != null) { 914 nextInsn.status |= Label.TARGET; 915 } 916 code.putByte(opcode <= 166 917 ? ((opcode + 1) ^ 1) - 1 918 : opcode ^ 1); 919 code.putShort(8); // jump offset 920 code.putByte(200); // GOTO_W 921 } 922 label.put(this, code, code.length - 1, true); 923 } else { 924 /* 925 * case of a backward jump with an offset >= -32768, or of a forward 926 * jump with, of course, an unknown offset. In these cases we store 927 * the offset in 2 bytes (which will be increased in 928 * resizeInstructions, if needed). 929 */ 930 code.putByte(opcode); 931 label.put(this, code, code.length - 1, false); 932 } 933 if (currentBlock != null) { 934 if (nextInsn != null) { 935 // if the jump instruction is not a GOTO, the next instruction 936 // is also a successor of this instruction. Calling visitLabel 937 // adds the label of this next instruction as a successor of the 938 // current block, and starts a new basic block 939 visitLabel(nextInsn); 940 } 941 if (opcode == Opcodes.GOTO) { 942 noSuccessor(); 943 } 944 } 945 } 946 visitLabel(final Label label)947 public void visitLabel(final Label label) { 948 // resolves previous forward references to label, if any 949 resize |= label.resolve(this, code.length, code.data); 950 // updates currentBlock 951 if ((label.status & Label.DEBUG) != 0) { 952 return; 953 } 954 if (compute == FRAMES) { 955 if (currentBlock != null) { 956 if (label.position == currentBlock.position) { 957 // successive labels, do not start a new basic block 958 currentBlock.status |= (label.status & Label.TARGET); 959 label.frame = currentBlock.frame; 960 return; 961 } 962 // ends current block (with one new successor) 963 addSuccessor(Edge.NORMAL, label); 964 } 965 // begins a new current block 966 currentBlock = label; 967 if (label.frame == null) { 968 label.frame = new Frame(); 969 label.frame.owner = label; 970 } 971 // updates the basic block list 972 if (previousBlock != null) { 973 if (label.position == previousBlock.position) { 974 previousBlock.status |= (label.status & Label.TARGET); 975 label.frame = previousBlock.frame; 976 currentBlock = previousBlock; 977 return; 978 } 979 previousBlock.successor = label; 980 } 981 previousBlock = label; 982 } else if (compute == MAXS) { 983 if (currentBlock != null) { 984 // ends current block (with one new successor) 985 currentBlock.outputStackMax = maxStackSize; 986 addSuccessor(stackSize, label); 987 } 988 // begins a new current block 989 currentBlock = label; 990 // resets the relative current and max stack sizes 991 stackSize = 0; 992 maxStackSize = 0; 993 // updates the basic block list 994 if (previousBlock != null) { 995 previousBlock.successor = label; 996 } 997 previousBlock = label; 998 } 999 } 1000 visitLdcInsn(final Object cst)1001 public void visitLdcInsn(final Object cst) { 1002 Item i = cw.newConstItem(cst); 1003 // Label currentBlock = this.currentBlock; 1004 if (currentBlock != null) { 1005 if (compute == FRAMES) { 1006 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); 1007 } else { 1008 int size; 1009 // computes the stack size variation 1010 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) 1011 { 1012 size = stackSize + 2; 1013 } else { 1014 size = stackSize + 1; 1015 } 1016 // updates current and max stack sizes 1017 if (size > maxStackSize) { 1018 maxStackSize = size; 1019 } 1020 stackSize = size; 1021 } 1022 } 1023 // adds the instruction to the bytecode of the method 1024 int index = i.index; 1025 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { 1026 code.put12(20 /* LDC2_W */, index); 1027 } else if (index >= 256) { 1028 code.put12(19 /* LDC_W */, index); 1029 } else { 1030 code.put11(Opcodes.LDC, index); 1031 } 1032 } 1033 visitIincInsn(final int var, final int increment)1034 public void visitIincInsn(final int var, final int increment) { 1035 if (currentBlock != null) { 1036 if (compute == FRAMES) { 1037 currentBlock.frame.execute(Opcodes.IINC, var, null, null); 1038 } 1039 } 1040 if (compute != NOTHING) { 1041 // updates max locals 1042 int n = var + 1; 1043 if (n > maxLocals) { 1044 maxLocals = n; 1045 } 1046 } 1047 // adds the instruction to the bytecode of the method 1048 if ((var > 255) || (increment > 127) || (increment < -128)) { 1049 code.putByte(196 /* WIDE */) 1050 .put12(Opcodes.IINC, var) 1051 .putShort(increment); 1052 } else { 1053 code.putByte(Opcodes.IINC).put11(var, increment); 1054 } 1055 } 1056 visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels)1057 public void visitTableSwitchInsn( 1058 final int min, 1059 final int max, 1060 final Label dflt, 1061 final Label[] labels) 1062 { 1063 // adds the instruction to the bytecode of the method 1064 int source = code.length; 1065 code.putByte(Opcodes.TABLESWITCH); 1066 code.length += (4 - code.length % 4) % 4; 1067 dflt.put(this, code, source, true); 1068 code.putInt(min).putInt(max); 1069 for (int i = 0; i < labels.length; ++i) { 1070 labels[i].put(this, code, source, true); 1071 } 1072 // updates currentBlock 1073 visitSwitchInsn(dflt, labels); 1074 } 1075 visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels)1076 public void visitLookupSwitchInsn( 1077 final Label dflt, 1078 final int[] keys, 1079 final Label[] labels) 1080 { 1081 // adds the instruction to the bytecode of the method 1082 int source = code.length; 1083 code.putByte(Opcodes.LOOKUPSWITCH); 1084 code.length += (4 - code.length % 4) % 4; 1085 dflt.put(this, code, source, true); 1086 code.putInt(labels.length); 1087 for (int i = 0; i < labels.length; ++i) { 1088 code.putInt(keys[i]); 1089 labels[i].put(this, code, source, true); 1090 } 1091 // updates currentBlock 1092 visitSwitchInsn(dflt, labels); 1093 } 1094 visitSwitchInsn(final Label dflt, final Label[] labels)1095 private void visitSwitchInsn(final Label dflt, final Label[] labels) { 1096 // Label currentBlock = this.currentBlock; 1097 if (currentBlock != null) { 1098 if (compute == FRAMES) { 1099 currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); 1100 // adds current block successors 1101 addSuccessor(Edge.NORMAL, dflt); 1102 dflt.getFirst().status |= Label.TARGET; 1103 for (int i = 0; i < labels.length; ++i) { 1104 addSuccessor(Edge.NORMAL, labels[i]); 1105 labels[i].getFirst().status |= Label.TARGET; 1106 } 1107 } else { 1108 // updates current stack size (max stack size unchanged) 1109 --stackSize; 1110 // adds current block successors 1111 addSuccessor(stackSize, dflt); 1112 for (int i = 0; i < labels.length; ++i) { 1113 addSuccessor(stackSize, labels[i]); 1114 } 1115 } 1116 // ends current block 1117 noSuccessor(); 1118 } 1119 } 1120 visitMultiANewArrayInsn(final String desc, final int dims)1121 public void visitMultiANewArrayInsn(final String desc, final int dims) { 1122 Item i = cw.newClassItem(desc); 1123 // Label currentBlock = this.currentBlock; 1124 if (currentBlock != null) { 1125 if (compute == FRAMES) { 1126 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); 1127 } else { 1128 // updates current stack size (max stack size unchanged because 1129 // stack size variation always negative or null) 1130 stackSize += 1 - dims; 1131 } 1132 } 1133 // adds the instruction to the bytecode of the method 1134 code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims); 1135 } 1136 visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type)1137 public void visitTryCatchBlock( 1138 final Label start, 1139 final Label end, 1140 final Label handler, 1141 final String type) 1142 { 1143 ++handlerCount; 1144 Handler h = new Handler(); 1145 h.start = start; 1146 h.end = end; 1147 h.handler = handler; 1148 h.desc = type; 1149 h.type = type != null ? cw.newClass(type) : 0; 1150 if (lastHandler == null) { 1151 firstHandler = h; 1152 } else { 1153 lastHandler.next = h; 1154 } 1155 lastHandler = h; 1156 } 1157 visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index)1158 public void visitLocalVariable( 1159 final String name, 1160 final String desc, 1161 final String signature, 1162 final Label start, 1163 final Label end, 1164 final int index) 1165 { 1166 if (signature != null) { 1167 if (localVarType == null) { 1168 localVarType = new ByteVector(); 1169 } 1170 ++localVarTypeCount; 1171 localVarType.putShort(start.position) 1172 .putShort(end.position - start.position) 1173 .putShort(cw.newUTF8(name)) 1174 .putShort(cw.newUTF8(signature)) 1175 .putShort(index); 1176 } 1177 if (localVar == null) { 1178 localVar = new ByteVector(); 1179 } 1180 ++localVarCount; 1181 localVar.putShort(start.position) 1182 .putShort(end.position - start.position) 1183 .putShort(cw.newUTF8(name)) 1184 .putShort(cw.newUTF8(desc)) 1185 .putShort(index); 1186 if (compute != NOTHING) { 1187 // updates max locals 1188 char c = desc.charAt(0); 1189 int n = index + (c == 'J' || c == 'D' ? 2 : 1); 1190 if (n > maxLocals) { 1191 maxLocals = n; 1192 } 1193 } 1194 } 1195 visitLineNumber(final int line, final Label start)1196 public void visitLineNumber(final int line, final Label start) { 1197 if (lineNumber == null) { 1198 lineNumber = new ByteVector(); 1199 } 1200 ++lineNumberCount; 1201 lineNumber.putShort(start.position); 1202 lineNumber.putShort(line); 1203 } 1204 visitMaxs(final int maxStack, final int maxLocals)1205 public void visitMaxs(final int maxStack, final int maxLocals) { 1206 if (ClassReader.FRAMES && compute == FRAMES) { 1207 // completes the control flow graph with exception handler blocks 1208 Handler handler = firstHandler; 1209 while (handler != null) { 1210 Label l = handler.start.getFirst(); 1211 Label h = handler.handler.getFirst(); 1212 Label e = handler.end.getFirst(); 1213 // computes the kind of the edges to 'h' 1214 String t = handler.desc == null 1215 ? "java/lang/Throwable" 1216 : handler.desc; 1217 int kind = Frame.OBJECT | cw.addType(t); 1218 // h is an exception handler 1219 h.status |= Label.TARGET; 1220 // adds 'h' as a successor of labels between 'start' and 'end' 1221 while (l != e) { 1222 // creates an edge to 'h' 1223 Edge b = new Edge(); 1224 b.info = kind; 1225 b.successor = h; 1226 // adds it to the successors of 'l' 1227 b.next = l.successors; 1228 l.successors = b; 1229 // goes to the next label 1230 l = l.successor; 1231 } 1232 handler = handler.next; 1233 } 1234 1235 // creates and visits the first (implicit) frame 1236 Frame f = labels.frame; 1237 Type[] args = Type.getArgumentTypes(descriptor); 1238 f.initInputFrame(cw, access, args, this.maxLocals); 1239 visitFrame(f); 1240 1241 /* 1242 * fix point algorithm: mark the first basic block as 'changed' 1243 * (i.e. put it in the 'changed' list) and, while there are changed 1244 * basic blocks, choose one, mark it as unchanged, and update its 1245 * successors (which can be changed in the process). 1246 */ 1247 int max = 0; 1248 Label changed = labels; 1249 while (changed != null) { 1250 // removes a basic block from the list of changed basic blocks 1251 Label l = changed; 1252 changed = changed.next; 1253 l.next = null; 1254 f = l.frame; 1255 // a reacheable jump target must be stored in the stack map 1256 if ((l.status & Label.TARGET) != 0) { 1257 l.status |= Label.STORE; 1258 } 1259 // all visited labels are reacheable, by definition 1260 l.status |= Label.REACHABLE; 1261 // updates the (absolute) maximum stack size 1262 int blockMax = f.inputStack.length + l.outputStackMax; 1263 if (blockMax > max) { 1264 max = blockMax; 1265 } 1266 // updates the successors of the current basic block 1267 Edge e = l.successors; 1268 while (e != null) { 1269 Label n = e.successor.getFirst(); 1270 boolean change = f.merge(cw, n.frame, e.info); 1271 if (change && n.next == null) { 1272 // if n has changed and is not already in the 'changed' 1273 // list, adds it to this list 1274 n.next = changed; 1275 changed = n; 1276 } 1277 e = e.next; 1278 } 1279 } 1280 this.maxStack = max; 1281 1282 // visits all the frames that must be stored in the stack map 1283 Label l = labels; 1284 while (l != null) { 1285 f = l.frame; 1286 if ((l.status & Label.STORE) != 0) { 1287 visitFrame(f); 1288 } 1289 if ((l.status & Label.REACHABLE) == 0) { 1290 // finds start and end of dead basic block 1291 Label k = l.successor; 1292 int start = l.position; 1293 int end = (k == null ? code.length : k.position) - 1; 1294 // if non empty basic block 1295 if (end >= start) { 1296 // replaces instructions with NOP ... NOP ATHROW 1297 for (int i = start; i < end; ++i) { 1298 code.data[i] = Opcodes.NOP; 1299 } 1300 code.data[end] = (byte) Opcodes.ATHROW; 1301 // emits a frame for this unreachable block 1302 startFrame(start, 0, 1); 1303 frame[frameIndex++] = Frame.OBJECT 1304 | cw.addType("java/lang/Throwable"); 1305 endFrame(); 1306 } 1307 } 1308 l = l.successor; 1309 } 1310 } else if (compute == MAXS) { 1311 // completes the control flow graph with exception handler blocks 1312 Handler handler = firstHandler; 1313 while (handler != null) { 1314 Label l = handler.start; 1315 Label h = handler.handler; 1316 Label e = handler.end; 1317 // adds 'h' as a successor of labels between 'start' and 'end' 1318 while (l != e) { 1319 // creates an edge to 'h' 1320 Edge b = new Edge(); 1321 b.info = Edge.EXCEPTION; 1322 b.successor = h; 1323 // adds it to the successors of 'l' 1324 if ((l.status & Label.JSR) == 0) { 1325 b.next = l.successors; 1326 l.successors = b; 1327 } else { 1328 // if l is a JSR block, adds b after the first two edges 1329 // to preserve the hypothesis about JSR block successors 1330 // order (see {@link #visitJumpInsn}) 1331 b.next = l.successors.next.next; 1332 l.successors.next.next = b; 1333 } 1334 // goes to the next label 1335 l = l.successor; 1336 } 1337 handler = handler.next; 1338 } 1339 1340 if (subroutines > 0) { 1341 // completes the control flow graph with the RET successors 1342 /* 1343 * first step: finds the subroutines. This step determines, for 1344 * each basic block, to which subroutine(s) it belongs. 1345 */ 1346 // finds the basic blocks that belong to the "main" subroutine 1347 int id = 0; 1348 labels.visitSubroutine(null, 1, subroutines); 1349 // finds the basic blocks that belong to the real subroutines 1350 Label l = labels; 1351 while (l != null) { 1352 if ((l.status & Label.JSR) != 0) { 1353 // the subroutine is defined by l's TARGET, not by l 1354 Label subroutine = l.successors.next.successor; 1355 // if this subroutine has not been visited yet... 1356 if ((subroutine.status & Label.VISITED) == 0) { 1357 // ...assigns it a new id and finds its basic blocks 1358 id += 1; 1359 subroutine.visitSubroutine(null, (id / 32L) << 32 1360 | (1L << (id % 32)), subroutines); 1361 } 1362 } 1363 l = l.successor; 1364 } 1365 // second step: finds the successors of RET blocks 1366 l = labels; 1367 while (l != null) { 1368 if ((l.status & Label.JSR) != 0) { 1369 Label L = labels; 1370 while (L != null) { 1371 L.status &= ~Label.VISITED; 1372 L = L.successor; 1373 } 1374 // the subroutine is defined by l's TARGET, not by l 1375 Label subroutine = l.successors.next.successor; 1376 subroutine.visitSubroutine(l, 0, subroutines); 1377 } 1378 l = l.successor; 1379 } 1380 } 1381 1382 /* 1383 * control flow analysis algorithm: while the block stack is not 1384 * empty, pop a block from this stack, update the max stack size, 1385 * compute the true (non relative) begin stack size of the 1386 * successors of this block, and push these successors onto the 1387 * stack (unless they have already been pushed onto the stack). 1388 * Note: by hypothesis, the {@link Label#inputStackTop} of the 1389 * blocks in the block stack are the true (non relative) beginning 1390 * stack sizes of these blocks. 1391 */ 1392 int max = 0; 1393 Label stack = labels; 1394 while (stack != null) { 1395 // pops a block from the stack 1396 Label l = stack; 1397 stack = stack.next; 1398 // computes the true (non relative) max stack size of this block 1399 int start = l.inputStackTop; 1400 int blockMax = start + l.outputStackMax; 1401 // updates the global max stack size 1402 if (blockMax > max) { 1403 max = blockMax; 1404 } 1405 // analyzes the successors of the block 1406 Edge b = l.successors; 1407 if ((l.status & Label.JSR) != 0) { 1408 // ignores the first edge of JSR blocks (virtual successor) 1409 b = b.next; 1410 } 1411 while (b != null) { 1412 l = b.successor; 1413 // if this successor has not already been pushed... 1414 if ((l.status & Label.PUSHED) == 0) { 1415 // computes its true beginning stack size... 1416 l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start 1417 + b.info; 1418 // ...and pushes it onto the stack 1419 l.status |= Label.PUSHED; 1420 l.next = stack; 1421 stack = l; 1422 } 1423 b = b.next; 1424 } 1425 } 1426 this.maxStack = max; 1427 } else { 1428 this.maxStack = maxStack; 1429 this.maxLocals = maxLocals; 1430 } 1431 } 1432 visitEnd()1433 public void visitEnd() { 1434 } 1435 1436 // ------------------------------------------------------------------------ 1437 // Utility methods: control flow analysis algorithm 1438 // ------------------------------------------------------------------------ 1439 1440 /** 1441 * Computes the size of the arguments and of the return value of a method. 1442 * 1443 * @param desc the descriptor of a method. 1444 * @return the size of the arguments of the method (plus one for the 1445 * implicit this argument), argSize, and the size of its return 1446 * value, retSize, packed into a single int i = 1447 * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal 1448 * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>). 1449 */ getArgumentsAndReturnSizes(final String desc)1450 static int getArgumentsAndReturnSizes(final String desc) { 1451 int n = 1; 1452 int c = 1; 1453 while (true) { 1454 char car = desc.charAt(c++); 1455 if (car == ')') { 1456 car = desc.charAt(c); 1457 return n << 2 1458 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); 1459 } else if (car == 'L') { 1460 while (desc.charAt(c++) != ';') { 1461 } 1462 n += 1; 1463 } else if (car == '[') { 1464 while ((car = desc.charAt(c)) == '[') { 1465 ++c; 1466 } 1467 if (car == 'D' || car == 'J') { 1468 n -= 1; 1469 } 1470 } else if (car == 'D' || car == 'J') { 1471 n += 2; 1472 } else { 1473 n += 1; 1474 } 1475 } 1476 } 1477 1478 /** 1479 * Adds a successor to the {@link #currentBlock currentBlock} block. 1480 * 1481 * @param info information about the control flow edge to be added. 1482 * @param successor the successor block to be added to the current block. 1483 */ addSuccessor(final int info, final Label successor)1484 private void addSuccessor(final int info, final Label successor) { 1485 // creates and initializes an Edge object... 1486 Edge b = new Edge(); 1487 b.info = info; 1488 b.successor = successor; 1489 // ...and adds it to the successor list of the currentBlock block 1490 b.next = currentBlock.successors; 1491 currentBlock.successors = b; 1492 } 1493 1494 /** 1495 * Ends the current basic block. This method must be used in the case where 1496 * the current basic block does not have any successor. 1497 */ noSuccessor()1498 private void noSuccessor() { 1499 if (compute == FRAMES) { 1500 Label l = new Label(); 1501 l.frame = new Frame(); 1502 l.frame.owner = l; 1503 l.resolve(this, code.length, code.data); 1504 previousBlock.successor = l; 1505 previousBlock = l; 1506 } else { 1507 currentBlock.outputStackMax = maxStackSize; 1508 } 1509 currentBlock = null; 1510 } 1511 1512 // ------------------------------------------------------------------------ 1513 // Utility methods: stack map frames 1514 // ------------------------------------------------------------------------ 1515 1516 /** 1517 * Visits a frame that has been computed from scratch. 1518 * 1519 * @param f the frame that must be visited. 1520 */ visitFrame(final Frame f)1521 private void visitFrame(final Frame f) { 1522 int i, t; 1523 int nTop = 0; 1524 int nLocal = 0; 1525 int nStack = 0; 1526 int[] locals = f.inputLocals; 1527 int[] stacks = f.inputStack; 1528 // computes the number of locals (ignores TOP types that are just after 1529 // a LONG or a DOUBLE, and all trailing TOP types) 1530 for (i = 0; i < locals.length; ++i) { 1531 t = locals[i]; 1532 if (t == Frame.TOP) { 1533 ++nTop; 1534 } else { 1535 nLocal += nTop + 1; 1536 nTop = 0; 1537 } 1538 if (t == Frame.LONG || t == Frame.DOUBLE) { 1539 ++i; 1540 } 1541 } 1542 // computes the stack size (ignores TOP types that are just after 1543 // a LONG or a DOUBLE) 1544 for (i = 0; i < stacks.length; ++i) { 1545 t = stacks[i]; 1546 ++nStack; 1547 if (t == Frame.LONG || t == Frame.DOUBLE) { 1548 ++i; 1549 } 1550 } 1551 // visits the frame and its content 1552 startFrame(f.owner.position, nLocal, nStack); 1553 for (i = 0; nLocal > 0; ++i, --nLocal) { 1554 t = locals[i]; 1555 frame[frameIndex++] = t; 1556 if (t == Frame.LONG || t == Frame.DOUBLE) { 1557 ++i; 1558 } 1559 } 1560 for (i = 0; i < stacks.length; ++i) { 1561 t = stacks[i]; 1562 frame[frameIndex++] = t; 1563 if (t == Frame.LONG || t == Frame.DOUBLE) { 1564 ++i; 1565 } 1566 } 1567 endFrame(); 1568 } 1569 1570 /** 1571 * Starts the visit of a stack map frame. 1572 * 1573 * @param offset the offset of the instruction to which the frame 1574 * corresponds. 1575 * @param nLocal the number of local variables in the frame. 1576 * @param nStack the number of stack elements in the frame. 1577 */ startFrame(final int offset, final int nLocal, final int nStack)1578 private void startFrame(final int offset, final int nLocal, final int nStack) 1579 { 1580 int n = 3 + nLocal + nStack; 1581 if (frame == null || frame.length < n) { 1582 frame = new int[n]; 1583 } 1584 frame[0] = offset; 1585 frame[1] = nLocal; 1586 frame[2] = nStack; 1587 frameIndex = 3; 1588 } 1589 1590 /** 1591 * Checks if the visit of the current frame {@link #frame} is finished, and 1592 * if yes, write it in the StackMapTable attribute. 1593 */ endFrame()1594 private void endFrame() { 1595 if (previousFrame != null) { // do not write the first frame 1596 if (stackMap == null) { 1597 stackMap = new ByteVector(); 1598 } 1599 writeFrame(); 1600 ++frameCount; 1601 } 1602 previousFrame = frame; 1603 frame = null; 1604 } 1605 1606 /** 1607 * Compress and writes the current frame {@link #frame} in the StackMapTable 1608 * attribute. 1609 */ writeFrame()1610 private void writeFrame() { 1611 int clocalsSize = frame[1]; 1612 int cstackSize = frame[2]; 1613 if ((cw.version & 0xFFFF) < Opcodes.V1_6) { 1614 stackMap.putShort(frame[0]).putShort(clocalsSize); 1615 writeFrameTypes(3, 3 + clocalsSize); 1616 stackMap.putShort(cstackSize); 1617 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); 1618 return; 1619 } 1620 int localsSize = previousFrame[1]; 1621 int type = FULL_FRAME; 1622 int k = 0; 1623 int delta; 1624 if (frameCount == 0) { 1625 delta = frame[0]; 1626 } else { 1627 delta = frame[0] - previousFrame[0] - 1; 1628 } 1629 if (cstackSize == 0) { 1630 k = clocalsSize - localsSize; 1631 switch (k) { 1632 case -3: 1633 case -2: 1634 case -1: 1635 type = CHOP_FRAME; 1636 localsSize = clocalsSize; 1637 break; 1638 case 0: 1639 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; 1640 break; 1641 case 1: 1642 case 2: 1643 case 3: 1644 type = APPEND_FRAME; 1645 break; 1646 } 1647 } else if (clocalsSize == localsSize && cstackSize == 1) { 1648 type = delta < 63 1649 ? SAME_LOCALS_1_STACK_ITEM_FRAME 1650 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 1651 } 1652 if (type != FULL_FRAME) { 1653 // verify if locals are the same 1654 int l = 3; 1655 for (int j = 0; j < localsSize; j++) { 1656 if (frame[l] != previousFrame[l]) { 1657 type = FULL_FRAME; 1658 break; 1659 } 1660 l++; 1661 } 1662 } 1663 switch (type) { 1664 case SAME_FRAME: 1665 stackMap.putByte(delta); 1666 break; 1667 case SAME_LOCALS_1_STACK_ITEM_FRAME: 1668 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); 1669 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); 1670 break; 1671 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: 1672 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) 1673 .putShort(delta); 1674 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); 1675 break; 1676 case SAME_FRAME_EXTENDED: 1677 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); 1678 break; 1679 case CHOP_FRAME: 1680 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); 1681 break; 1682 case APPEND_FRAME: 1683 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); 1684 writeFrameTypes(3 + localsSize, 3 + clocalsSize); 1685 break; 1686 // case FULL_FRAME: 1687 default: 1688 stackMap.putByte(FULL_FRAME) 1689 .putShort(delta) 1690 .putShort(clocalsSize); 1691 writeFrameTypes(3, 3 + clocalsSize); 1692 stackMap.putShort(cstackSize); 1693 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); 1694 } 1695 } 1696 1697 /** 1698 * Writes some types of the current frame {@link #frame} into the 1699 * StackMapTableAttribute. This method converts types from the format used 1700 * in {@link Label} to the format used in StackMapTable attributes. In 1701 * particular, it converts type table indexes to constant pool indexes. 1702 * 1703 * @param start index of the first type in {@link #frame} to write. 1704 * @param end index of last type in {@link #frame} to write (exclusive). 1705 */ 1706 private void writeFrameTypes(final int start, final int end) { 1707 for (int i = start; i < end; ++i) { 1708 int t = frame[i]; 1709 int d = t & Frame.DIM; 1710 if (d == 0) { 1711 int v = t & Frame.BASE_VALUE; 1712 switch (t & Frame.BASE_KIND) { 1713 case Frame.OBJECT: 1714 stackMap.putByte(7) 1715 .putShort(cw.newClass(cw.typeTable[v].strVal1)); 1716 break; 1717 case Frame.UNINITIALIZED: 1718 stackMap.putByte(8).putShort(cw.typeTable[v].intVal); 1719 break; 1720 default: 1721 stackMap.putByte(v); 1722 } 1723 } else { 1724 StringBuffer buf = new StringBuffer(); 1725 d >>= 28; 1726 while (d-- > 0) { 1727 buf.append('['); 1728 } 1729 if ((t & Frame.BASE_KIND) == Frame.OBJECT) { 1730 buf.append('L'); 1731 buf.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); 1732 buf.append(';'); 1733 } else { 1734 switch (t & 0xF) { 1735 case 1: 1736 buf.append('I'); 1737 break; 1738 case 2: 1739 buf.append('F'); 1740 break; 1741 case 3: 1742 buf.append('D'); 1743 break; 1744 case 9: 1745 buf.append('Z'); 1746 break; 1747 case 10: 1748 buf.append('B'); 1749 break; 1750 case 11: 1751 buf.append('C'); 1752 break; 1753 case 12: 1754 buf.append('S'); 1755 break; 1756 default: 1757 buf.append('J'); 1758 } 1759 } 1760 stackMap.putByte(7).putShort(cw.newClass(buf.toString())); 1761 } 1762 } 1763 } 1764 1765 private void writeFrameType(final Object type) { 1766 if (type instanceof String) { 1767 stackMap.putByte(7).putShort(cw.newClass((String) type)); 1768 } else if (type instanceof Integer) { 1769 stackMap.putByte(((Integer) type).intValue()); 1770 } else { 1771 stackMap.putByte(8).putShort(((Label) type).position); 1772 } 1773 } 1774 1775 // ------------------------------------------------------------------------ 1776 // Utility methods: dump bytecode array 1777 // ------------------------------------------------------------------------ 1778 1779 /** 1780 * Returns the size of the bytecode of this method. 1781 * 1782 * @return the size of the bytecode of this method. 1783 */ 1784 final int getSize() { 1785 if (classReaderOffset != 0) { 1786 return 6 + classReaderLength; 1787 } 1788 if (resize) { 1789 // replaces the temporary jump opcodes introduced by Label.resolve. 1790 if (ClassReader.RESIZE) { 1791 resizeInstructions(); 1792 } else { 1793 throw new RuntimeException("Method code too large!"); 1794 } 1795 } 1796 int size = 8; 1797 if (code.length > 0) { 1798 cw.newUTF8("Code"); 1799 size += 18 + code.length + 8 * handlerCount; 1800 if (localVar != null) { 1801 cw.newUTF8("LocalVariableTable"); 1802 size += 8 + localVar.length; 1803 } 1804 if (localVarType != null) { 1805 cw.newUTF8("LocalVariableTypeTable"); 1806 size += 8 + localVarType.length; 1807 } 1808 if (lineNumber != null) { 1809 cw.newUTF8("LineNumberTable"); 1810 size += 8 + lineNumber.length; 1811 } 1812 if (stackMap != null) { 1813 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; 1814 cw.newUTF8(zip ? "StackMapTable" : "StackMap"); 1815 size += 8 + stackMap.length; 1816 } 1817 if (cattrs != null) { 1818 size += cattrs.getSize(cw, 1819 code.data, 1820 code.length, 1821 maxStack, 1822 maxLocals); 1823 } 1824 } 1825 if (exceptionCount > 0) { 1826 cw.newUTF8("Exceptions"); 1827 size += 8 + 2 * exceptionCount; 1828 } 1829 if ((access & Opcodes.ACC_SYNTHETIC) != 0 1830 && (cw.version & 0xffff) < Opcodes.V1_5) 1831 { 1832 cw.newUTF8("Synthetic"); 1833 size += 6; 1834 } 1835 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 1836 cw.newUTF8("Deprecated"); 1837 size += 6; 1838 } 1839 if (ClassReader.SIGNATURES && signature != null) { 1840 cw.newUTF8("Signature"); 1841 cw.newUTF8(signature); 1842 size += 8; 1843 } 1844 if (ClassReader.ANNOTATIONS && annd != null) { 1845 cw.newUTF8("AnnotationDefault"); 1846 size += 6 + annd.length; 1847 } 1848 if (ClassReader.ANNOTATIONS && anns != null) { 1849 cw.newUTF8("RuntimeVisibleAnnotations"); 1850 size += 8 + anns.getSize(); 1851 } 1852 if (ClassReader.ANNOTATIONS && ianns != null) { 1853 cw.newUTF8("RuntimeInvisibleAnnotations"); 1854 size += 8 + ianns.getSize(); 1855 } 1856 if (ClassReader.ANNOTATIONS && panns != null) { 1857 cw.newUTF8("RuntimeVisibleParameterAnnotations"); 1858 size += 7 + 2 * (panns.length - synthetics); 1859 for (int i = panns.length - 1; i >= synthetics; --i) { 1860 size += panns[i] == null ? 0 : panns[i].getSize(); 1861 } 1862 } 1863 if (ClassReader.ANNOTATIONS && ipanns != null) { 1864 cw.newUTF8("RuntimeInvisibleParameterAnnotations"); 1865 size += 7 + 2 * (ipanns.length - synthetics); 1866 for (int i = ipanns.length - 1; i >= synthetics; --i) { 1867 size += ipanns[i] == null ? 0 : ipanns[i].getSize(); 1868 } 1869 } 1870 if (attrs != null) { 1871 size += attrs.getSize(cw, null, 0, -1, -1); 1872 } 1873 return size; 1874 } 1875 1876 /** 1877 * Puts the bytecode of this method in the given byte vector. 1878 * 1879 * @param out the byte vector into which the bytecode of this method must be 1880 * copied. 1881 */ put(final ByteVector out)1882 final void put(final ByteVector out) { 1883 out.putShort(access).putShort(name).putShort(desc); 1884 if (classReaderOffset != 0) { 1885 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); 1886 return; 1887 } 1888 int attributeCount = 0; 1889 if (code.length > 0) { 1890 ++attributeCount; 1891 } 1892 if (exceptionCount > 0) { 1893 ++attributeCount; 1894 } 1895 if ((access & Opcodes.ACC_SYNTHETIC) != 0 1896 && (cw.version & 0xffff) < Opcodes.V1_5) 1897 { 1898 ++attributeCount; 1899 } 1900 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 1901 ++attributeCount; 1902 } 1903 if (ClassReader.SIGNATURES && signature != null) { 1904 ++attributeCount; 1905 } 1906 if (ClassReader.ANNOTATIONS && annd != null) { 1907 ++attributeCount; 1908 } 1909 if (ClassReader.ANNOTATIONS && anns != null) { 1910 ++attributeCount; 1911 } 1912 if (ClassReader.ANNOTATIONS && ianns != null) { 1913 ++attributeCount; 1914 } 1915 if (ClassReader.ANNOTATIONS && panns != null) { 1916 ++attributeCount; 1917 } 1918 if (ClassReader.ANNOTATIONS && ipanns != null) { 1919 ++attributeCount; 1920 } 1921 if (attrs != null) { 1922 attributeCount += attrs.getCount(); 1923 } 1924 out.putShort(attributeCount); 1925 if (code.length > 0) { 1926 int size = 12 + code.length + 8 * handlerCount; 1927 if (localVar != null) { 1928 size += 8 + localVar.length; 1929 } 1930 if (localVarType != null) { 1931 size += 8 + localVarType.length; 1932 } 1933 if (lineNumber != null) { 1934 size += 8 + lineNumber.length; 1935 } 1936 if (stackMap != null) { 1937 size += 8 + stackMap.length; 1938 } 1939 if (cattrs != null) { 1940 size += cattrs.getSize(cw, 1941 code.data, 1942 code.length, 1943 maxStack, 1944 maxLocals); 1945 } 1946 out.putShort(cw.newUTF8("Code")).putInt(size); 1947 out.putShort(maxStack).putShort(maxLocals); 1948 out.putInt(code.length).putByteArray(code.data, 0, code.length); 1949 out.putShort(handlerCount); 1950 if (handlerCount > 0) { 1951 Handler h = firstHandler; 1952 while (h != null) { 1953 out.putShort(h.start.position) 1954 .putShort(h.end.position) 1955 .putShort(h.handler.position) 1956 .putShort(h.type); 1957 h = h.next; 1958 } 1959 } 1960 attributeCount = 0; 1961 if (localVar != null) { 1962 ++attributeCount; 1963 } 1964 if (localVarType != null) { 1965 ++attributeCount; 1966 } 1967 if (lineNumber != null) { 1968 ++attributeCount; 1969 } 1970 if (stackMap != null) { 1971 ++attributeCount; 1972 } 1973 if (cattrs != null) { 1974 attributeCount += cattrs.getCount(); 1975 } 1976 out.putShort(attributeCount); 1977 if (localVar != null) { 1978 out.putShort(cw.newUTF8("LocalVariableTable")); 1979 out.putInt(localVar.length + 2).putShort(localVarCount); 1980 out.putByteArray(localVar.data, 0, localVar.length); 1981 } 1982 if (localVarType != null) { 1983 out.putShort(cw.newUTF8("LocalVariableTypeTable")); 1984 out.putInt(localVarType.length + 2).putShort(localVarTypeCount); 1985 out.putByteArray(localVarType.data, 0, localVarType.length); 1986 } 1987 if (lineNumber != null) { 1988 out.putShort(cw.newUTF8("LineNumberTable")); 1989 out.putInt(lineNumber.length + 2).putShort(lineNumberCount); 1990 out.putByteArray(lineNumber.data, 0, lineNumber.length); 1991 } 1992 if (stackMap != null) { 1993 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; 1994 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); 1995 out.putInt(stackMap.length + 2).putShort(frameCount); 1996 out.putByteArray(stackMap.data, 0, stackMap.length); 1997 } 1998 if (cattrs != null) { 1999 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); 2000 } 2001 } 2002 if (exceptionCount > 0) { 2003 out.putShort(cw.newUTF8("Exceptions")) 2004 .putInt(2 * exceptionCount + 2); 2005 out.putShort(exceptionCount); 2006 for (int i = 0; i < exceptionCount; ++i) { 2007 out.putShort(exceptions[i]); 2008 } 2009 } 2010 if ((access & Opcodes.ACC_SYNTHETIC) != 0 2011 && (cw.version & 0xffff) < Opcodes.V1_5) 2012 { 2013 out.putShort(cw.newUTF8("Synthetic")).putInt(0); 2014 } 2015 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 2016 out.putShort(cw.newUTF8("Deprecated")).putInt(0); 2017 } 2018 if (ClassReader.SIGNATURES && signature != null) { 2019 out.putShort(cw.newUTF8("Signature")) 2020 .putInt(2) 2021 .putShort(cw.newUTF8(signature)); 2022 } 2023 if (ClassReader.ANNOTATIONS && annd != null) { 2024 out.putShort(cw.newUTF8("AnnotationDefault")); 2025 out.putInt(annd.length); 2026 out.putByteArray(annd.data, 0, annd.length); 2027 } 2028 if (ClassReader.ANNOTATIONS && anns != null) { 2029 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); 2030 anns.put(out); 2031 } 2032 if (ClassReader.ANNOTATIONS && ianns != null) { 2033 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); 2034 ianns.put(out); 2035 } 2036 if (ClassReader.ANNOTATIONS && panns != null) { 2037 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); 2038 AnnotationWriter.put(panns, synthetics, out); 2039 } 2040 if (ClassReader.ANNOTATIONS && ipanns != null) { 2041 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); 2042 AnnotationWriter.put(ipanns, synthetics, out); 2043 } 2044 if (attrs != null) { 2045 attrs.put(cw, null, 0, -1, -1, out); 2046 } 2047 } 2048 2049 // ------------------------------------------------------------------------ 2050 // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W) 2051 // ------------------------------------------------------------------------ 2052 2053 /** 2054 * Resizes and replaces the temporary instructions inserted by 2055 * {@link Label#resolve} for wide forward jumps, while keeping jump offsets 2056 * and instruction addresses consistent. This may require to resize other 2057 * existing instructions, or even to introduce new instructions: for 2058 * example, increasing the size of an instruction by 2 at the middle of a 2059 * method can increases the offset of an IFEQ instruction from 32766 to 2060 * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W 2061 * 32765. This, in turn, may require to increase the size of another jump 2062 * instruction, and so on... All these operations are handled automatically 2063 * by this method. <p> <i>This method must be called after all the method 2064 * that is being built has been visited</i>. In particular, the 2065 * {@link Label Label} objects used to construct the method are no longer 2066 * valid after this method has been called. 2067 */ resizeInstructions()2068 private void resizeInstructions() { 2069 byte[] b = code.data; // bytecode of the method 2070 int u, v, label; // indexes in b 2071 int i, j; // loop indexes 2072 /* 2073 * 1st step: As explained above, resizing an instruction may require to 2074 * resize another one, which may require to resize yet another one, and 2075 * so on. The first step of the algorithm consists in finding all the 2076 * instructions that need to be resized, without modifying the code. 2077 * This is done by the following "fix point" algorithm: 2078 * 2079 * Parse the code to find the jump instructions whose offset will need 2080 * more than 2 bytes to be stored (the future offset is computed from 2081 * the current offset and from the number of bytes that will be inserted 2082 * or removed between the source and target instructions). For each such 2083 * instruction, adds an entry in (a copy of) the indexes and sizes 2084 * arrays (if this has not already been done in a previous iteration!). 2085 * 2086 * If at least one entry has been added during the previous step, go 2087 * back to the beginning, otherwise stop. 2088 * 2089 * In fact the real algorithm is complicated by the fact that the size 2090 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their 2091 * position in the bytecode (because of padding). In order to ensure the 2092 * convergence of the algorithm, the number of bytes to be added or 2093 * removed from these instructions is over estimated during the previous 2094 * loop, and computed exactly only after the loop is finished (this 2095 * requires another pass to parse the bytecode of the method). 2096 */ 2097 int[] allIndexes = new int[0]; // copy of indexes 2098 int[] allSizes = new int[0]; // copy of sizes 2099 boolean[] resize; // instructions to be resized 2100 int newOffset; // future offset of a jump instruction 2101 2102 resize = new boolean[code.length]; 2103 2104 // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done 2105 int state = 3; 2106 do { 2107 if (state == 3) { 2108 state = 2; 2109 } 2110 u = 0; 2111 while (u < b.length) { 2112 int opcode = b[u] & 0xFF; // opcode of current instruction 2113 int insert = 0; // bytes to be added after this instruction 2114 2115 switch (ClassWriter.TYPE[opcode]) { 2116 case ClassWriter.NOARG_INSN: 2117 case ClassWriter.IMPLVAR_INSN: 2118 u += 1; 2119 break; 2120 case ClassWriter.LABEL_INSN: 2121 if (opcode > 201) { 2122 // converts temporary opcodes 202 to 217, 218 and 2123 // 219 to IFEQ ... JSR (inclusive), IFNULL and 2124 // IFNONNULL 2125 opcode = opcode < 218 ? opcode - 49 : opcode - 20; 2126 label = u + readUnsignedShort(b, u + 1); 2127 } else { 2128 label = u + readShort(b, u + 1); 2129 } 2130 newOffset = getNewOffset(allIndexes, allSizes, u, label); 2131 if (newOffset < Short.MIN_VALUE 2132 || newOffset > Short.MAX_VALUE) 2133 { 2134 if (!resize[u]) { 2135 if (opcode == Opcodes.GOTO 2136 || opcode == Opcodes.JSR) 2137 { 2138 // two additional bytes will be required to 2139 // replace this GOTO or JSR instruction with 2140 // a GOTO_W or a JSR_W 2141 insert = 2; 2142 } else { 2143 // five additional bytes will be required to 2144 // replace this IFxxx <l> instruction with 2145 // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx 2146 // is the "opposite" opcode of IFxxx (i.e., 2147 // IFNE for IFEQ) and where <l'> designates 2148 // the instruction just after the GOTO_W. 2149 insert = 5; 2150 } 2151 resize[u] = true; 2152 } 2153 } 2154 u += 3; 2155 break; 2156 case ClassWriter.LABELW_INSN: 2157 u += 5; 2158 break; 2159 case ClassWriter.TABL_INSN: 2160 if (state == 1) { 2161 // true number of bytes to be added (or removed) 2162 // from this instruction = (future number of padding 2163 // bytes - current number of padding byte) - 2164 // previously over estimated variation = 2165 // = ((3 - newOffset%4) - (3 - u%4)) - u%4 2166 // = (-newOffset%4 + u%4) - u%4 2167 // = -(newOffset & 3) 2168 newOffset = getNewOffset(allIndexes, allSizes, 0, u); 2169 insert = -(newOffset & 3); 2170 } else if (!resize[u]) { 2171 // over estimation of the number of bytes to be 2172 // added to this instruction = 3 - current number 2173 // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 2174 insert = u & 3; 2175 resize[u] = true; 2176 } 2177 // skips instruction 2178 u = u + 4 - (u & 3); 2179 u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; 2180 break; 2181 case ClassWriter.LOOK_INSN: 2182 if (state == 1) { 2183 // like TABL_INSN 2184 newOffset = getNewOffset(allIndexes, allSizes, 0, u); 2185 insert = -(newOffset & 3); 2186 } else if (!resize[u]) { 2187 // like TABL_INSN 2188 insert = u & 3; 2189 resize[u] = true; 2190 } 2191 // skips instruction 2192 u = u + 4 - (u & 3); 2193 u += 8 * readInt(b, u + 4) + 8; 2194 break; 2195 case ClassWriter.WIDE_INSN: 2196 opcode = b[u + 1] & 0xFF; 2197 if (opcode == Opcodes.IINC) { 2198 u += 6; 2199 } else { 2200 u += 4; 2201 } 2202 break; 2203 case ClassWriter.VAR_INSN: 2204 case ClassWriter.SBYTE_INSN: 2205 case ClassWriter.LDC_INSN: 2206 u += 2; 2207 break; 2208 case ClassWriter.SHORT_INSN: 2209 case ClassWriter.LDCW_INSN: 2210 case ClassWriter.FIELDORMETH_INSN: 2211 case ClassWriter.TYPE_INSN: 2212 case ClassWriter.IINC_INSN: 2213 u += 3; 2214 break; 2215 case ClassWriter.ITFMETH_INSN: 2216 u += 5; 2217 break; 2218 // case ClassWriter.MANA_INSN: 2219 default: 2220 u += 4; 2221 break; 2222 } 2223 if (insert != 0) { 2224 // adds a new (u, insert) entry in the allIndexes and 2225 // allSizes arrays 2226 int[] newIndexes = new int[allIndexes.length + 1]; 2227 int[] newSizes = new int[allSizes.length + 1]; 2228 System.arraycopy(allIndexes, 2229 0, 2230 newIndexes, 2231 0, 2232 allIndexes.length); 2233 System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); 2234 newIndexes[allIndexes.length] = u; 2235 newSizes[allSizes.length] = insert; 2236 allIndexes = newIndexes; 2237 allSizes = newSizes; 2238 if (insert > 0) { 2239 state = 3; 2240 } 2241 } 2242 } 2243 if (state < 3) { 2244 --state; 2245 } 2246 } while (state != 0); 2247 2248 // 2nd step: 2249 // copies the bytecode of the method into a new bytevector, updates the 2250 // offsets, and inserts (or removes) bytes as requested. 2251 2252 ByteVector newCode = new ByteVector(code.length); 2253 2254 u = 0; 2255 while (u < code.length) { 2256 int opcode = b[u] & 0xFF; 2257 switch (ClassWriter.TYPE[opcode]) { 2258 case ClassWriter.NOARG_INSN: 2259 case ClassWriter.IMPLVAR_INSN: 2260 newCode.putByte(opcode); 2261 u += 1; 2262 break; 2263 case ClassWriter.LABEL_INSN: 2264 if (opcode > 201) { 2265 // changes temporary opcodes 202 to 217 (inclusive), 218 2266 // and 219 to IFEQ ... JSR (inclusive), IFNULL and 2267 // IFNONNULL 2268 opcode = opcode < 218 ? opcode - 49 : opcode - 20; 2269 label = u + readUnsignedShort(b, u + 1); 2270 } else { 2271 label = u + readShort(b, u + 1); 2272 } 2273 newOffset = getNewOffset(allIndexes, allSizes, u, label); 2274 if (resize[u]) { 2275 // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx 2276 // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is 2277 // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) 2278 // and where <l'> designates the instruction just after 2279 // the GOTO_W. 2280 if (opcode == Opcodes.GOTO) { 2281 newCode.putByte(200); // GOTO_W 2282 } else if (opcode == Opcodes.JSR) { 2283 newCode.putByte(201); // JSR_W 2284 } else { 2285 newCode.putByte(opcode <= 166 2286 ? ((opcode + 1) ^ 1) - 1 2287 : opcode ^ 1); 2288 newCode.putShort(8); // jump offset 2289 newCode.putByte(200); // GOTO_W 2290 // newOffset now computed from start of GOTO_W 2291 newOffset -= 3; 2292 } 2293 newCode.putInt(newOffset); 2294 } else { 2295 newCode.putByte(opcode); 2296 newCode.putShort(newOffset); 2297 } 2298 u += 3; 2299 break; 2300 case ClassWriter.LABELW_INSN: 2301 label = u + readInt(b, u + 1); 2302 newOffset = getNewOffset(allIndexes, allSizes, u, label); 2303 newCode.putByte(opcode); 2304 newCode.putInt(newOffset); 2305 u += 5; 2306 break; 2307 case ClassWriter.TABL_INSN: 2308 // skips 0 to 3 padding bytes 2309 v = u; 2310 u = u + 4 - (v & 3); 2311 // reads and copies instruction 2312 newCode.putByte(Opcodes.TABLESWITCH); 2313 newCode.length += (4 - newCode.length % 4) % 4; 2314 label = v + readInt(b, u); 2315 u += 4; 2316 newOffset = getNewOffset(allIndexes, allSizes, v, label); 2317 newCode.putInt(newOffset); 2318 j = readInt(b, u); 2319 u += 4; 2320 newCode.putInt(j); 2321 j = readInt(b, u) - j + 1; 2322 u += 4; 2323 newCode.putInt(readInt(b, u - 4)); 2324 for (; j > 0; --j) { 2325 label = v + readInt(b, u); 2326 u += 4; 2327 newOffset = getNewOffset(allIndexes, allSizes, v, label); 2328 newCode.putInt(newOffset); 2329 } 2330 break; 2331 case ClassWriter.LOOK_INSN: 2332 // skips 0 to 3 padding bytes 2333 v = u; 2334 u = u + 4 - (v & 3); 2335 // reads and copies instruction 2336 newCode.putByte(Opcodes.LOOKUPSWITCH); 2337 newCode.length += (4 - newCode.length % 4) % 4; 2338 label = v + readInt(b, u); 2339 u += 4; 2340 newOffset = getNewOffset(allIndexes, allSizes, v, label); 2341 newCode.putInt(newOffset); 2342 j = readInt(b, u); 2343 u += 4; 2344 newCode.putInt(j); 2345 for (; j > 0; --j) { 2346 newCode.putInt(readInt(b, u)); 2347 u += 4; 2348 label = v + readInt(b, u); 2349 u += 4; 2350 newOffset = getNewOffset(allIndexes, allSizes, v, label); 2351 newCode.putInt(newOffset); 2352 } 2353 break; 2354 case ClassWriter.WIDE_INSN: 2355 opcode = b[u + 1] & 0xFF; 2356 if (opcode == Opcodes.IINC) { 2357 newCode.putByteArray(b, u, 6); 2358 u += 6; 2359 } else { 2360 newCode.putByteArray(b, u, 4); 2361 u += 4; 2362 } 2363 break; 2364 case ClassWriter.VAR_INSN: 2365 case ClassWriter.SBYTE_INSN: 2366 case ClassWriter.LDC_INSN: 2367 newCode.putByteArray(b, u, 2); 2368 u += 2; 2369 break; 2370 case ClassWriter.SHORT_INSN: 2371 case ClassWriter.LDCW_INSN: 2372 case ClassWriter.FIELDORMETH_INSN: 2373 case ClassWriter.TYPE_INSN: 2374 case ClassWriter.IINC_INSN: 2375 newCode.putByteArray(b, u, 3); 2376 u += 3; 2377 break; 2378 case ClassWriter.ITFMETH_INSN: 2379 newCode.putByteArray(b, u, 5); 2380 u += 5; 2381 break; 2382 // case MANA_INSN: 2383 default: 2384 newCode.putByteArray(b, u, 4); 2385 u += 4; 2386 break; 2387 } 2388 } 2389 2390 // recomputes the stack map frames 2391 if (frameCount > 0) { 2392 if (compute == FRAMES) { 2393 frameCount = 0; 2394 stackMap = null; 2395 previousFrame = null; 2396 frame = null; 2397 Frame f = new Frame(); 2398 f.owner = labels; 2399 Type[] args = Type.getArgumentTypes(descriptor); 2400 f.initInputFrame(cw, access, args, maxLocals); 2401 visitFrame(f); 2402 Label l = labels; 2403 while (l != null) { 2404 /* 2405 * here we need the original label position. getNewOffset 2406 * must therefore never have been called for this label. 2407 */ 2408 u = l.position - 3; 2409 if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) 2410 { 2411 getNewOffset(allIndexes, allSizes, l); 2412 // TODO update offsets in UNINITIALIZED values 2413 visitFrame(l.frame); 2414 } 2415 l = l.successor; 2416 } 2417 } else { 2418 /* 2419 * Resizing an existing stack map frame table is really hard. 2420 * Not only the table must be parsed to update the offets, but 2421 * new frames may be needed for jump instructions that were 2422 * inserted by this method. And updating the offsets or 2423 * inserting frames can change the format of the following 2424 * frames, in case of packed frames. In practice the whole table 2425 * must be recomputed. For this the frames are marked as 2426 * potentially invalid. This will cause the whole class to be 2427 * reread and rewritten with the COMPUTE_FRAMES option (see the 2428 * ClassWriter.toByteArray method). This is not very efficient 2429 * but is much easier and requires much less code than any other 2430 * method I can think of. 2431 */ 2432 cw.invalidFrames = true; 2433 } 2434 } 2435 // updates the exception handler block labels 2436 Handler h = firstHandler; 2437 while (h != null) { 2438 getNewOffset(allIndexes, allSizes, h.start); 2439 getNewOffset(allIndexes, allSizes, h.end); 2440 getNewOffset(allIndexes, allSizes, h.handler); 2441 h = h.next; 2442 } 2443 // updates the instructions addresses in the 2444 // local var and line number tables 2445 for (i = 0; i < 2; ++i) { 2446 ByteVector bv = i == 0 ? localVar : localVarType; 2447 if (bv != null) { 2448 b = bv.data; 2449 u = 0; 2450 while (u < bv.length) { 2451 label = readUnsignedShort(b, u); 2452 newOffset = getNewOffset(allIndexes, allSizes, 0, label); 2453 writeShort(b, u, newOffset); 2454 label += readUnsignedShort(b, u + 2); 2455 newOffset = getNewOffset(allIndexes, allSizes, 0, label) 2456 - newOffset; 2457 writeShort(b, u + 2, newOffset); 2458 u += 10; 2459 } 2460 } 2461 } 2462 if (lineNumber != null) { 2463 b = lineNumber.data; 2464 u = 0; 2465 while (u < lineNumber.length) { 2466 writeShort(b, u, getNewOffset(allIndexes, 2467 allSizes, 2468 0, 2469 readUnsignedShort(b, u))); 2470 u += 4; 2471 } 2472 } 2473 // updates the labels of the other attributes 2474 Attribute attr = cattrs; 2475 while (attr != null) { 2476 Label[] labels = attr.getLabels(); 2477 if (labels != null) { 2478 for (i = labels.length - 1; i >= 0; --i) { 2479 getNewOffset(allIndexes, allSizes, labels[i]); 2480 } 2481 } 2482 attr = attr.next; 2483 } 2484 2485 // replaces old bytecodes with new ones 2486 code = newCode; 2487 } 2488 2489 /** 2490 * Reads an unsigned short value in the given byte array. 2491 * 2492 * @param b a byte array. 2493 * @param index the start index of the value to be read. 2494 * @return the read value. 2495 */ readUnsignedShort(final byte[] b, final int index)2496 static int readUnsignedShort(final byte[] b, final int index) { 2497 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); 2498 } 2499 2500 /** 2501 * Reads a signed short value in the given byte array. 2502 * 2503 * @param b a byte array. 2504 * @param index the start index of the value to be read. 2505 * @return the read value. 2506 */ readShort(final byte[] b, final int index)2507 static short readShort(final byte[] b, final int index) { 2508 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); 2509 } 2510 2511 /** 2512 * Reads a signed int value in the given byte array. 2513 * 2514 * @param b a byte array. 2515 * @param index the start index of the value to be read. 2516 * @return the read value. 2517 */ readInt(final byte[] b, final int index)2518 static int readInt(final byte[] b, final int index) { 2519 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) 2520 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); 2521 } 2522 2523 /** 2524 * Writes a short value in the given byte array. 2525 * 2526 * @param b a byte array. 2527 * @param index where the first byte of the short value must be written. 2528 * @param s the value to be written in the given byte array. 2529 */ writeShort(final byte[] b, final int index, final int s)2530 static void writeShort(final byte[] b, final int index, final int s) { 2531 b[index] = (byte) (s >>> 8); 2532 b[index + 1] = (byte) s; 2533 } 2534 2535 /** 2536 * Computes the future value of a bytecode offset. <p> Note: it is possible 2537 * to have several entries for the same instruction in the <tt>indexes</tt> 2538 * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b') 2539 * are equivalent to a single entry (index=a,size=b+b'). 2540 * 2541 * @param indexes current positions of the instructions to be resized. Each 2542 * instruction must be designated by the index of its <i>last</i> 2543 * byte, plus one (or, in other words, by the index of the <i>first</i> 2544 * byte of the <i>next</i> instruction). 2545 * @param sizes the number of bytes to be <i>added</i> to the above 2546 * instructions. More precisely, for each i < <tt>len</tt>, 2547 * <tt>sizes</tt>[i] bytes will be added at the end of the 2548 * instruction designated by <tt>indexes</tt>[i] or, if 2549 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| 2550 * bytes of the instruction will be removed (the instruction size 2551 * <i>must not</i> become negative or null). 2552 * @param begin index of the first byte of the source instruction. 2553 * @param end index of the first byte of the target instruction. 2554 * @return the future value of the given bytecode offset. 2555 */ getNewOffset( final int[] indexes, final int[] sizes, final int begin, final int end)2556 static int getNewOffset( 2557 final int[] indexes, 2558 final int[] sizes, 2559 final int begin, 2560 final int end) 2561 { 2562 int offset = end - begin; 2563 for (int i = 0; i < indexes.length; ++i) { 2564 if (begin < indexes[i] && indexes[i] <= end) { 2565 // forward jump 2566 offset += sizes[i]; 2567 } else if (end < indexes[i] && indexes[i] <= begin) { 2568 // backward jump 2569 offset -= sizes[i]; 2570 } 2571 } 2572 return offset; 2573 } 2574 2575 /** 2576 * Updates the offset of the given label. 2577 * 2578 * @param indexes current positions of the instructions to be resized. Each 2579 * instruction must be designated by the index of its <i>last</i> 2580 * byte, plus one (or, in other words, by the index of the <i>first</i> 2581 * byte of the <i>next</i> instruction). 2582 * @param sizes the number of bytes to be <i>added</i> to the above 2583 * instructions. More precisely, for each i < <tt>len</tt>, 2584 * <tt>sizes</tt>[i] bytes will be added at the end of the 2585 * instruction designated by <tt>indexes</tt>[i] or, if 2586 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| 2587 * bytes of the instruction will be removed (the instruction size 2588 * <i>must not</i> become negative or null). 2589 * @param label the label whose offset must be updated. 2590 */ getNewOffset( final int[] indexes, final int[] sizes, final Label label)2591 static void getNewOffset( 2592 final int[] indexes, 2593 final int[] sizes, 2594 final Label label) 2595 { 2596 if ((label.status & Label.RESIZED) == 0) { 2597 label.position = getNewOffset(indexes, sizes, 0, label.position); 2598 label.status |= Label.RESIZED; 2599 } 2600 } 2601 } 2602