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 */ 30package 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 */ 40class 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 */ 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 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 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 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 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 537 public void visitCode() { 538 } 539 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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