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 static final int FRAMES = 0; 132 133 /** 134 * Indicates that the stack map frames of type F_INSERT must be computed. 135 * The other frames are not (re)computed. They should all be of type F_NEW 136 * and should be sufficient to compute the content of the F_INSERT frames, 137 * together with the bytecode instructions between a F_NEW and a F_INSERT 138 * frame - and without any knowledge of the type hierarchy (by definition of 139 * F_INSERT). 140 * 141 * @see #compute 142 */ 143 static final int INSERTED_FRAMES = 1; 144 145 /** 146 * Indicates that the maximum stack size and number of local variables must 147 * be automatically computed. 148 * 149 * @see #compute 150 */ 151 static final int MAXS = 2; 152 153 /** 154 * Indicates that nothing must be automatically computed. 155 * 156 * @see #compute 157 */ 158 static final int NOTHING = 3; 159 160 /** 161 * The class writer to which this method must be added. 162 */ 163 final ClassWriter cw; 164 165 /** 166 * Access flags of this method. 167 */ 168 private int access; 169 170 /** 171 * The index of the constant pool item that contains the name of this 172 * method. 173 */ 174 private final int name; 175 176 /** 177 * The index of the constant pool item that contains the descriptor of this 178 * method. 179 */ 180 private final int desc; 181 182 /** 183 * The descriptor of this method. 184 */ 185 private final String descriptor; 186 187 /** 188 * The signature of this method. 189 */ 190 String signature; 191 192 /** 193 * If not zero, indicates that the code of this method must be copied from 194 * the ClassReader associated to this writer in <code>cw.cr</code>. More 195 * precisely, this field gives the index of the first byte to copied from 196 * <code>cw.cr.b</code>. 197 */ 198 int classReaderOffset; 199 200 /** 201 * If not zero, indicates that the code of this method must be copied from 202 * the ClassReader associated to this writer in <code>cw.cr</code>. More 203 * precisely, this field gives the number of bytes to copied from 204 * <code>cw.cr.b</code>. 205 */ 206 int classReaderLength; 207 208 /** 209 * Number of exceptions that can be thrown by this method. 210 */ 211 int exceptionCount; 212 213 /** 214 * The exceptions that can be thrown by this method. More precisely, this 215 * array contains the indexes of the constant pool items that contain the 216 * internal names of these exception classes. 217 */ 218 int[] exceptions; 219 220 /** 221 * The annotation default attribute of this method. May be <tt>null</tt>. 222 */ 223 private ByteVector annd; 224 225 /** 226 * The runtime visible annotations of this method. May be <tt>null</tt>. 227 */ 228 private AnnotationWriter anns; 229 230 /** 231 * The runtime invisible annotations of this method. May be <tt>null</tt>. 232 */ 233 private AnnotationWriter ianns; 234 235 /** 236 * The runtime visible type annotations of this method. May be <tt>null</tt> 237 * . 238 */ 239 private AnnotationWriter tanns; 240 241 /** 242 * The runtime invisible type annotations of this method. May be 243 * <tt>null</tt>. 244 */ 245 private AnnotationWriter itanns; 246 247 /** 248 * The runtime visible parameter annotations of this method. May be 249 * <tt>null</tt>. 250 */ 251 private AnnotationWriter[] panns; 252 253 /** 254 * The runtime invisible parameter annotations of this method. May be 255 * <tt>null</tt>. 256 */ 257 private AnnotationWriter[] ipanns; 258 259 /** 260 * The number of synthetic parameters of this method. 261 */ 262 private int synthetics; 263 264 /** 265 * The non standard attributes of the method. 266 */ 267 private Attribute attrs; 268 269 /** 270 * The bytecode of this method. 271 */ 272 private ByteVector code = new ByteVector(); 273 274 /** 275 * Maximum stack size of this method. 276 */ 277 private int maxStack; 278 279 /** 280 * Maximum number of local variables for this method. 281 */ 282 private int maxLocals; 283 284 /** 285 * Number of local variables in the current stack map frame. 286 */ 287 private int currentLocals; 288 289 /** 290 * Number of stack map frames in the StackMapTable attribute. 291 */ 292 int frameCount; 293 294 /** 295 * The StackMapTable attribute. 296 */ 297 private ByteVector stackMap; 298 299 /** 300 * The offset of the last frame that was written in the StackMapTable 301 * attribute. 302 */ 303 private int previousFrameOffset; 304 305 /** 306 * The last frame that was written in the StackMapTable attribute. 307 * 308 * @see #frame 309 */ 310 private int[] previousFrame; 311 312 /** 313 * The current stack map frame. The first element contains the offset of the 314 * instruction to which the frame corresponds, the second element is the 315 * number of locals and the third one is the number of stack elements. The 316 * local variables start at index 3 and are followed by the operand stack 317 * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = 318 * nStack, frame[3] = nLocal. All types are encoded as integers, with the 319 * same format as the one used in {@link Label}, but limited to BASE types. 320 */ 321 private int[] frame; 322 323 /** 324 * Number of elements in the exception handler list. 325 */ 326 private int handlerCount; 327 328 /** 329 * The first element in the exception handler list. 330 */ 331 private Handler firstHandler; 332 333 /** 334 * The last element in the exception handler list. 335 */ 336 private Handler lastHandler; 337 338 /** 339 * Number of entries in the MethodParameters attribute. 340 */ 341 private int methodParametersCount; 342 343 /** 344 * The MethodParameters attribute. 345 */ 346 private ByteVector methodParameters; 347 348 /** 349 * Number of entries in the LocalVariableTable attribute. 350 */ 351 private int localVarCount; 352 353 /** 354 * The LocalVariableTable attribute. 355 */ 356 private ByteVector localVar; 357 358 /** 359 * Number of entries in the LocalVariableTypeTable attribute. 360 */ 361 private int localVarTypeCount; 362 363 /** 364 * The LocalVariableTypeTable attribute. 365 */ 366 private ByteVector localVarType; 367 368 /** 369 * Number of entries in the LineNumberTable attribute. 370 */ 371 private int lineNumberCount; 372 373 /** 374 * The LineNumberTable attribute. 375 */ 376 private ByteVector lineNumber; 377 378 /** 379 * The start offset of the last visited instruction. 380 */ 381 private int lastCodeOffset; 382 383 /** 384 * The runtime visible type annotations of the code. May be <tt>null</tt>. 385 */ 386 private AnnotationWriter ctanns; 387 388 /** 389 * The runtime invisible type annotations of the code. May be <tt>null</tt>. 390 */ 391 private AnnotationWriter ictanns; 392 393 /** 394 * The non standard attributes of the method's code. 395 */ 396 private Attribute cattrs; 397 398 /** 399 * The number of subroutines in this method. 400 */ 401 private int subroutines; 402 403 // ------------------------------------------------------------------------ 404 405 /* 406 * Fields for the control flow graph analysis algorithm (used to compute the 407 * maximum stack size). A control flow graph contains one node per "basic 408 * block", and one edge per "jump" from one basic block to another. Each 409 * node (i.e., each basic block) is represented by the Label object that 410 * corresponds to the first instruction of this basic block. Each node also 411 * stores the list of its successors in the graph, as a linked list of Edge 412 * objects. 413 */ 414 415 /** 416 * Indicates what must be automatically computed. 417 * 418 * @see #FRAMES 419 * @see #INSERTED_FRAMES 420 * @see #MAXS 421 * @see #NOTHING 422 */ 423 private final int compute; 424 425 /** 426 * A list of labels. This list is the list of basic blocks in the method, 427 * i.e. a list of Label objects linked to each other by their 428 * {@link Label#successor} field, in the order they are visited by 429 * {@link MethodVisitor#visitLabel}, and starting with the first basic 430 * block. 431 */ 432 private Label labels; 433 434 /** 435 * The previous basic block. 436 */ 437 private Label previousBlock; 438 439 /** 440 * The current basic block. 441 */ 442 private Label currentBlock; 443 444 /** 445 * The (relative) stack size after the last visited instruction. This size 446 * is relative to the beginning of the current basic block, i.e., the true 447 * stack size after the last visited instruction is equal to the 448 * {@link Label#inputStackTop beginStackSize} of the current basic block 449 * plus <tt>stackSize</tt>. 450 */ 451 private int stackSize; 452 453 /** 454 * The (relative) maximum stack size after the last visited instruction. 455 * This size is relative to the beginning of the current basic block, i.e., 456 * the true maximum stack size after the last visited instruction is equal 457 * to the {@link Label#inputStackTop beginStackSize} of the current basic 458 * block plus <tt>stackSize</tt>. 459 */ 460 private int maxStackSize; 461 462 // ------------------------------------------------------------------------ 463 // Constructor 464 // ------------------------------------------------------------------------ 465 466 /** 467 * Constructs a new {@link MethodWriter}. 468 * 469 * @param cw 470 * the class writer in which the method must be added. 471 * @param access 472 * the method's access flags (see {@link Opcodes}). 473 * @param name 474 * the method's name. 475 * @param desc 476 * the method's descriptor (see {@link Type}). 477 * @param signature 478 * the method's signature. May be <tt>null</tt>. 479 * @param exceptions 480 * the internal names of the method's exceptions. May be 481 * <tt>null</tt>. 482 * @param compute 483 * Indicates what must be automatically computed (see #compute). 484 */ 485 MethodWriter(final ClassWriter cw, final int access, final String name, 486 final String desc, final String signature, 487 final String[] exceptions, final int compute) { 488 super(Opcodes.ASM6); 489 if (cw.firstMethod == null) { 490 cw.firstMethod = this; 491 } else { 492 cw.lastMethod.mv = this; 493 } 494 cw.lastMethod = this; 495 this.cw = cw; 496 this.access = access; 497 if ("<init>".equals(name)) { 498 this.access |= ACC_CONSTRUCTOR; 499 } 500 this.name = cw.newUTF8(name); 501 this.desc = cw.newUTF8(desc); 502 this.descriptor = desc; 503 this.signature = signature; 504 if (exceptions != null && exceptions.length > 0) { 505 exceptionCount = exceptions.length; 506 this.exceptions = new int[exceptionCount]; 507 for (int i = 0; i < exceptionCount; ++i) { 508 this.exceptions[i] = cw.newClass(exceptions[i]); 509 } 510 } 511 this.compute = compute; 512 if (compute != NOTHING) { 513 // updates maxLocals 514 int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; 515 if ((access & Opcodes.ACC_STATIC) != 0) { 516 --size; 517 } 518 maxLocals = size; 519 currentLocals = size; 520 // creates and visits the label for the first basic block 521 labels = new Label(); 522 labels.status |= Label.PUSHED; 523 visitLabel(labels); 524 } 525 } 526 527 // ------------------------------------------------------------------------ 528 // Implementation of the MethodVisitor abstract class 529 // ------------------------------------------------------------------------ 530 531 @Override 532 public void visitParameter(String name, int access) { 533 if (methodParameters == null) { 534 methodParameters = new ByteVector(); 535 } 536 ++methodParametersCount; 537 methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name)) 538 .putShort(access); 539 } 540 541 @Override 542 public AnnotationVisitor visitAnnotationDefault() { 543 annd = new ByteVector(); 544 return new AnnotationWriter(cw, false, annd, null, 0); 545 } 546 547 @Override 548 public AnnotationVisitor visitAnnotation(final String desc, 549 final boolean visible) { 550 ByteVector bv = new ByteVector(); 551 // write type, and reserve space for values count 552 bv.putShort(cw.newUTF8(desc)).putShort(0); 553 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); 554 if (visible) { 555 aw.next = anns; 556 anns = aw; 557 } else { 558 aw.next = ianns; 559 ianns = aw; 560 } 561 return aw; 562 } 563 564 @Override 565 public AnnotationVisitor visitTypeAnnotation(final int typeRef, 566 final TypePath typePath, final String desc, final boolean visible) { 567 ByteVector bv = new ByteVector(); 568 // write target_type and target_info 569 AnnotationWriter.putTarget(typeRef, typePath, bv); 570 // write type, and reserve space for values count 571 bv.putShort(cw.newUTF8(desc)).putShort(0); 572 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 573 bv.length - 2); 574 if (visible) { 575 aw.next = tanns; 576 tanns = aw; 577 } else { 578 aw.next = itanns; 579 itanns = aw; 580 } 581 return aw; 582 } 583 584 @Override 585 public AnnotationVisitor visitParameterAnnotation(final int parameter, 586 final String desc, final boolean visible) { 587 ByteVector bv = new ByteVector(); 588 if ("Ljava/lang/Synthetic;".equals(desc)) { 589 // workaround for a bug in javac with synthetic parameters 590 // see ClassReader.readParameterAnnotations 591 synthetics = Math.max(synthetics, parameter + 1); 592 return new AnnotationWriter(cw, false, bv, null, 0); 593 } 594 // write type, and reserve space for values count 595 bv.putShort(cw.newUTF8(desc)).putShort(0); 596 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); 597 if (visible) { 598 if (panns == null) { 599 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; 600 } 601 aw.next = panns[parameter]; 602 panns[parameter] = aw; 603 } else { 604 if (ipanns == null) { 605 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; 606 } 607 aw.next = ipanns[parameter]; 608 ipanns[parameter] = aw; 609 } 610 return aw; 611 } 612 613 @Override 614 public void visitAttribute(final Attribute attr) { 615 if (attr.isCodeAttribute()) { 616 attr.next = cattrs; 617 cattrs = attr; 618 } else { 619 attr.next = attrs; 620 attrs = attr; 621 } 622 } 623 624 @Override 625 public void visitCode() { 626 } 627 628 @Override 629 public void visitFrame(final int type, final int nLocal, 630 final Object[] local, final int nStack, final Object[] stack) { 631 if (compute == FRAMES) { 632 return; 633 } 634 635 if (compute == INSERTED_FRAMES) { 636 if (currentBlock.frame == null) { 637 // This should happen only once, for the implicit first frame 638 // (which is explicitly visited in ClassReader if the 639 // EXPAND_ASM_INSNS option is used). 640 currentBlock.frame = new CurrentFrame(); 641 currentBlock.frame.owner = currentBlock; 642 currentBlock.frame.initInputFrame(cw, access, 643 Type.getArgumentTypes(descriptor), nLocal); 644 visitImplicitFirstFrame(); 645 } else { 646 if (type == Opcodes.F_NEW) { 647 currentBlock.frame.set(cw, nLocal, local, nStack, stack); 648 } else { 649 // In this case type is equal to F_INSERT by hypothesis, and 650 // currentBlock.frame contains the stack map frame at the 651 // current instruction, computed from the last F_NEW frame 652 // and the bytecode instructions in between (via calls to 653 // CurrentFrame#execute). 654 } 655 visitFrame(currentBlock.frame); 656 } 657 } else if (type == Opcodes.F_NEW) { 658 if (previousFrame == null) { 659 visitImplicitFirstFrame(); 660 } 661 currentLocals = nLocal; 662 int frameIndex = startFrame(code.length, nLocal, nStack); 663 for (int i = 0; i < nLocal; ++i) { 664 if (local[i] instanceof String) { 665 String desc = Type.getObjectType((String) local[i]).getDescriptor(); 666 frame[frameIndex++] = Frame.type(cw, desc); 667 } else if (local[i] instanceof Integer) { 668 frame[frameIndex++] = Frame.BASE | ((Integer) local[i]).intValue(); 669 } else { 670 frame[frameIndex++] = Frame.UNINITIALIZED 671 | cw.addUninitializedType("", 672 ((Label) local[i]).position); 673 } 674 } 675 for (int i = 0; i < nStack; ++i) { 676 if (stack[i] instanceof String) { 677 String desc = Type.getObjectType((String) stack[i]).getDescriptor(); 678 frame[frameIndex++] = Frame.type(cw, desc); 679 } else if (stack[i] instanceof Integer) { 680 frame[frameIndex++] = Frame.BASE | ((Integer) stack[i]).intValue(); 681 } else { 682 frame[frameIndex++] = Frame.UNINITIALIZED 683 | cw.addUninitializedType("", 684 ((Label) stack[i]).position); 685 } 686 } 687 endFrame(); 688 } else { 689 int delta; 690 if (stackMap == null) { 691 stackMap = new ByteVector(); 692 delta = code.length; 693 } else { 694 delta = code.length - previousFrameOffset - 1; 695 if (delta < 0) { 696 if (type == Opcodes.F_SAME) { 697 return; 698 } else { 699 throw new IllegalStateException(); 700 } 701 } 702 } 703 704 switch (type) { 705 case Opcodes.F_FULL: 706 currentLocals = nLocal; 707 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal); 708 for (int i = 0; i < nLocal; ++i) { 709 writeFrameType(local[i]); 710 } 711 stackMap.putShort(nStack); 712 for (int i = 0; i < nStack; ++i) { 713 writeFrameType(stack[i]); 714 } 715 break; 716 case Opcodes.F_APPEND: 717 currentLocals += nLocal; 718 stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta); 719 for (int i = 0; i < nLocal; ++i) { 720 writeFrameType(local[i]); 721 } 722 break; 723 case Opcodes.F_CHOP: 724 currentLocals -= nLocal; 725 stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta); 726 break; 727 case Opcodes.F_SAME: 728 if (delta < 64) { 729 stackMap.putByte(delta); 730 } else { 731 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); 732 } 733 break; 734 case Opcodes.F_SAME1: 735 if (delta < 64) { 736 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); 737 } else { 738 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) 739 .putShort(delta); 740 } 741 writeFrameType(stack[0]); 742 break; 743 } 744 745 previousFrameOffset = code.length; 746 ++frameCount; 747 } 748 749 maxStack = Math.max(maxStack, nStack); 750 maxLocals = Math.max(maxLocals, currentLocals); 751 } 752 753 @Override 754 public void visitInsn(final int opcode) { 755 lastCodeOffset = code.length; 756 // adds the instruction to the bytecode of the method 757 code.putByte(opcode); 758 // update currentBlock 759 // Label currentBlock = this.currentBlock; 760 if (currentBlock != null) { 761 if (compute == FRAMES || compute == INSERTED_FRAMES) { 762 currentBlock.frame.execute(opcode, 0, null, null); 763 } else { 764 // updates current and max stack sizes 765 int size = stackSize + Frame.SIZE[opcode]; 766 if (size > maxStackSize) { 767 maxStackSize = size; 768 } 769 stackSize = size; 770 } 771 // if opcode == ATHROW or xRETURN, ends current block (no successor) 772 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) 773 || opcode == Opcodes.ATHROW) { 774 noSuccessor(); 775 } 776 } 777 } 778 779 @Override 780 public void visitIntInsn(final int opcode, final int operand) { 781 lastCodeOffset = code.length; 782 // Label currentBlock = this.currentBlock; 783 if (currentBlock != null) { 784 if (compute == FRAMES || compute == INSERTED_FRAMES) { 785 currentBlock.frame.execute(opcode, operand, null, null); 786 } else if (opcode != Opcodes.NEWARRAY) { 787 // updates current and max stack sizes only for NEWARRAY 788 // (stack size variation = 0 for BIPUSH or SIPUSH) 789 int size = stackSize + 1; 790 if (size > maxStackSize) { 791 maxStackSize = size; 792 } 793 stackSize = size; 794 } 795 } 796 // adds the instruction to the bytecode of the method 797 if (opcode == Opcodes.SIPUSH) { 798 code.put12(opcode, operand); 799 } else { // BIPUSH or NEWARRAY 800 code.put11(opcode, operand); 801 } 802 } 803 804 @Override 805 public void visitVarInsn(final int opcode, final int var) { 806 lastCodeOffset = code.length; 807 // Label currentBlock = this.currentBlock; 808 if (currentBlock != null) { 809 if (compute == FRAMES || compute == INSERTED_FRAMES) { 810 currentBlock.frame.execute(opcode, var, null, null); 811 } else { 812 // updates current and max stack sizes 813 if (opcode == Opcodes.RET) { 814 // no stack change, but end of current block (no successor) 815 currentBlock.status |= Label.RET; 816 // save 'stackSize' here for future use 817 // (see {@link #findSubroutineSuccessors}) 818 currentBlock.inputStackTop = stackSize; 819 noSuccessor(); 820 } else { // xLOAD or xSTORE 821 int size = stackSize + Frame.SIZE[opcode]; 822 if (size > maxStackSize) { 823 maxStackSize = size; 824 } 825 stackSize = size; 826 } 827 } 828 } 829 if (compute != NOTHING) { 830 // updates max locals 831 int n; 832 if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD 833 || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) { 834 n = var + 2; 835 } else { 836 n = var + 1; 837 } 838 if (n > maxLocals) { 839 maxLocals = n; 840 } 841 } 842 // adds the instruction to the bytecode of the method 843 if (var < 4 && opcode != Opcodes.RET) { 844 int opt; 845 if (opcode < Opcodes.ISTORE) { 846 /* ILOAD_0 */ 847 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; 848 } else { 849 /* ISTORE_0 */ 850 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; 851 } 852 code.putByte(opt); 853 } else if (var >= 256) { 854 code.putByte(196 /* WIDE */).put12(opcode, var); 855 } else { 856 code.put11(opcode, var); 857 } 858 if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) { 859 visitLabel(new Label()); 860 } 861 } 862 863 @Override 864 public void visitTypeInsn(final int opcode, final String type) { 865 lastCodeOffset = code.length; 866 Item i = cw.newStringishItem(ClassWriter.CLASS, type); 867 // Label currentBlock = this.currentBlock; 868 if (currentBlock != null) { 869 if (compute == FRAMES || compute == INSERTED_FRAMES) { 870 currentBlock.frame.execute(opcode, code.length, cw, i); 871 } else if (opcode == Opcodes.NEW) { 872 // updates current and max stack sizes only if opcode == NEW 873 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF) 874 int size = stackSize + 1; 875 if (size > maxStackSize) { 876 maxStackSize = size; 877 } 878 stackSize = size; 879 } 880 } 881 // adds the instruction to the bytecode of the method 882 code.put12(opcode, i.index); 883 } 884 885 @Override 886 public void visitFieldInsn(final int opcode, final String owner, 887 final String name, final String desc) { 888 lastCodeOffset = code.length; 889 Item i = cw.newFieldItem(owner, name, desc); 890 // Label currentBlock = this.currentBlock; 891 if (currentBlock != null) { 892 if (compute == FRAMES || compute == INSERTED_FRAMES) { 893 currentBlock.frame.execute(opcode, 0, cw, i); 894 } else { 895 int size; 896 // computes the stack size variation 897 char c = desc.charAt(0); 898 switch (opcode) { 899 case Opcodes.GETSTATIC: 900 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); 901 break; 902 case Opcodes.PUTSTATIC: 903 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); 904 break; 905 case Opcodes.GETFIELD: 906 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); 907 break; 908 // case Constants.PUTFIELD: 909 default: 910 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); 911 break; 912 } 913 // updates current and max stack sizes 914 if (size > maxStackSize) { 915 maxStackSize = size; 916 } 917 stackSize = size; 918 } 919 } 920 // adds the instruction to the bytecode of the method 921 code.put12(opcode, i.index); 922 } 923 924 @Override 925 public void visitMethodInsn(final int opcode, final String owner, 926 final String name, final String desc, final boolean itf) { 927 lastCodeOffset = code.length; 928 Item i = cw.newMethodItem(owner, name, desc, itf); 929 int argSize = i.intVal; 930 // Label currentBlock = this.currentBlock; 931 if (currentBlock != null) { 932 if (compute == FRAMES || compute == INSERTED_FRAMES) { 933 currentBlock.frame.execute(opcode, 0, cw, i); 934 } else { 935 /* 936 * computes the stack size variation. In order not to recompute 937 * several times this variation for the same Item, we use the 938 * intVal field of this item to store this variation, once it 939 * has been computed. More precisely this intVal field stores 940 * the sizes of the arguments and of the return value 941 * corresponding to desc. 942 */ 943 if (argSize == 0) { 944 // the above sizes have not been computed yet, 945 // so we compute them... 946 argSize = Type.getArgumentsAndReturnSizes(desc); 947 // ... and we save them in order 948 // not to recompute them in the future 949 i.intVal = argSize; 950 } 951 int size; 952 if (opcode == Opcodes.INVOKESTATIC) { 953 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; 954 } else { 955 size = stackSize - (argSize >> 2) + (argSize & 0x03); 956 } 957 // updates current and max stack sizes 958 if (size > maxStackSize) { 959 maxStackSize = size; 960 } 961 stackSize = size; 962 } 963 } 964 // adds the instruction to the bytecode of the method 965 if (opcode == Opcodes.INVOKEINTERFACE) { 966 if (argSize == 0) { 967 argSize = Type.getArgumentsAndReturnSizes(desc); 968 i.intVal = argSize; 969 } 970 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); 971 } else { 972 code.put12(opcode, i.index); 973 } 974 } 975 976 @Override 977 public void visitInvokeDynamicInsn(final String name, final String desc, 978 final Handle bsm, final Object... bsmArgs) { 979 lastCodeOffset = code.length; 980 Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs); 981 int argSize = i.intVal; 982 // Label currentBlock = this.currentBlock; 983 if (currentBlock != null) { 984 if (compute == FRAMES || compute == INSERTED_FRAMES) { 985 currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i); 986 } else { 987 /* 988 * computes the stack size variation. In order not to recompute 989 * several times this variation for the same Item, we use the 990 * intVal field of this item to store this variation, once it 991 * has been computed. More precisely this intVal field stores 992 * the sizes of the arguments and of the return value 993 * corresponding to desc. 994 */ 995 if (argSize == 0) { 996 // the above sizes have not been computed yet, 997 // so we compute them... 998 argSize = Type.getArgumentsAndReturnSizes(desc); 999 // ... and we save them in order 1000 // not to recompute them in the future 1001 i.intVal = argSize; 1002 } 1003 int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; 1004 1005 // updates current and max stack sizes 1006 if (size > maxStackSize) { 1007 maxStackSize = size; 1008 } 1009 stackSize = size; 1010 } 1011 } 1012 // adds the instruction to the bytecode of the method 1013 code.put12(Opcodes.INVOKEDYNAMIC, i.index); 1014 code.putShort(0); 1015 } 1016 1017 @Override 1018 public void visitJumpInsn(int opcode, final Label label) { 1019 boolean isWide = opcode >= 200; // GOTO_W 1020 opcode = isWide ? opcode - 33 : opcode; 1021 lastCodeOffset = code.length; 1022 Label nextInsn = null; 1023 // Label currentBlock = this.currentBlock; 1024 if (currentBlock != null) { 1025 if (compute == FRAMES) { 1026 currentBlock.frame.execute(opcode, 0, null, null); 1027 // 'label' is the target of a jump instruction 1028 label.getFirst().status |= Label.TARGET; 1029 // adds 'label' as a successor of this basic block 1030 addSuccessor(Edge.NORMAL, label); 1031 if (opcode != Opcodes.GOTO) { 1032 // creates a Label for the next basic block 1033 nextInsn = new Label(); 1034 } 1035 } else if (compute == INSERTED_FRAMES) { 1036 currentBlock.frame.execute(opcode, 0, null, null); 1037 } else { 1038 if (opcode == Opcodes.JSR) { 1039 if ((label.status & Label.SUBROUTINE) == 0) { 1040 label.status |= Label.SUBROUTINE; 1041 ++subroutines; 1042 } 1043 currentBlock.status |= Label.JSR; 1044 addSuccessor(stackSize + 1, label); 1045 // creates a Label for the next basic block 1046 nextInsn = new Label(); 1047 /* 1048 * note that, by construction in this method, a JSR block 1049 * has at least two successors in the control flow graph: 1050 * the first one leads the next instruction after the JSR, 1051 * while the second one leads to the JSR target. 1052 */ 1053 } else { 1054 // updates current stack size (max stack size unchanged 1055 // because stack size variation always negative in this 1056 // case) 1057 stackSize += Frame.SIZE[opcode]; 1058 addSuccessor(stackSize, label); 1059 } 1060 } 1061 } 1062 // adds the instruction to the bytecode of the method 1063 if ((label.status & Label.RESOLVED) != 0 1064 && label.position - code.length < Short.MIN_VALUE) { 1065 /* 1066 * case of a backward jump with an offset < -32768. In this case we 1067 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx 1068 * <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is the 1069 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <L> 1070 * designates the instruction just after the GOTO_W. 1071 */ 1072 if (opcode == Opcodes.GOTO) { 1073 code.putByte(200); // GOTO_W 1074 } else if (opcode == Opcodes.JSR) { 1075 code.putByte(201); // JSR_W 1076 } else { 1077 // if the IF instruction is transformed into IFNOT GOTO_W the 1078 // next instruction becomes the target of the IFNOT instruction 1079 if (nextInsn != null) { 1080 nextInsn.status |= Label.TARGET; 1081 } 1082 code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 1083 : opcode ^ 1); 1084 code.putShort(8); // jump offset 1085 // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real 1086 // GOTO_W because we might need to insert a frame just after (as 1087 // the target of the IFNOTxxx jump instruction). 1088 code.putByte(220); 1089 cw.hasAsmInsns = true; 1090 } 1091 label.put(this, code, code.length - 1, true); 1092 } else if (isWide) { 1093 /* 1094 * case of a GOTO_W or JSR_W specified by the user (normally 1095 * ClassReader when used to resize instructions). In this case we 1096 * keep the original instruction. 1097 */ 1098 code.putByte(opcode + 33); 1099 label.put(this, code, code.length - 1, true); 1100 } else { 1101 /* 1102 * case of a backward jump with an offset >= -32768, or of a forward 1103 * jump with, of course, an unknown offset. In these cases we store 1104 * the offset in 2 bytes (which will be increased in 1105 * resizeInstructions, if needed). 1106 */ 1107 code.putByte(opcode); 1108 label.put(this, code, code.length - 1, false); 1109 } 1110 if (currentBlock != null) { 1111 if (nextInsn != null) { 1112 // if the jump instruction is not a GOTO, the next instruction 1113 // is also a successor of this instruction. Calling visitLabel 1114 // adds the label of this next instruction as a successor of the 1115 // current block, and starts a new basic block 1116 visitLabel(nextInsn); 1117 } 1118 if (opcode == Opcodes.GOTO) { 1119 noSuccessor(); 1120 } 1121 } 1122 } 1123 1124 @Override 1125 public void visitLabel(final Label label) { 1126 // resolves previous forward references to label, if any 1127 cw.hasAsmInsns |= label.resolve(this, code.length, code.data); 1128 // updates currentBlock 1129 if ((label.status & Label.DEBUG) != 0) { 1130 return; 1131 } 1132 if (compute == FRAMES) { 1133 if (currentBlock != null) { 1134 if (label.position == currentBlock.position) { 1135 // successive labels, do not start a new basic block 1136 currentBlock.status |= (label.status & Label.TARGET); 1137 label.frame = currentBlock.frame; 1138 return; 1139 } 1140 // ends current block (with one new successor) 1141 addSuccessor(Edge.NORMAL, label); 1142 } 1143 // begins a new current block 1144 currentBlock = label; 1145 if (label.frame == null) { 1146 label.frame = new Frame(); 1147 label.frame.owner = label; 1148 } 1149 // updates the basic block list 1150 if (previousBlock != null) { 1151 if (label.position == previousBlock.position) { 1152 previousBlock.status |= (label.status & Label.TARGET); 1153 label.frame = previousBlock.frame; 1154 currentBlock = previousBlock; 1155 return; 1156 } 1157 previousBlock.successor = label; 1158 } 1159 previousBlock = label; 1160 } else if (compute == INSERTED_FRAMES) { 1161 if (currentBlock == null) { 1162 // This case should happen only once, for the visitLabel call in 1163 // the constructor. Indeed, if compute is equal to 1164 // INSERTED_FRAMES currentBlock can not be set back to null (see 1165 // #noSuccessor). 1166 currentBlock = label; 1167 } else { 1168 // Updates the frame owner so that a correct frame offset is 1169 // computed in visitFrame(Frame). 1170 currentBlock.frame.owner = label; 1171 } 1172 } else if (compute == MAXS) { 1173 if (currentBlock != null) { 1174 // ends current block (with one new successor) 1175 currentBlock.outputStackMax = maxStackSize; 1176 addSuccessor(stackSize, label); 1177 } 1178 // begins a new current block 1179 currentBlock = label; 1180 // resets the relative current and max stack sizes 1181 stackSize = 0; 1182 maxStackSize = 0; 1183 // updates the basic block list 1184 if (previousBlock != null) { 1185 previousBlock.successor = label; 1186 } 1187 previousBlock = label; 1188 } 1189 } 1190 1191 @Override 1192 public void visitLdcInsn(final Object cst) { 1193 lastCodeOffset = code.length; 1194 Item i = cw.newConstItem(cst); 1195 // Label currentBlock = this.currentBlock; 1196 if (currentBlock != null) { 1197 if (compute == FRAMES || compute == INSERTED_FRAMES) { 1198 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); 1199 } else { 1200 int size; 1201 // computes the stack size variation 1202 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { 1203 size = stackSize + 2; 1204 } else { 1205 size = stackSize + 1; 1206 } 1207 // updates current and max stack sizes 1208 if (size > maxStackSize) { 1209 maxStackSize = size; 1210 } 1211 stackSize = size; 1212 } 1213 } 1214 // adds the instruction to the bytecode of the method 1215 int index = i.index; 1216 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { 1217 code.put12(20 /* LDC2_W */, index); 1218 } else if (index >= 256) { 1219 code.put12(19 /* LDC_W */, index); 1220 } else { 1221 code.put11(Opcodes.LDC, index); 1222 } 1223 } 1224 1225 @Override 1226 public void visitIincInsn(final int var, final int increment) { 1227 lastCodeOffset = code.length; 1228 if (currentBlock != null) { 1229 if (compute == FRAMES || compute == INSERTED_FRAMES) { 1230 currentBlock.frame.execute(Opcodes.IINC, var, null, null); 1231 } 1232 } 1233 if (compute != NOTHING) { 1234 // updates max locals 1235 int n = var + 1; 1236 if (n > maxLocals) { 1237 maxLocals = n; 1238 } 1239 } 1240 // adds the instruction to the bytecode of the method 1241 if ((var > 255) || (increment > 127) || (increment < -128)) { 1242 code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var) 1243 .putShort(increment); 1244 } else { 1245 code.putByte(Opcodes.IINC).put11(var, increment); 1246 } 1247 } 1248 1249 @Override 1250 public void visitTableSwitchInsn(final int min, final int max, 1251 final Label dflt, final Label... labels) { 1252 lastCodeOffset = code.length; 1253 // adds the instruction to the bytecode of the method 1254 int source = code.length; 1255 code.putByte(Opcodes.TABLESWITCH); 1256 code.putByteArray(null, 0, (4 - code.length % 4) % 4); 1257 dflt.put(this, code, source, true); 1258 code.putInt(min).putInt(max); 1259 for (int i = 0; i < labels.length; ++i) { 1260 labels[i].put(this, code, source, true); 1261 } 1262 // updates currentBlock 1263 visitSwitchInsn(dflt, labels); 1264 } 1265 1266 @Override 1267 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, 1268 final Label[] labels) { 1269 lastCodeOffset = code.length; 1270 // adds the instruction to the bytecode of the method 1271 int source = code.length; 1272 code.putByte(Opcodes.LOOKUPSWITCH); 1273 code.putByteArray(null, 0, (4 - code.length % 4) % 4); 1274 dflt.put(this, code, source, true); 1275 code.putInt(labels.length); 1276 for (int i = 0; i < labels.length; ++i) { 1277 code.putInt(keys[i]); 1278 labels[i].put(this, code, source, true); 1279 } 1280 // updates currentBlock 1281 visitSwitchInsn(dflt, labels); 1282 } 1283 1284 private void visitSwitchInsn(final Label dflt, final Label[] labels) { 1285 // Label currentBlock = this.currentBlock; 1286 if (currentBlock != null) { 1287 if (compute == FRAMES) { 1288 currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); 1289 // adds current block successors 1290 addSuccessor(Edge.NORMAL, dflt); 1291 dflt.getFirst().status |= Label.TARGET; 1292 for (int i = 0; i < labels.length; ++i) { 1293 addSuccessor(Edge.NORMAL, labels[i]); 1294 labels[i].getFirst().status |= Label.TARGET; 1295 } 1296 } else { 1297 // updates current stack size (max stack size unchanged) 1298 --stackSize; 1299 // adds current block successors 1300 addSuccessor(stackSize, dflt); 1301 for (int i = 0; i < labels.length; ++i) { 1302 addSuccessor(stackSize, labels[i]); 1303 } 1304 } 1305 // ends current block 1306 noSuccessor(); 1307 } 1308 } 1309 1310 @Override 1311 public void visitMultiANewArrayInsn(final String desc, final int dims) { 1312 lastCodeOffset = code.length; 1313 Item i = cw.newStringishItem(ClassWriter.CLASS, desc); 1314 // Label currentBlock = this.currentBlock; 1315 if (currentBlock != null) { 1316 if (compute == FRAMES || compute == INSERTED_FRAMES) { 1317 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); 1318 } else { 1319 // updates current stack size (max stack size unchanged because 1320 // stack size variation always negative or null) 1321 stackSize += 1 - dims; 1322 } 1323 } 1324 // adds the instruction to the bytecode of the method 1325 code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims); 1326 } 1327 1328 @Override 1329 public AnnotationVisitor visitInsnAnnotation(int typeRef, 1330 TypePath typePath, String desc, boolean visible) { 1331 ByteVector bv = new ByteVector(); 1332 // write target_type and target_info 1333 typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8); 1334 AnnotationWriter.putTarget(typeRef, typePath, bv); 1335 // write type, and reserve space for values count 1336 bv.putShort(cw.newUTF8(desc)).putShort(0); 1337 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 1338 bv.length - 2); 1339 if (visible) { 1340 aw.next = ctanns; 1341 ctanns = aw; 1342 } else { 1343 aw.next = ictanns; 1344 ictanns = aw; 1345 } 1346 return aw; 1347 } 1348 1349 @Override 1350 public void visitTryCatchBlock(final Label start, final Label end, 1351 final Label handler, final String type) { 1352 ++handlerCount; 1353 Handler h = new Handler(); 1354 h.start = start; 1355 h.end = end; 1356 h.handler = handler; 1357 h.desc = type; 1358 h.type = type != null ? cw.newClass(type) : 0; 1359 if (lastHandler == null) { 1360 firstHandler = h; 1361 } else { 1362 lastHandler.next = h; 1363 } 1364 lastHandler = h; 1365 } 1366 1367 @Override 1368 public AnnotationVisitor visitTryCatchAnnotation(int typeRef, 1369 TypePath typePath, String desc, boolean visible) { 1370 ByteVector bv = new ByteVector(); 1371 // write target_type and target_info 1372 AnnotationWriter.putTarget(typeRef, typePath, bv); 1373 // write type, and reserve space for values count 1374 bv.putShort(cw.newUTF8(desc)).putShort(0); 1375 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 1376 bv.length - 2); 1377 if (visible) { 1378 aw.next = ctanns; 1379 ctanns = aw; 1380 } else { 1381 aw.next = ictanns; 1382 ictanns = aw; 1383 } 1384 return aw; 1385 } 1386 1387 @Override 1388 public void visitLocalVariable(final String name, final String desc, 1389 final String signature, final Label start, final Label end, 1390 final int index) { 1391 if (signature != null) { 1392 if (localVarType == null) { 1393 localVarType = new ByteVector(); 1394 } 1395 ++localVarTypeCount; 1396 localVarType.putShort(start.position) 1397 .putShort(end.position - start.position) 1398 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature)) 1399 .putShort(index); 1400 } 1401 if (localVar == null) { 1402 localVar = new ByteVector(); 1403 } 1404 ++localVarCount; 1405 localVar.putShort(start.position) 1406 .putShort(end.position - start.position) 1407 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc)) 1408 .putShort(index); 1409 if (compute != NOTHING) { 1410 // updates max locals 1411 char c = desc.charAt(0); 1412 int n = index + (c == 'J' || c == 'D' ? 2 : 1); 1413 if (n > maxLocals) { 1414 maxLocals = n; 1415 } 1416 } 1417 } 1418 1419 @Override 1420 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, 1421 TypePath typePath, Label[] start, Label[] end, int[] index, 1422 String desc, boolean visible) { 1423 ByteVector bv = new ByteVector(); 1424 // write target_type and target_info 1425 bv.putByte(typeRef >>> 24).putShort(start.length); 1426 for (int i = 0; i < start.length; ++i) { 1427 bv.putShort(start[i].position) 1428 .putShort(end[i].position - start[i].position) 1429 .putShort(index[i]); 1430 } 1431 if (typePath == null) { 1432 bv.putByte(0); 1433 } else { 1434 int length = typePath.b[typePath.offset] * 2 + 1; 1435 bv.putByteArray(typePath.b, typePath.offset, length); 1436 } 1437 // write type, and reserve space for values count 1438 bv.putShort(cw.newUTF8(desc)).putShort(0); 1439 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 1440 bv.length - 2); 1441 if (visible) { 1442 aw.next = ctanns; 1443 ctanns = aw; 1444 } else { 1445 aw.next = ictanns; 1446 ictanns = aw; 1447 } 1448 return aw; 1449 } 1450 1451 @Override 1452 public void visitLineNumber(final int line, final Label start) { 1453 if (lineNumber == null) { 1454 lineNumber = new ByteVector(); 1455 } 1456 ++lineNumberCount; 1457 lineNumber.putShort(start.position); 1458 lineNumber.putShort(line); 1459 } 1460 1461 @Override 1462 public void visitMaxs(final int maxStack, final int maxLocals) { 1463 if (compute == FRAMES) { 1464 // completes the control flow graph with exception handler blocks 1465 Handler handler = firstHandler; 1466 while (handler != null) { 1467 Label l = handler.start.getFirst(); 1468 Label h = handler.handler.getFirst(); 1469 Label e = handler.end.getFirst(); 1470 // computes the kind of the edges to 'h' 1471 String t = handler.desc == null ? "java/lang/Throwable" 1472 : handler.desc; 1473 int kind = Frame.OBJECT | cw.addType(t); 1474 // h is an exception handler 1475 h.status |= Label.TARGET; 1476 // adds 'h' as a successor of labels between 'start' and 'end' 1477 while (l != e) { 1478 // creates an edge to 'h' 1479 Edge b = new Edge(); 1480 b.info = kind; 1481 b.successor = h; 1482 // adds it to the successors of 'l' 1483 b.next = l.successors; 1484 l.successors = b; 1485 // goes to the next label 1486 l = l.successor; 1487 } 1488 handler = handler.next; 1489 } 1490 1491 // creates and visits the first (implicit) frame 1492 Frame f = labels.frame; 1493 f.initInputFrame(cw, access, Type.getArgumentTypes(descriptor), 1494 this.maxLocals); 1495 visitFrame(f); 1496 1497 /* 1498 * fix point algorithm: mark the first basic block as 'changed' 1499 * (i.e. put it in the 'changed' list) and, while there are changed 1500 * basic blocks, choose one, mark it as unchanged, and update its 1501 * successors (which can be changed in the process). 1502 */ 1503 int max = 0; 1504 Label changed = labels; 1505 while (changed != null) { 1506 // removes a basic block from the list of changed basic blocks 1507 Label l = changed; 1508 changed = changed.next; 1509 l.next = null; 1510 f = l.frame; 1511 // a reachable jump target must be stored in the stack map 1512 if ((l.status & Label.TARGET) != 0) { 1513 l.status |= Label.STORE; 1514 } 1515 // all visited labels are reachable, by definition 1516 l.status |= Label.REACHABLE; 1517 // updates the (absolute) maximum stack size 1518 int blockMax = f.inputStack.length + l.outputStackMax; 1519 if (blockMax > max) { 1520 max = blockMax; 1521 } 1522 // updates the successors of the current basic block 1523 Edge e = l.successors; 1524 while (e != null) { 1525 Label n = e.successor.getFirst(); 1526 boolean change = f.merge(cw, n.frame, e.info); 1527 if (change && n.next == null) { 1528 // if n has changed and is not already in the 'changed' 1529 // list, adds it to this list 1530 n.next = changed; 1531 changed = n; 1532 } 1533 e = e.next; 1534 } 1535 } 1536 1537 // visits all the frames that must be stored in the stack map 1538 Label l = labels; 1539 while (l != null) { 1540 f = l.frame; 1541 if ((l.status & Label.STORE) != 0) { 1542 visitFrame(f); 1543 } 1544 if ((l.status & Label.REACHABLE) == 0) { 1545 // finds start and end of dead basic block 1546 Label k = l.successor; 1547 int start = l.position; 1548 int end = (k == null ? code.length : k.position) - 1; 1549 // if non empty basic block 1550 if (end >= start) { 1551 max = Math.max(max, 1); 1552 // replaces instructions with NOP ... NOP ATHROW 1553 for (int i = start; i < end; ++i) { 1554 code.data[i] = Opcodes.NOP; 1555 } 1556 code.data[end] = (byte) Opcodes.ATHROW; 1557 // emits a frame for this unreachable block 1558 int frameIndex = startFrame(start, 0, 1); 1559 frame[frameIndex] = Frame.OBJECT 1560 | cw.addType("java/lang/Throwable"); 1561 endFrame(); 1562 // removes the start-end range from the exception 1563 // handlers 1564 firstHandler = Handler.remove(firstHandler, l, k); 1565 } 1566 } 1567 l = l.successor; 1568 } 1569 1570 handler = firstHandler; 1571 handlerCount = 0; 1572 while (handler != null) { 1573 handlerCount += 1; 1574 handler = handler.next; 1575 } 1576 1577 this.maxStack = max; 1578 } else if (compute == MAXS) { 1579 // completes the control flow graph with exception handler blocks 1580 Handler handler = firstHandler; 1581 while (handler != null) { 1582 Label l = handler.start; 1583 Label h = handler.handler; 1584 Label e = handler.end; 1585 // adds 'h' as a successor of labels between 'start' and 'end' 1586 while (l != e) { 1587 // creates an edge to 'h' 1588 Edge b = new Edge(); 1589 b.info = Edge.EXCEPTION; 1590 b.successor = h; 1591 // adds it to the successors of 'l' 1592 if ((l.status & Label.JSR) == 0) { 1593 b.next = l.successors; 1594 l.successors = b; 1595 } else { 1596 // if l is a JSR block, adds b after the first two edges 1597 // to preserve the hypothesis about JSR block successors 1598 // order (see {@link #visitJumpInsn}) 1599 b.next = l.successors.next.next; 1600 l.successors.next.next = b; 1601 } 1602 // goes to the next label 1603 l = l.successor; 1604 } 1605 handler = handler.next; 1606 } 1607 1608 if (subroutines > 0) { 1609 // completes the control flow graph with the RET successors 1610 /* 1611 * first step: finds the subroutines. This step determines, for 1612 * each basic block, to which subroutine(s) it belongs. 1613 */ 1614 // finds the basic blocks that belong to the "main" subroutine 1615 int id = 0; 1616 labels.visitSubroutine(null, 1, subroutines); 1617 // finds the basic blocks that belong to the real subroutines 1618 Label l = labels; 1619 while (l != null) { 1620 if ((l.status & Label.JSR) != 0) { 1621 // the subroutine is defined by l's TARGET, not by l 1622 Label subroutine = l.successors.next.successor; 1623 // if this subroutine has not been visited yet... 1624 if ((subroutine.status & Label.VISITED) == 0) { 1625 // ...assigns it a new id and finds its basic blocks 1626 id += 1; 1627 subroutine.visitSubroutine(null, (id / 32L) << 32 1628 | (1L << (id % 32)), subroutines); 1629 } 1630 } 1631 l = l.successor; 1632 } 1633 // second step: finds the successors of RET blocks 1634 l = labels; 1635 while (l != null) { 1636 if ((l.status & Label.JSR) != 0) { 1637 Label L = labels; 1638 while (L != null) { 1639 L.status &= ~Label.VISITED2; 1640 L = L.successor; 1641 } 1642 // the subroutine is defined by l's TARGET, not by l 1643 Label subroutine = l.successors.next.successor; 1644 subroutine.visitSubroutine(l, 0, subroutines); 1645 } 1646 l = l.successor; 1647 } 1648 } 1649 1650 /* 1651 * control flow analysis algorithm: while the block stack is not 1652 * empty, pop a block from this stack, update the max stack size, 1653 * compute the true (non relative) begin stack size of the 1654 * successors of this block, and push these successors onto the 1655 * stack (unless they have already been pushed onto the stack). 1656 * Note: by hypothesis, the {@link Label#inputStackTop} of the 1657 * blocks in the block stack are the true (non relative) beginning 1658 * stack sizes of these blocks. 1659 */ 1660 int max = 0; 1661 Label stack = labels; 1662 while (stack != null) { 1663 // pops a block from the stack 1664 Label l = stack; 1665 stack = stack.next; 1666 // computes the true (non relative) max stack size of this block 1667 int start = l.inputStackTop; 1668 int blockMax = start + l.outputStackMax; 1669 // updates the global max stack size 1670 if (blockMax > max) { 1671 max = blockMax; 1672 } 1673 // analyzes the successors of the block 1674 Edge b = l.successors; 1675 if ((l.status & Label.JSR) != 0) { 1676 // ignores the first edge of JSR blocks (virtual successor) 1677 b = b.next; 1678 } 1679 while (b != null) { 1680 l = b.successor; 1681 // if this successor has not already been pushed... 1682 if ((l.status & Label.PUSHED) == 0) { 1683 // computes its true beginning stack size... 1684 l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start 1685 + b.info; 1686 // ...and pushes it onto the stack 1687 l.status |= Label.PUSHED; 1688 l.next = stack; 1689 stack = l; 1690 } 1691 b = b.next; 1692 } 1693 } 1694 this.maxStack = Math.max(maxStack, max); 1695 } else { 1696 this.maxStack = maxStack; 1697 this.maxLocals = maxLocals; 1698 } 1699 } 1700 1701 @Override 1702 public void visitEnd() { 1703 } 1704 1705 // ------------------------------------------------------------------------ 1706 // Utility methods: control flow analysis algorithm 1707 // ------------------------------------------------------------------------ 1708 1709 /** 1710 * Adds a successor to the {@link #currentBlock currentBlock} block. 1711 * 1712 * @param info 1713 * information about the control flow edge to be added. 1714 * @param successor 1715 * the successor block to be added to the current block. 1716 */ 1717 private void addSuccessor(final int info, final Label successor) { 1718 // creates and initializes an Edge object... 1719 Edge b = new Edge(); 1720 b.info = info; 1721 b.successor = successor; 1722 // ...and adds it to the successor list of the currentBlock block 1723 b.next = currentBlock.successors; 1724 currentBlock.successors = b; 1725 } 1726 1727 /** 1728 * Ends the current basic block. This method must be used in the case where 1729 * the current basic block does not have any successor. 1730 */ 1731 private void noSuccessor() { 1732 if (compute == FRAMES) { 1733 Label l = new Label(); 1734 l.frame = new Frame(); 1735 l.frame.owner = l; 1736 l.resolve(this, code.length, code.data); 1737 previousBlock.successor = l; 1738 previousBlock = l; 1739 } else { 1740 currentBlock.outputStackMax = maxStackSize; 1741 } 1742 if (compute != INSERTED_FRAMES) { 1743 currentBlock = null; 1744 } 1745 } 1746 1747 // ------------------------------------------------------------------------ 1748 // Utility methods: stack map frames 1749 // ------------------------------------------------------------------------ 1750 1751 /** 1752 * Visits a frame that has been computed from scratch. 1753 * 1754 * @param f 1755 * the frame that must be visited. 1756 */ 1757 private void visitFrame(final Frame f) { 1758 int i, t; 1759 int nTop = 0; 1760 int nLocal = 0; 1761 int nStack = 0; 1762 int[] locals = f.inputLocals; 1763 int[] stacks = f.inputStack; 1764 // computes the number of locals (ignores TOP types that are just after 1765 // a LONG or a DOUBLE, and all trailing TOP types) 1766 for (i = 0; i < locals.length; ++i) { 1767 t = locals[i]; 1768 if (t == Frame.TOP) { 1769 ++nTop; 1770 } else { 1771 nLocal += nTop + 1; 1772 nTop = 0; 1773 } 1774 if (t == Frame.LONG || t == Frame.DOUBLE) { 1775 ++i; 1776 } 1777 } 1778 // computes the stack size (ignores TOP types that are just after 1779 // a LONG or a DOUBLE) 1780 for (i = 0; i < stacks.length; ++i) { 1781 t = stacks[i]; 1782 ++nStack; 1783 if (t == Frame.LONG || t == Frame.DOUBLE) { 1784 ++i; 1785 } 1786 } 1787 // visits the frame and its content 1788 int frameIndex = startFrame(f.owner.position, nLocal, nStack); 1789 for (i = 0; nLocal > 0; ++i, --nLocal) { 1790 t = locals[i]; 1791 frame[frameIndex++] = t; 1792 if (t == Frame.LONG || t == Frame.DOUBLE) { 1793 ++i; 1794 } 1795 } 1796 for (i = 0; i < stacks.length; ++i) { 1797 t = stacks[i]; 1798 frame[frameIndex++] = t; 1799 if (t == Frame.LONG || t == Frame.DOUBLE) { 1800 ++i; 1801 } 1802 } 1803 endFrame(); 1804 } 1805 1806 /** 1807 * Visit the implicit first frame of this method. 1808 */ 1809 private void visitImplicitFirstFrame() { 1810 // There can be at most descriptor.length() + 1 locals 1811 int frameIndex = startFrame(0, descriptor.length() + 1, 0); 1812 if ((access & Opcodes.ACC_STATIC) == 0) { 1813 if ((access & ACC_CONSTRUCTOR) == 0) { 1814 frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); 1815 } else { 1816 frame[frameIndex++] = Frame.UNINITIALIZED_THIS; 1817 } 1818 } 1819 int i = 1; 1820 loop: while (true) { 1821 int j = i; 1822 switch (descriptor.charAt(i++)) { 1823 case 'Z': 1824 case 'C': 1825 case 'B': 1826 case 'S': 1827 case 'I': 1828 frame[frameIndex++] = Frame.INTEGER; 1829 break; 1830 case 'F': 1831 frame[frameIndex++] = Frame.FLOAT; 1832 break; 1833 case 'J': 1834 frame[frameIndex++] = Frame.LONG; 1835 break; 1836 case 'D': 1837 frame[frameIndex++] = Frame.DOUBLE; 1838 break; 1839 case '[': 1840 while (descriptor.charAt(i) == '[') { 1841 ++i; 1842 } 1843 if (descriptor.charAt(i) == 'L' || descriptor.charAt(i) == 'Q') { 1844 ++i; 1845 while (descriptor.charAt(i) != ';') { 1846 ++i; 1847 } 1848 } 1849 frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i)); 1850 break; 1851 case 'L': 1852 case 'Q': 1853 while (descriptor.charAt(i) != ';') { 1854 ++i; 1855 } 1856 frame[frameIndex++] = Frame.OBJECT 1857 | cw.addType(descriptor.substring(j + 1, i++)); 1858 break; 1859 default: 1860 break loop; 1861 } 1862 } 1863 frame[1] = frameIndex - 3; 1864 endFrame(); 1865 } 1866 1867 /** 1868 * Starts the visit of a stack map frame. 1869 * 1870 * @param offset 1871 * the offset of the instruction to which the frame corresponds. 1872 * @param nLocal 1873 * the number of local variables in the frame. 1874 * @param nStack 1875 * the number of stack elements in the frame. 1876 * @return the index of the next element to be written in this frame. 1877 */ 1878 private int startFrame(final int offset, final int nLocal, final int nStack) { 1879 int n = 3 + nLocal + nStack; 1880 if (frame == null || frame.length < n) { 1881 frame = new int[n]; 1882 } 1883 frame[0] = offset; 1884 frame[1] = nLocal; 1885 frame[2] = nStack; 1886 return 3; 1887 } 1888 1889 /** 1890 * Checks if the visit of the current frame {@link #frame} is finished, and 1891 * if yes, write it in the StackMapTable attribute. 1892 */ 1893 private void endFrame() { 1894 if (previousFrame != null) { // do not write the first frame 1895 if (stackMap == null) { 1896 stackMap = new ByteVector(); 1897 } 1898 writeFrame(); 1899 ++frameCount; 1900 } 1901 previousFrame = frame; 1902 frame = null; 1903 } 1904 1905 /** 1906 * Compress and writes the current frame {@link #frame} in the StackMapTable 1907 * attribute. 1908 */ 1909 private void writeFrame() { 1910 int clocalsSize = frame[1]; 1911 int cstackSize = frame[2]; 1912 if ((cw.version & 0xFFFF) < Opcodes.V1_6) { 1913 stackMap.putShort(frame[0]).putShort(clocalsSize); 1914 writeFrameTypes(3, 3 + clocalsSize); 1915 stackMap.putShort(cstackSize); 1916 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); 1917 return; 1918 } 1919 int localsSize = previousFrame[1]; 1920 int type = FULL_FRAME; 1921 int k = 0; 1922 int delta; 1923 if (frameCount == 0) { 1924 delta = frame[0]; 1925 } else { 1926 delta = frame[0] - previousFrame[0] - 1; 1927 } 1928 if (cstackSize == 0) { 1929 k = clocalsSize - localsSize; 1930 switch (k) { 1931 case -3: 1932 case -2: 1933 case -1: 1934 type = CHOP_FRAME; 1935 localsSize = clocalsSize; 1936 break; 1937 case 0: 1938 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; 1939 break; 1940 case 1: 1941 case 2: 1942 case 3: 1943 type = APPEND_FRAME; 1944 break; 1945 } 1946 } else if (clocalsSize == localsSize && cstackSize == 1) { 1947 type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME 1948 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 1949 } 1950 if (type != FULL_FRAME) { 1951 // verify if locals are the same 1952 int l = 3; 1953 for (int j = 0; j < localsSize; j++) { 1954 if (frame[l] != previousFrame[l]) { 1955 type = FULL_FRAME; 1956 break; 1957 } 1958 l++; 1959 } 1960 } 1961 switch (type) { 1962 case SAME_FRAME: 1963 stackMap.putByte(delta); 1964 break; 1965 case SAME_LOCALS_1_STACK_ITEM_FRAME: 1966 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); 1967 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); 1968 break; 1969 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: 1970 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort( 1971 delta); 1972 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); 1973 break; 1974 case SAME_FRAME_EXTENDED: 1975 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); 1976 break; 1977 case CHOP_FRAME: 1978 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); 1979 break; 1980 case APPEND_FRAME: 1981 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); 1982 writeFrameTypes(3 + localsSize, 3 + clocalsSize); 1983 break; 1984 // case FULL_FRAME: 1985 default: 1986 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); 1987 writeFrameTypes(3, 3 + clocalsSize); 1988 stackMap.putShort(cstackSize); 1989 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); 1990 } 1991 } 1992 1993 /** 1994 * Writes some types of the current frame {@link #frame} into the 1995 * StackMapTableAttribute. This method converts types from the format used 1996 * in {@link Label} to the format used in StackMapTable attributes. In 1997 * particular, it converts type table indexes to constant pool indexes. 1998 * 1999 * @param start 2000 * index of the first type in {@link #frame} to write. 2001 * @param end 2002 * index of last type in {@link #frame} to write (exclusive). 2003 */ 2004 private void writeFrameTypes(final int start, final int end) { 2005 for (int i = start; i < end; ++i) { 2006 int t = frame[i]; 2007 int d = t & Frame.DIM; 2008 if (d == 0) { 2009 int v = t & Frame.BASE_VALUE; 2010 switch (t & Frame.BASE_KIND) { 2011 case Frame.OBJECT: 2012 stackMap.putByte(7).putShort( 2013 cw.newClass(cw.typeTable[v].strVal1)); 2014 break; 2015 case Frame.UNINITIALIZED: 2016 stackMap.putByte(8).putShort(cw.typeTable[v].intVal); 2017 break; 2018 default: 2019 stackMap.putByte(v); 2020 } 2021 } else { 2022 StringBuilder sb = new StringBuilder(); 2023 d >>= 28; 2024 while (d-- > 0) { 2025 sb.append('['); 2026 } 2027 if ((t & Frame.BASE_KIND) == Frame.OBJECT) { 2028 sb.append('L'); 2029 sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); 2030 sb.append(';'); 2031 } else { 2032 switch (t & 0xF) { 2033 case 1: 2034 sb.append('I'); 2035 break; 2036 case 2: 2037 sb.append('F'); 2038 break; 2039 case 3: 2040 sb.append('D'); 2041 break; 2042 case 9: 2043 sb.append('Z'); 2044 break; 2045 case 10: 2046 sb.append('B'); 2047 break; 2048 case 11: 2049 sb.append('C'); 2050 break; 2051 case 12: 2052 sb.append('S'); 2053 break; 2054 default: 2055 sb.append('J'); 2056 } 2057 } 2058 stackMap.putByte(7).putShort(cw.newClass(sb.toString())); 2059 } 2060 } 2061 } 2062 2063 private void writeFrameType(final Object type) { 2064 if (type instanceof String) { 2065 stackMap.putByte(7).putShort(cw.newClass((String) type)); 2066 } else if (type instanceof Integer) { 2067 stackMap.putByte(((Integer) type).intValue()); 2068 } else { 2069 stackMap.putByte(8).putShort(((Label) type).position); 2070 } 2071 } 2072 2073 // ------------------------------------------------------------------------ 2074 // Utility methods: dump bytecode array 2075 // ------------------------------------------------------------------------ 2076 2077 /** 2078 * Returns the size of the bytecode of this method. 2079 * 2080 * @return the size of the bytecode of this method. 2081 */ 2082 final int getSize() { 2083 if (classReaderOffset != 0) { 2084 return 6 + classReaderLength; 2085 } 2086 int size = 8; 2087 if (code.length > 0) { 2088 if (code.length > 65535) { 2089 throw new RuntimeException("Method code too large!"); 2090 } 2091 cw.newUTF8("Code"); 2092 size += 18 + code.length + 8 * handlerCount; 2093 if (localVar != null) { 2094 cw.newUTF8("LocalVariableTable"); 2095 size += 8 + localVar.length; 2096 } 2097 if (localVarType != null) { 2098 cw.newUTF8("LocalVariableTypeTable"); 2099 size += 8 + localVarType.length; 2100 } 2101 if (lineNumber != null) { 2102 cw.newUTF8("LineNumberTable"); 2103 size += 8 + lineNumber.length; 2104 } 2105 if (stackMap != null) { 2106 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; 2107 cw.newUTF8(zip ? "StackMapTable" : "StackMap"); 2108 size += 8 + stackMap.length; 2109 } 2110 if (ctanns != null) { 2111 cw.newUTF8("RuntimeVisibleTypeAnnotations"); 2112 size += 8 + ctanns.getSize(); 2113 } 2114 if (ictanns != null) { 2115 cw.newUTF8("RuntimeInvisibleTypeAnnotations"); 2116 size += 8 + ictanns.getSize(); 2117 } 2118 if (cattrs != null) { 2119 size += cattrs.getSize(cw, code.data, code.length, maxStack, 2120 maxLocals); 2121 } 2122 } 2123 if (exceptionCount > 0) { 2124 cw.newUTF8("Exceptions"); 2125 size += 8 + 2 * exceptionCount; 2126 } 2127 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 2128 if ((cw.version & 0xFFFF) < Opcodes.V1_5 2129 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { 2130 cw.newUTF8("Synthetic"); 2131 size += 6; 2132 } 2133 } 2134 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 2135 cw.newUTF8("Deprecated"); 2136 size += 6; 2137 } 2138 if (signature != null) { 2139 cw.newUTF8("Signature"); 2140 cw.newUTF8(signature); 2141 size += 8; 2142 } 2143 if (methodParameters != null) { 2144 cw.newUTF8("MethodParameters"); 2145 size += 7 + methodParameters.length; 2146 } 2147 if (annd != null) { 2148 cw.newUTF8("AnnotationDefault"); 2149 size += 6 + annd.length; 2150 } 2151 if (anns != null) { 2152 cw.newUTF8("RuntimeVisibleAnnotations"); 2153 size += 8 + anns.getSize(); 2154 } 2155 if (ianns != null) { 2156 cw.newUTF8("RuntimeInvisibleAnnotations"); 2157 size += 8 + ianns.getSize(); 2158 } 2159 if (tanns != null) { 2160 cw.newUTF8("RuntimeVisibleTypeAnnotations"); 2161 size += 8 + tanns.getSize(); 2162 } 2163 if (itanns != null) { 2164 cw.newUTF8("RuntimeInvisibleTypeAnnotations"); 2165 size += 8 + itanns.getSize(); 2166 } 2167 if (panns != null) { 2168 cw.newUTF8("RuntimeVisibleParameterAnnotations"); 2169 size += 7 + 2 * (panns.length - synthetics); 2170 for (int i = panns.length - 1; i >= synthetics; --i) { 2171 size += panns[i] == null ? 0 : panns[i].getSize(); 2172 } 2173 } 2174 if (ipanns != null) { 2175 cw.newUTF8("RuntimeInvisibleParameterAnnotations"); 2176 size += 7 + 2 * (ipanns.length - synthetics); 2177 for (int i = ipanns.length - 1; i >= synthetics; --i) { 2178 size += ipanns[i] == null ? 0 : ipanns[i].getSize(); 2179 } 2180 } 2181 if (attrs != null) { 2182 size += attrs.getSize(cw, null, 0, -1, -1); 2183 } 2184 return size; 2185 } 2186 2187 /** 2188 * Puts the bytecode of this method in the given byte vector. 2189 * 2190 * @param out 2191 * the byte vector into which the bytecode of this method must be 2192 * copied. 2193 */ 2194 final void put(final ByteVector out) { 2195 final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; 2196 int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED 2197 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE 2198 | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); 2199 out.putShort(access & ~mask).putShort(name).putShort(desc); 2200 if (classReaderOffset != 0) { 2201 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); 2202 return; 2203 } 2204 int attributeCount = 0; 2205 if (code.length > 0) { 2206 ++attributeCount; 2207 } 2208 if (exceptionCount > 0) { 2209 ++attributeCount; 2210 } 2211 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 2212 if ((cw.version & 0xFFFF) < Opcodes.V1_5 2213 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { 2214 ++attributeCount; 2215 } 2216 } 2217 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 2218 ++attributeCount; 2219 } 2220 if (signature != null) { 2221 ++attributeCount; 2222 } 2223 if (methodParameters != null) { 2224 ++attributeCount; 2225 } 2226 if (annd != null) { 2227 ++attributeCount; 2228 } 2229 if (anns != null) { 2230 ++attributeCount; 2231 } 2232 if (ianns != null) { 2233 ++attributeCount; 2234 } 2235 if (tanns != null) { 2236 ++attributeCount; 2237 } 2238 if (itanns != null) { 2239 ++attributeCount; 2240 } 2241 if (panns != null) { 2242 ++attributeCount; 2243 } 2244 if (ipanns != null) { 2245 ++attributeCount; 2246 } 2247 if (attrs != null) { 2248 attributeCount += attrs.getCount(); 2249 } 2250 out.putShort(attributeCount); 2251 if (code.length > 0) { 2252 int size = 12 + code.length + 8 * handlerCount; 2253 if (localVar != null) { 2254 size += 8 + localVar.length; 2255 } 2256 if (localVarType != null) { 2257 size += 8 + localVarType.length; 2258 } 2259 if (lineNumber != null) { 2260 size += 8 + lineNumber.length; 2261 } 2262 if (stackMap != null) { 2263 size += 8 + stackMap.length; 2264 } 2265 if (ctanns != null) { 2266 size += 8 + ctanns.getSize(); 2267 } 2268 if (ictanns != null) { 2269 size += 8 + ictanns.getSize(); 2270 } 2271 if (cattrs != null) { 2272 size += cattrs.getSize(cw, code.data, code.length, maxStack, 2273 maxLocals); 2274 } 2275 out.putShort(cw.newUTF8("Code")).putInt(size); 2276 out.putShort(maxStack).putShort(maxLocals); 2277 out.putInt(code.length).putByteArray(code.data, 0, code.length); 2278 out.putShort(handlerCount); 2279 if (handlerCount > 0) { 2280 Handler h = firstHandler; 2281 while (h != null) { 2282 out.putShort(h.start.position).putShort(h.end.position) 2283 .putShort(h.handler.position).putShort(h.type); 2284 h = h.next; 2285 } 2286 } 2287 attributeCount = 0; 2288 if (localVar != null) { 2289 ++attributeCount; 2290 } 2291 if (localVarType != null) { 2292 ++attributeCount; 2293 } 2294 if (lineNumber != null) { 2295 ++attributeCount; 2296 } 2297 if (stackMap != null) { 2298 ++attributeCount; 2299 } 2300 if (ctanns != null) { 2301 ++attributeCount; 2302 } 2303 if (ictanns != null) { 2304 ++attributeCount; 2305 } 2306 if (cattrs != null) { 2307 attributeCount += cattrs.getCount(); 2308 } 2309 out.putShort(attributeCount); 2310 if (localVar != null) { 2311 out.putShort(cw.newUTF8("LocalVariableTable")); 2312 out.putInt(localVar.length + 2).putShort(localVarCount); 2313 out.putByteArray(localVar.data, 0, localVar.length); 2314 } 2315 if (localVarType != null) { 2316 out.putShort(cw.newUTF8("LocalVariableTypeTable")); 2317 out.putInt(localVarType.length + 2).putShort(localVarTypeCount); 2318 out.putByteArray(localVarType.data, 0, localVarType.length); 2319 } 2320 if (lineNumber != null) { 2321 out.putShort(cw.newUTF8("LineNumberTable")); 2322 out.putInt(lineNumber.length + 2).putShort(lineNumberCount); 2323 out.putByteArray(lineNumber.data, 0, lineNumber.length); 2324 } 2325 if (stackMap != null) { 2326 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; 2327 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); 2328 out.putInt(stackMap.length + 2).putShort(frameCount); 2329 out.putByteArray(stackMap.data, 0, stackMap.length); 2330 } 2331 if (ctanns != null) { 2332 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); 2333 ctanns.put(out); 2334 } 2335 if (ictanns != null) { 2336 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); 2337 ictanns.put(out); 2338 } 2339 if (cattrs != null) { 2340 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); 2341 } 2342 } 2343 if (exceptionCount > 0) { 2344 out.putShort(cw.newUTF8("Exceptions")).putInt( 2345 2 * exceptionCount + 2); 2346 out.putShort(exceptionCount); 2347 for (int i = 0; i < exceptionCount; ++i) { 2348 out.putShort(exceptions[i]); 2349 } 2350 } 2351 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 2352 if ((cw.version & 0xFFFF) < Opcodes.V1_5 2353 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { 2354 out.putShort(cw.newUTF8("Synthetic")).putInt(0); 2355 } 2356 } 2357 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 2358 out.putShort(cw.newUTF8("Deprecated")).putInt(0); 2359 } 2360 if (signature != null) { 2361 out.putShort(cw.newUTF8("Signature")).putInt(2) 2362 .putShort(cw.newUTF8(signature)); 2363 } 2364 if (methodParameters != null) { 2365 out.putShort(cw.newUTF8("MethodParameters")); 2366 out.putInt(methodParameters.length + 1).putByte( 2367 methodParametersCount); 2368 out.putByteArray(methodParameters.data, 0, methodParameters.length); 2369 } 2370 if (annd != null) { 2371 out.putShort(cw.newUTF8("AnnotationDefault")); 2372 out.putInt(annd.length); 2373 out.putByteArray(annd.data, 0, annd.length); 2374 } 2375 if (anns != null) { 2376 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); 2377 anns.put(out); 2378 } 2379 if (ianns != null) { 2380 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); 2381 ianns.put(out); 2382 } 2383 if (tanns != null) { 2384 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); 2385 tanns.put(out); 2386 } 2387 if (itanns != null) { 2388 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); 2389 itanns.put(out); 2390 } 2391 if (panns != null) { 2392 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); 2393 AnnotationWriter.put(panns, synthetics, out); 2394 } 2395 if (ipanns != null) { 2396 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); 2397 AnnotationWriter.put(ipanns, synthetics, out); 2398 } 2399 if (attrs != null) { 2400 attrs.put(cw, null, 0, -1, -1, out); 2401 } 2402 } 2403 }