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