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 */ MethodWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions, final boolean computeMaxs, final boolean computeFrames)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 visitParameter(String name, int access)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 visitAnnotationDefault()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 visitAnnotation(final String desc, final boolean visible)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 visitTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible)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 visitParameterAnnotation(final int parameter, final String desc, final boolean visible)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 visitAttribute(final Attribute attr)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 visitCode()636 public void visitCode() { 637 } 638 639 @Override visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack)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 visitInsn(final int opcode)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 visitIntInsn(final int opcode, final int operand)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 visitVarInsn(final int opcode, final int var)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 visitTypeInsn(final int opcode, final String type)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 visitFieldInsn(final int opcode, final String owner, final String name, final String desc)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 visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf)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 visitInvokeDynamicInsn(final String name, final String desc, final Handle bsm, final Object... bsmArgs)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 visitJumpInsn(final int opcode, final Label label)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 visitLabel(final Label label)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 visitLdcInsn(final Object cst)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 visitIincInsn(final int var, final int increment)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 visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels)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 visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)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 visitSwitchInsn(final Label dflt, final Label[] labels)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 visitMultiANewArrayInsn(final String desc, final int dims)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 visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible)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 visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type)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 visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible)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 visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index)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 visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible)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 visitLineNumber(final int line, final Label start)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 visitMaxs(final int maxStack, final int maxLocals)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 visitEnd()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 */ addSuccessor(final int info, final Label successor)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 */ noSuccessor()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 */ visitFrame(final Frame f)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 */ visitImplicitFirstFrame()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 */ startFrame(final int offset, final int nLocal, final int nStack)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 */ endFrame()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 */ writeFrame()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 > 65536) { 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 */ put(final ByteVector out)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 */ resizeInstructions()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 for (i = 0; i < cw.typeTable.length; ++i) { 2739 Item item = cw.typeTable[i]; 2740 if (item != null && item.type == ClassWriter.TYPE_UNINIT) { 2741 item.intVal = getNewOffset(allIndexes, allSizes, 0, 2742 item.intVal); 2743 } 2744 } 2745 // The stack map frames are not serialized yet, so we don't need 2746 // to update them. They will be serialized in visitMaxs. 2747 } else if (frameCount > 0) { 2748 /* 2749 * Resizing an existing stack map frame table is really hard. Not 2750 * only the table must be parsed to update the offets, but new 2751 * frames may be needed for jump instructions that were inserted by 2752 * this method. And updating the offsets or inserting frames can 2753 * change the format of the following frames, in case of packed 2754 * frames. In practice the whole table must be recomputed. For this 2755 * the frames are marked as potentially invalid. This will cause the 2756 * whole class to be reread and rewritten with the COMPUTE_FRAMES 2757 * option (see the ClassWriter.toByteArray method). This is not very 2758 * efficient but is much easier and requires much less code than any 2759 * other method I can think of. 2760 */ 2761 cw.invalidFrames = true; 2762 } 2763 // updates the exception handler block labels 2764 Handler h = firstHandler; 2765 while (h != null) { 2766 getNewOffset(allIndexes, allSizes, h.start); 2767 getNewOffset(allIndexes, allSizes, h.end); 2768 getNewOffset(allIndexes, allSizes, h.handler); 2769 h = h.next; 2770 } 2771 // updates the instructions addresses in the 2772 // local var and line number tables 2773 for (i = 0; i < 2; ++i) { 2774 ByteVector bv = i == 0 ? localVar : localVarType; 2775 if (bv != null) { 2776 b = bv.data; 2777 u = 0; 2778 while (u < bv.length) { 2779 label = readUnsignedShort(b, u); 2780 newOffset = getNewOffset(allIndexes, allSizes, 0, label); 2781 writeShort(b, u, newOffset); 2782 label += readUnsignedShort(b, u + 2); 2783 newOffset = getNewOffset(allIndexes, allSizes, 0, label) 2784 - newOffset; 2785 writeShort(b, u + 2, newOffset); 2786 u += 10; 2787 } 2788 } 2789 } 2790 if (lineNumber != null) { 2791 b = lineNumber.data; 2792 u = 0; 2793 while (u < lineNumber.length) { 2794 writeShort( 2795 b, 2796 u, 2797 getNewOffset(allIndexes, allSizes, 0, 2798 readUnsignedShort(b, u))); 2799 u += 4; 2800 } 2801 } 2802 // updates the labels of the other attributes 2803 Attribute attr = cattrs; 2804 while (attr != null) { 2805 Label[] labels = attr.getLabels(); 2806 if (labels != null) { 2807 for (i = labels.length - 1; i >= 0; --i) { 2808 getNewOffset(allIndexes, allSizes, labels[i]); 2809 } 2810 } 2811 attr = attr.next; 2812 } 2813 2814 // replaces old bytecodes with new ones 2815 code = newCode; 2816 } 2817 2818 /** 2819 * Reads an unsigned short value in the given byte array. 2820 * 2821 * @param b 2822 * a byte array. 2823 * @param index 2824 * the start index of the value to be read. 2825 * @return the read value. 2826 */ readUnsignedShort(final byte[] b, final int index)2827 static int readUnsignedShort(final byte[] b, final int index) { 2828 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); 2829 } 2830 2831 /** 2832 * Reads a signed short value in the given byte array. 2833 * 2834 * @param b 2835 * a byte array. 2836 * @param index 2837 * the start index of the value to be read. 2838 * @return the read value. 2839 */ readShort(final byte[] b, final int index)2840 static short readShort(final byte[] b, final int index) { 2841 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); 2842 } 2843 2844 /** 2845 * Reads a signed int value in the given byte array. 2846 * 2847 * @param b 2848 * a byte array. 2849 * @param index 2850 * the start index of the value to be read. 2851 * @return the read value. 2852 */ readInt(final byte[] b, final int index)2853 static int readInt(final byte[] b, final int index) { 2854 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) 2855 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); 2856 } 2857 2858 /** 2859 * Writes a short value in the given byte array. 2860 * 2861 * @param b 2862 * a byte array. 2863 * @param index 2864 * where the first byte of the short value must be written. 2865 * @param s 2866 * the value to be written in the given byte array. 2867 */ writeShort(final byte[] b, final int index, final int s)2868 static void writeShort(final byte[] b, final int index, final int s) { 2869 b[index] = (byte) (s >>> 8); 2870 b[index + 1] = (byte) s; 2871 } 2872 2873 /** 2874 * Computes the future value of a bytecode offset. 2875 * <p> 2876 * Note: it is possible to have several entries for the same instruction in 2877 * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and 2878 * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b'). 2879 * 2880 * @param indexes 2881 * current positions of the instructions to be resized. Each 2882 * instruction must be designated by the index of its <i>last</i> 2883 * byte, plus one (or, in other words, by the index of the 2884 * <i>first</i> byte of the <i>next</i> instruction). 2885 * @param sizes 2886 * the number of bytes to be <i>added</i> to the above 2887 * instructions. More precisely, for each i < <tt>len</tt>, 2888 * <tt>sizes</tt>[i] bytes will be added at the end of the 2889 * instruction designated by <tt>indexes</tt>[i] or, if 2890 * <tt>sizes</tt>[i] is negative, the <i>last</i> | 2891 * <tt>sizes[i]</tt>| bytes of the instruction will be removed 2892 * (the instruction size <i>must not</i> become negative or 2893 * null). 2894 * @param begin 2895 * index of the first byte of the source instruction. 2896 * @param end 2897 * index of the first byte of the target instruction. 2898 * @return the future value of the given bytecode offset. 2899 */ getNewOffset(final int[] indexes, final int[] sizes, final int begin, final int end)2900 static int getNewOffset(final int[] indexes, final int[] sizes, 2901 final int begin, final int end) { 2902 int offset = end - begin; 2903 for (int i = 0; i < indexes.length; ++i) { 2904 if (begin < indexes[i] && indexes[i] <= end) { 2905 // forward jump 2906 offset += sizes[i]; 2907 } else if (end < indexes[i] && indexes[i] <= begin) { 2908 // backward jump 2909 offset -= sizes[i]; 2910 } 2911 } 2912 return offset; 2913 } 2914 2915 /** 2916 * Updates the offset of the given label. 2917 * 2918 * @param indexes 2919 * current positions of the instructions to be resized. Each 2920 * instruction must be designated by the index of its <i>last</i> 2921 * byte, plus one (or, in other words, by the index of the 2922 * <i>first</i> byte of the <i>next</i> instruction). 2923 * @param sizes 2924 * the number of bytes to be <i>added</i> to the above 2925 * instructions. More precisely, for each i < <tt>len</tt>, 2926 * <tt>sizes</tt>[i] bytes will be added at the end of the 2927 * instruction designated by <tt>indexes</tt>[i] or, if 2928 * <tt>sizes</tt>[i] is negative, the <i>last</i> | 2929 * <tt>sizes[i]</tt>| bytes of the instruction will be removed 2930 * (the instruction size <i>must not</i> become negative or 2931 * null). 2932 * @param label 2933 * the label whose offset must be updated. 2934 */ getNewOffset(final int[] indexes, final int[] sizes, final Label label)2935 static void getNewOffset(final int[] indexes, final int[] sizes, 2936 final Label label) { 2937 if ((label.status & Label.RESIZED) == 0) { 2938 label.position = getNewOffset(indexes, sizes, 0, label.position); 2939 label.status |= Label.RESIZED; 2940 } 2941 } 2942 } 2943