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