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') { 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 while (descriptor.charAt(i) != ';') { 1853 ++i; 1854 } 1855 frame[frameIndex++] = Frame.OBJECT 1856 | cw.addType(descriptor.substring(j + 1, i++)); 1857 break; 1858 default: 1859 break loop; 1860 } 1861 } 1862 frame[1] = frameIndex - 3; 1863 endFrame(); 1864 } 1865 1866 /** 1867 * Starts the visit of a stack map frame. 1868 * 1869 * @param offset 1870 * the offset of the instruction to which the frame corresponds. 1871 * @param nLocal 1872 * the number of local variables in the frame. 1873 * @param nStack 1874 * the number of stack elements in the frame. 1875 * @return the index of the next element to be written in this frame. 1876 */ 1877 private int startFrame(final int offset, final int nLocal, final int nStack) { 1878 int n = 3 + nLocal + nStack; 1879 if (frame == null || frame.length < n) { 1880 frame = new int[n]; 1881 } 1882 frame[0] = offset; 1883 frame[1] = nLocal; 1884 frame[2] = nStack; 1885 return 3; 1886 } 1887 1888 /** 1889 * Checks if the visit of the current frame {@link #frame} is finished, and 1890 * if yes, write it in the StackMapTable attribute. 1891 */ 1892 private void endFrame() { 1893 if (previousFrame != null) { // do not write the first frame 1894 if (stackMap == null) { 1895 stackMap = new ByteVector(); 1896 } 1897 writeFrame(); 1898 ++frameCount; 1899 } 1900 previousFrame = frame; 1901 frame = null; 1902 } 1903 1904 /** 1905 * Compress and writes the current frame {@link #frame} in the StackMapTable 1906 * attribute. 1907 */ 1908 private void writeFrame() { 1909 int clocalsSize = frame[1]; 1910 int cstackSize = frame[2]; 1911 if ((cw.version & 0xFFFF) < Opcodes.V1_6) { 1912 stackMap.putShort(frame[0]).putShort(clocalsSize); 1913 writeFrameTypes(3, 3 + clocalsSize); 1914 stackMap.putShort(cstackSize); 1915 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); 1916 return; 1917 } 1918 int localsSize = previousFrame[1]; 1919 int type = FULL_FRAME; 1920 int k = 0; 1921 int delta; 1922 if (frameCount == 0) { 1923 delta = frame[0]; 1924 } else { 1925 delta = frame[0] - previousFrame[0] - 1; 1926 } 1927 if (cstackSize == 0) { 1928 k = clocalsSize - localsSize; 1929 switch (k) { 1930 case -3: 1931 case -2: 1932 case -1: 1933 type = CHOP_FRAME; 1934 localsSize = clocalsSize; 1935 break; 1936 case 0: 1937 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; 1938 break; 1939 case 1: 1940 case 2: 1941 case 3: 1942 type = APPEND_FRAME; 1943 break; 1944 } 1945 } else if (clocalsSize == localsSize && cstackSize == 1) { 1946 type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME 1947 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 1948 } 1949 if (type != FULL_FRAME) { 1950 // verify if locals are the same 1951 int l = 3; 1952 for (int j = 0; j < localsSize; j++) { 1953 if (frame[l] != previousFrame[l]) { 1954 type = FULL_FRAME; 1955 break; 1956 } 1957 l++; 1958 } 1959 } 1960 switch (type) { 1961 case SAME_FRAME: 1962 stackMap.putByte(delta); 1963 break; 1964 case SAME_LOCALS_1_STACK_ITEM_FRAME: 1965 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); 1966 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); 1967 break; 1968 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: 1969 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort( 1970 delta); 1971 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); 1972 break; 1973 case SAME_FRAME_EXTENDED: 1974 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); 1975 break; 1976 case CHOP_FRAME: 1977 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); 1978 break; 1979 case APPEND_FRAME: 1980 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); 1981 writeFrameTypes(3 + localsSize, 3 + clocalsSize); 1982 break; 1983 // case FULL_FRAME: 1984 default: 1985 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); 1986 writeFrameTypes(3, 3 + clocalsSize); 1987 stackMap.putShort(cstackSize); 1988 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); 1989 } 1990 } 1991 1992 /** 1993 * Writes some types of the current frame {@link #frame} into the 1994 * StackMapTableAttribute. This method converts types from the format used 1995 * in {@link Label} to the format used in StackMapTable attributes. In 1996 * particular, it converts type table indexes to constant pool indexes. 1997 * 1998 * @param start 1999 * index of the first type in {@link #frame} to write. 2000 * @param end 2001 * index of last type in {@link #frame} to write (exclusive). 2002 */ 2003 private void writeFrameTypes(final int start, final int end) { 2004 for (int i = start; i < end; ++i) { 2005 int t = frame[i]; 2006 int d = t & Frame.DIM; 2007 if (d == 0) { 2008 int v = t & Frame.BASE_VALUE; 2009 switch (t & Frame.BASE_KIND) { 2010 case Frame.OBJECT: 2011 stackMap.putByte(7).putShort( 2012 cw.newClass(cw.typeTable[v].strVal1)); 2013 break; 2014 case Frame.UNINITIALIZED: 2015 stackMap.putByte(8).putShort(cw.typeTable[v].intVal); 2016 break; 2017 default: 2018 stackMap.putByte(v); 2019 } 2020 } else { 2021 StringBuilder sb = new StringBuilder(); 2022 d >>= 28; 2023 while (d-- > 0) { 2024 sb.append('['); 2025 } 2026 if ((t & Frame.BASE_KIND) == Frame.OBJECT) { 2027 sb.append('L'); 2028 sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); 2029 sb.append(';'); 2030 } else { 2031 switch (t & 0xF) { 2032 case 1: 2033 sb.append('I'); 2034 break; 2035 case 2: 2036 sb.append('F'); 2037 break; 2038 case 3: 2039 sb.append('D'); 2040 break; 2041 case 9: 2042 sb.append('Z'); 2043 break; 2044 case 10: 2045 sb.append('B'); 2046 break; 2047 case 11: 2048 sb.append('C'); 2049 break; 2050 case 12: 2051 sb.append('S'); 2052 break; 2053 default: 2054 sb.append('J'); 2055 } 2056 } 2057 stackMap.putByte(7).putShort(cw.newClass(sb.toString())); 2058 } 2059 } 2060 } 2061 2062 private void writeFrameType(final Object type) { 2063 if (type instanceof String) { 2064 stackMap.putByte(7).putShort(cw.newClass((String) type)); 2065 } else if (type instanceof Integer) { 2066 stackMap.putByte(((Integer) type).intValue()); 2067 } else { 2068 stackMap.putByte(8).putShort(((Label) type).position); 2069 } 2070 } 2071 2072 // ------------------------------------------------------------------------ 2073 // Utility methods: dump bytecode array 2074 // ------------------------------------------------------------------------ 2075 2076 /** 2077 * Returns the size of the bytecode of this method. 2078 * 2079 * @return the size of the bytecode of this method. 2080 */ 2081 final int getSize() { 2082 if (classReaderOffset != 0) { 2083 return 6 + classReaderLength; 2084 } 2085 int size = 8; 2086 if (code.length > 0) { 2087 if (code.length > 65535) { 2088 throw new RuntimeException("Method code too large!"); 2089 } 2090 cw.newUTF8("Code"); 2091 size += 18 + code.length + 8 * handlerCount; 2092 if (localVar != null) { 2093 cw.newUTF8("LocalVariableTable"); 2094 size += 8 + localVar.length; 2095 } 2096 if (localVarType != null) { 2097 cw.newUTF8("LocalVariableTypeTable"); 2098 size += 8 + localVarType.length; 2099 } 2100 if (lineNumber != null) { 2101 cw.newUTF8("LineNumberTable"); 2102 size += 8 + lineNumber.length; 2103 } 2104 if (stackMap != null) { 2105 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; 2106 cw.newUTF8(zip ? "StackMapTable" : "StackMap"); 2107 size += 8 + stackMap.length; 2108 } 2109 if (ctanns != null) { 2110 cw.newUTF8("RuntimeVisibleTypeAnnotations"); 2111 size += 8 + ctanns.getSize(); 2112 } 2113 if (ictanns != null) { 2114 cw.newUTF8("RuntimeInvisibleTypeAnnotations"); 2115 size += 8 + ictanns.getSize(); 2116 } 2117 if (cattrs != null) { 2118 size += cattrs.getSize(cw, code.data, code.length, maxStack, 2119 maxLocals); 2120 } 2121 } 2122 if (exceptionCount > 0) { 2123 cw.newUTF8("Exceptions"); 2124 size += 8 + 2 * exceptionCount; 2125 } 2126 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 2127 if ((cw.version & 0xFFFF) < Opcodes.V1_5 2128 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { 2129 cw.newUTF8("Synthetic"); 2130 size += 6; 2131 } 2132 } 2133 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 2134 cw.newUTF8("Deprecated"); 2135 size += 6; 2136 } 2137 if (signature != null) { 2138 cw.newUTF8("Signature"); 2139 cw.newUTF8(signature); 2140 size += 8; 2141 } 2142 if (methodParameters != null) { 2143 cw.newUTF8("MethodParameters"); 2144 size += 7 + methodParameters.length; 2145 } 2146 if (annd != null) { 2147 cw.newUTF8("AnnotationDefault"); 2148 size += 6 + annd.length; 2149 } 2150 if (anns != null) { 2151 cw.newUTF8("RuntimeVisibleAnnotations"); 2152 size += 8 + anns.getSize(); 2153 } 2154 if (ianns != null) { 2155 cw.newUTF8("RuntimeInvisibleAnnotations"); 2156 size += 8 + ianns.getSize(); 2157 } 2158 if (tanns != null) { 2159 cw.newUTF8("RuntimeVisibleTypeAnnotations"); 2160 size += 8 + tanns.getSize(); 2161 } 2162 if (itanns != null) { 2163 cw.newUTF8("RuntimeInvisibleTypeAnnotations"); 2164 size += 8 + itanns.getSize(); 2165 } 2166 if (panns != null) { 2167 cw.newUTF8("RuntimeVisibleParameterAnnotations"); 2168 size += 7 + 2 * (panns.length - synthetics); 2169 for (int i = panns.length - 1; i >= synthetics; --i) { 2170 size += panns[i] == null ? 0 : panns[i].getSize(); 2171 } 2172 } 2173 if (ipanns != null) { 2174 cw.newUTF8("RuntimeInvisibleParameterAnnotations"); 2175 size += 7 + 2 * (ipanns.length - synthetics); 2176 for (int i = ipanns.length - 1; i >= synthetics; --i) { 2177 size += ipanns[i] == null ? 0 : ipanns[i].getSize(); 2178 } 2179 } 2180 if (attrs != null) { 2181 size += attrs.getSize(cw, null, 0, -1, -1); 2182 } 2183 return size; 2184 } 2185 2186 /** 2187 * Puts the bytecode of this method in the given byte vector. 2188 * 2189 * @param out 2190 * the byte vector into which the bytecode of this method must be 2191 * copied. 2192 */ 2193 final void put(final ByteVector out) { 2194 final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; 2195 int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED 2196 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE 2197 | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); 2198 out.putShort(access & ~mask).putShort(name).putShort(desc); 2199 if (classReaderOffset != 0) { 2200 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); 2201 return; 2202 } 2203 int attributeCount = 0; 2204 if (code.length > 0) { 2205 ++attributeCount; 2206 } 2207 if (exceptionCount > 0) { 2208 ++attributeCount; 2209 } 2210 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 2211 if ((cw.version & 0xFFFF) < Opcodes.V1_5 2212 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { 2213 ++attributeCount; 2214 } 2215 } 2216 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 2217 ++attributeCount; 2218 } 2219 if (signature != null) { 2220 ++attributeCount; 2221 } 2222 if (methodParameters != null) { 2223 ++attributeCount; 2224 } 2225 if (annd != null) { 2226 ++attributeCount; 2227 } 2228 if (anns != null) { 2229 ++attributeCount; 2230 } 2231 if (ianns != null) { 2232 ++attributeCount; 2233 } 2234 if (tanns != null) { 2235 ++attributeCount; 2236 } 2237 if (itanns != null) { 2238 ++attributeCount; 2239 } 2240 if (panns != null) { 2241 ++attributeCount; 2242 } 2243 if (ipanns != null) { 2244 ++attributeCount; 2245 } 2246 if (attrs != null) { 2247 attributeCount += attrs.getCount(); 2248 } 2249 out.putShort(attributeCount); 2250 if (code.length > 0) { 2251 int size = 12 + code.length + 8 * handlerCount; 2252 if (localVar != null) { 2253 size += 8 + localVar.length; 2254 } 2255 if (localVarType != null) { 2256 size += 8 + localVarType.length; 2257 } 2258 if (lineNumber != null) { 2259 size += 8 + lineNumber.length; 2260 } 2261 if (stackMap != null) { 2262 size += 8 + stackMap.length; 2263 } 2264 if (ctanns != null) { 2265 size += 8 + ctanns.getSize(); 2266 } 2267 if (ictanns != null) { 2268 size += 8 + ictanns.getSize(); 2269 } 2270 if (cattrs != null) { 2271 size += cattrs.getSize(cw, code.data, code.length, maxStack, 2272 maxLocals); 2273 } 2274 out.putShort(cw.newUTF8("Code")).putInt(size); 2275 out.putShort(maxStack).putShort(maxLocals); 2276 out.putInt(code.length).putByteArray(code.data, 0, code.length); 2277 out.putShort(handlerCount); 2278 if (handlerCount > 0) { 2279 Handler h = firstHandler; 2280 while (h != null) { 2281 out.putShort(h.start.position).putShort(h.end.position) 2282 .putShort(h.handler.position).putShort(h.type); 2283 h = h.next; 2284 } 2285 } 2286 attributeCount = 0; 2287 if (localVar != null) { 2288 ++attributeCount; 2289 } 2290 if (localVarType != null) { 2291 ++attributeCount; 2292 } 2293 if (lineNumber != null) { 2294 ++attributeCount; 2295 } 2296 if (stackMap != null) { 2297 ++attributeCount; 2298 } 2299 if (ctanns != null) { 2300 ++attributeCount; 2301 } 2302 if (ictanns != null) { 2303 ++attributeCount; 2304 } 2305 if (cattrs != null) { 2306 attributeCount += cattrs.getCount(); 2307 } 2308 out.putShort(attributeCount); 2309 if (localVar != null) { 2310 out.putShort(cw.newUTF8("LocalVariableTable")); 2311 out.putInt(localVar.length + 2).putShort(localVarCount); 2312 out.putByteArray(localVar.data, 0, localVar.length); 2313 } 2314 if (localVarType != null) { 2315 out.putShort(cw.newUTF8("LocalVariableTypeTable")); 2316 out.putInt(localVarType.length + 2).putShort(localVarTypeCount); 2317 out.putByteArray(localVarType.data, 0, localVarType.length); 2318 } 2319 if (lineNumber != null) { 2320 out.putShort(cw.newUTF8("LineNumberTable")); 2321 out.putInt(lineNumber.length + 2).putShort(lineNumberCount); 2322 out.putByteArray(lineNumber.data, 0, lineNumber.length); 2323 } 2324 if (stackMap != null) { 2325 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; 2326 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); 2327 out.putInt(stackMap.length + 2).putShort(frameCount); 2328 out.putByteArray(stackMap.data, 0, stackMap.length); 2329 } 2330 if (ctanns != null) { 2331 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); 2332 ctanns.put(out); 2333 } 2334 if (ictanns != null) { 2335 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); 2336 ictanns.put(out); 2337 } 2338 if (cattrs != null) { 2339 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); 2340 } 2341 } 2342 if (exceptionCount > 0) { 2343 out.putShort(cw.newUTF8("Exceptions")).putInt( 2344 2 * exceptionCount + 2); 2345 out.putShort(exceptionCount); 2346 for (int i = 0; i < exceptionCount; ++i) { 2347 out.putShort(exceptions[i]); 2348 } 2349 } 2350 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 2351 if ((cw.version & 0xFFFF) < Opcodes.V1_5 2352 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { 2353 out.putShort(cw.newUTF8("Synthetic")).putInt(0); 2354 } 2355 } 2356 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 2357 out.putShort(cw.newUTF8("Deprecated")).putInt(0); 2358 } 2359 if (signature != null) { 2360 out.putShort(cw.newUTF8("Signature")).putInt(2) 2361 .putShort(cw.newUTF8(signature)); 2362 } 2363 if (methodParameters != null) { 2364 out.putShort(cw.newUTF8("MethodParameters")); 2365 out.putInt(methodParameters.length + 1).putByte( 2366 methodParametersCount); 2367 out.putByteArray(methodParameters.data, 0, methodParameters.length); 2368 } 2369 if (annd != null) { 2370 out.putShort(cw.newUTF8("AnnotationDefault")); 2371 out.putInt(annd.length); 2372 out.putByteArray(annd.data, 0, annd.length); 2373 } 2374 if (anns != null) { 2375 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); 2376 anns.put(out); 2377 } 2378 if (ianns != null) { 2379 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); 2380 ianns.put(out); 2381 } 2382 if (tanns != null) { 2383 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); 2384 tanns.put(out); 2385 } 2386 if (itanns != null) { 2387 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); 2388 itanns.put(out); 2389 } 2390 if (panns != null) { 2391 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); 2392 AnnotationWriter.put(panns, synthetics, out); 2393 } 2394 if (ipanns != null) { 2395 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); 2396 AnnotationWriter.put(ipanns, synthetics, out); 2397 } 2398 if (attrs != null) { 2399 attrs.put(cw, null, 0, -1, -1, out); 2400 } 2401 } 2402 }