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