< prev index next >

src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java

Print this page
rev 47452 : imported patch jdk-new-asmv6.patch


 111 
 112     /**
 113      * Frame where current locals are the same as the locals in the previous
 114      * frame, except that k additional locals are defined. The value of k is
 115      * given by the formula frame_type-251.
 116      */
 117     static final int APPEND_FRAME = 252; // to 254 // fc-fe
 118 
 119     /**
 120      * Full frame
 121      */
 122     static final int FULL_FRAME = 255; // ff
 123 
 124     /**
 125      * Indicates that the stack map frames must be recomputed from scratch. In
 126      * this case the maximum stack size and number of local variables is also
 127      * recomputed from scratch.
 128      *
 129      * @see #compute
 130      */
 131     private static final int FRAMES = 0;
 132 
 133     /**












 134      * Indicates that the maximum stack size and number of local variables must
 135      * be automatically computed.
 136      *
 137      * @see #compute
 138      */
 139     private static final int MAXS = 1;
 140 
 141     /**
 142      * Indicates that nothing must be automatically computed.
 143      *
 144      * @see #compute
 145      */
 146     private static final int NOTHING = 2;
 147 
 148     /**
 149      * The class writer to which this method must be added.
 150      */
 151     final ClassWriter cw;
 152 
 153     /**
 154      * Access flags of this method.
 155      */
 156     private int access;
 157 
 158     /**
 159      * The index of the constant pool item that contains the name of this
 160      * method.
 161      */
 162     private final int name;
 163 
 164     /**
 165      * The index of the constant pool item that contains the descriptor of this
 166      * method.


 260     private ByteVector code = new ByteVector();
 261 
 262     /**
 263      * Maximum stack size of this method.
 264      */
 265     private int maxStack;
 266 
 267     /**
 268      * Maximum number of local variables for this method.
 269      */
 270     private int maxLocals;
 271 
 272     /**
 273      * Number of local variables in the current stack map frame.
 274      */
 275     private int currentLocals;
 276 
 277     /**
 278      * Number of stack map frames in the StackMapTable attribute.
 279      */
 280     private int frameCount;
 281 
 282     /**
 283      * The StackMapTable attribute.
 284      */
 285     private ByteVector stackMap;
 286 
 287     /**
 288      * The offset of the last frame that was written in the StackMapTable
 289      * attribute.
 290      */
 291     private int previousFrameOffset;
 292 
 293     /**
 294      * The last frame that was written in the StackMapTable attribute.
 295      *
 296      * @see #frame
 297      */
 298     private int[] previousFrame;
 299 
 300     /**


 367      * The start offset of the last visited instruction.
 368      */
 369     private int lastCodeOffset;
 370 
 371     /**
 372      * The runtime visible type annotations of the code. May be <tt>null</tt>.
 373      */
 374     private AnnotationWriter ctanns;
 375 
 376     /**
 377      * The runtime invisible type annotations of the code. May be <tt>null</tt>.
 378      */
 379     private AnnotationWriter ictanns;
 380 
 381     /**
 382      * The non standard attributes of the method's code.
 383      */
 384     private Attribute cattrs;
 385 
 386     /**
 387      * Indicates if some jump instructions are too small and need to be resized.
 388      */
 389     private boolean resize;
 390 
 391     /**
 392      * The number of subroutines in this method.
 393      */
 394     private int subroutines;
 395 
 396     // ------------------------------------------------------------------------
 397 
 398     /*
 399      * Fields for the control flow graph analysis algorithm (used to compute the
 400      * maximum stack size). A control flow graph contains one node per "basic
 401      * block", and one edge per "jump" from one basic block to another. Each
 402      * node (i.e., each basic block) is represented by the Label object that
 403      * corresponds to the first instruction of this basic block. Each node also
 404      * stores the list of its successors in the graph, as a linked list of Edge
 405      * objects.
 406      */
 407 
 408     /**
 409      * Indicates what must be automatically computed.
 410      *
 411      * @see #FRAMES

 412      * @see #MAXS
 413      * @see #NOTHING
 414      */
 415     private final int compute;
 416 
 417     /**
 418      * A list of labels. This list is the list of basic blocks in the method,
 419      * i.e. a list of Label objects linked to each other by their
 420      * {@link Label#successor} field, in the order they are visited by
 421      * {@link MethodVisitor#visitLabel}, and starting with the first basic
 422      * block.
 423      */
 424     private Label labels;
 425 
 426     /**
 427      * The previous basic block.
 428      */
 429     private Label previousBlock;
 430 
 431     /**


 454     // ------------------------------------------------------------------------
 455     // Constructor
 456     // ------------------------------------------------------------------------
 457 
 458     /**
 459      * Constructs a new {@link MethodWriter}.
 460      *
 461      * @param cw
 462      *            the class writer in which the method must be added.
 463      * @param access
 464      *            the method's access flags (see {@link Opcodes}).
 465      * @param name
 466      *            the method's name.
 467      * @param desc
 468      *            the method's descriptor (see {@link Type}).
 469      * @param signature
 470      *            the method's signature. May be <tt>null</tt>.
 471      * @param exceptions
 472      *            the internal names of the method's exceptions. May be
 473      *            <tt>null</tt>.
 474      * @param computeMaxs
 475      *            <tt>true</tt> if the maximum stack size and number of local
 476      *            variables must be automatically computed.
 477      * @param computeFrames
 478      *            <tt>true</tt> if the stack map tables must be recomputed from
 479      *            scratch.
 480      */
 481     MethodWriter(final ClassWriter cw, final int access, final String name,
 482             final String desc, final String signature,
 483             final String[] exceptions, final boolean computeMaxs,
 484             final boolean computeFrames) {
 485         super(Opcodes.ASM5);
 486         if (cw.firstMethod == null) {
 487             cw.firstMethod = this;
 488         } else {
 489             cw.lastMethod.mv = this;
 490         }
 491         cw.lastMethod = this;
 492         this.cw = cw;
 493         this.access = access;
 494         if ("<init>".equals(name)) {
 495             this.access |= ACC_CONSTRUCTOR;
 496         }
 497         this.name = cw.newUTF8(name);
 498         this.desc = cw.newUTF8(desc);
 499         this.descriptor = desc;
 500         if (ClassReader.SIGNATURES) {
 501             this.signature = signature;
 502         }
 503         if (exceptions != null && exceptions.length > 0) {
 504             exceptionCount = exceptions.length;
 505             this.exceptions = new int[exceptionCount];
 506             for (int i = 0; i < exceptionCount; ++i) {
 507                 this.exceptions[i] = cw.newClass(exceptions[i]);
 508             }
 509         }
 510         this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
 511         if (computeMaxs || computeFrames) {
 512             // updates maxLocals
 513             int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
 514             if ((access & Opcodes.ACC_STATIC) != 0) {
 515                 --size;
 516             }
 517             maxLocals = size;
 518             currentLocals = size;
 519             // creates and visits the label for the first basic block
 520             labels = new Label();
 521             labels.status |= Label.PUSHED;
 522             visitLabel(labels);
 523         }
 524     }
 525 
 526     // ------------------------------------------------------------------------
 527     // Implementation of the MethodVisitor abstract class
 528     // ------------------------------------------------------------------------
 529 
 530     @Override
 531     public void visitParameter(String name, int access) {
 532         if (methodParameters == null) {
 533             methodParameters = new ByteVector();
 534         }
 535         ++methodParametersCount;
 536         methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
 537                 .putShort(access);
 538     }
 539 
 540     @Override
 541     public AnnotationVisitor visitAnnotationDefault() {
 542         if (!ClassReader.ANNOTATIONS) {
 543             return null;
 544         }
 545         annd = new ByteVector();
 546         return new AnnotationWriter(cw, false, annd, null, 0);
 547     }
 548 
 549     @Override
 550     public AnnotationVisitor visitAnnotation(final String desc,
 551             final boolean visible) {
 552         if (!ClassReader.ANNOTATIONS) {
 553             return null;
 554         }
 555         ByteVector bv = new ByteVector();
 556         // write type, and reserve space for values count
 557         bv.putShort(cw.newUTF8(desc)).putShort(0);
 558         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
 559         if (visible) {
 560             aw.next = anns;
 561             anns = aw;
 562         } else {
 563             aw.next = ianns;
 564             ianns = aw;
 565         }
 566         return aw;
 567     }
 568 
 569     @Override
 570     public AnnotationVisitor visitTypeAnnotation(final int typeRef,
 571             final TypePath typePath, final String desc, final boolean visible) {
 572         if (!ClassReader.ANNOTATIONS) {
 573             return null;
 574         }
 575         ByteVector bv = new ByteVector();
 576         // write target_type and target_info
 577         AnnotationWriter.putTarget(typeRef, typePath, bv);
 578         // write type, and reserve space for values count
 579         bv.putShort(cw.newUTF8(desc)).putShort(0);
 580         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
 581                 bv.length - 2);
 582         if (visible) {
 583             aw.next = tanns;
 584             tanns = aw;
 585         } else {
 586             aw.next = itanns;
 587             itanns = aw;
 588         }
 589         return aw;
 590     }
 591 
 592     @Override
 593     public AnnotationVisitor visitParameterAnnotation(final int parameter,
 594             final String desc, final boolean visible) {
 595         if (!ClassReader.ANNOTATIONS) {
 596             return null;
 597         }
 598         ByteVector bv = new ByteVector();
 599         if ("Ljava/lang/Synthetic;".equals(desc)) {
 600             // workaround for a bug in javac with synthetic parameters
 601             // see ClassReader.readParameterAnnotations
 602             synthetics = Math.max(synthetics, parameter + 1);
 603             return new AnnotationWriter(cw, false, bv, null, 0);
 604         }
 605         // write type, and reserve space for values count
 606         bv.putShort(cw.newUTF8(desc)).putShort(0);
 607         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
 608         if (visible) {
 609             if (panns == null) {
 610                 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
 611             }
 612             aw.next = panns[parameter];
 613             panns[parameter] = aw;
 614         } else {
 615             if (ipanns == null) {
 616                 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
 617             }


 622     }
 623 
 624     @Override
 625     public void visitAttribute(final Attribute attr) {
 626         if (attr.isCodeAttribute()) {
 627             attr.next = cattrs;
 628             cattrs = attr;
 629         } else {
 630             attr.next = attrs;
 631             attrs = attr;
 632         }
 633     }
 634 
 635     @Override
 636     public void visitCode() {
 637     }
 638 
 639     @Override
 640     public void visitFrame(final int type, final int nLocal,
 641             final Object[] local, final int nStack, final Object[] stack) {
 642         if (!ClassReader.FRAMES || compute == FRAMES) {
 643             return;
 644         }
 645 











 646         if (type == Opcodes.F_NEW) {











 647             if (previousFrame == null) {
 648                 visitImplicitFirstFrame();
 649             }
 650             currentLocals = nLocal;
 651             int frameIndex = startFrame(code.length, nLocal, nStack);
 652             for (int i = 0; i < nLocal; ++i) {
 653                 if (local[i] instanceof String) {
 654                     frame[frameIndex++] = Frame.OBJECT
 655                             | cw.addType((String) local[i]);
 656                 } else if (local[i] instanceof Integer) {
 657                     frame[frameIndex++] = ((Integer) local[i]).intValue();
 658                 } else {
 659                     frame[frameIndex++] = Frame.UNINITIALIZED
 660                             | cw.addUninitializedType("",
 661                                     ((Label) local[i]).position);
 662                 }
 663             }
 664             for (int i = 0; i < nStack; ++i) {
 665                 if (stack[i] instanceof String) {
 666                     frame[frameIndex++] = Frame.OBJECT
 667                             | cw.addType((String) stack[i]);
 668                 } else if (stack[i] instanceof Integer) {
 669                     frame[frameIndex++] = ((Integer) stack[i]).intValue();
 670                 } else {
 671                     frame[frameIndex++] = Frame.UNINITIALIZED
 672                             | cw.addUninitializedType("",
 673                                     ((Label) stack[i]).position);
 674                 }
 675             }
 676             endFrame();
 677         } else {
 678             int delta;
 679             if (stackMap == null) {
 680                 stackMap = new ByteVector();
 681                 delta = code.length;
 682             } else {
 683                 delta = code.length - previousFrameOffset - 1;
 684                 if (delta < 0) {
 685                     if (type == Opcodes.F_SAME) {
 686                         return;
 687                     } else {
 688                         throw new IllegalStateException();
 689                     }


 730                 writeFrameType(stack[0]);
 731                 break;
 732             }
 733 
 734             previousFrameOffset = code.length;
 735             ++frameCount;
 736         }
 737 
 738         maxStack = Math.max(maxStack, nStack);
 739         maxLocals = Math.max(maxLocals, currentLocals);
 740     }
 741 
 742     @Override
 743     public void visitInsn(final int opcode) {
 744         lastCodeOffset = code.length;
 745         // adds the instruction to the bytecode of the method
 746         code.putByte(opcode);
 747         // update currentBlock
 748         // Label currentBlock = this.currentBlock;
 749         if (currentBlock != null) {
 750             if (compute == FRAMES) {
 751                 currentBlock.frame.execute(opcode, 0, null, null);
 752             } else {
 753                 // updates current and max stack sizes
 754                 int size = stackSize + Frame.SIZE[opcode];
 755                 if (size > maxStackSize) {
 756                     maxStackSize = size;
 757                 }
 758                 stackSize = size;
 759             }
 760             // if opcode == ATHROW or xRETURN, ends current block (no successor)
 761             if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
 762                     || opcode == Opcodes.ATHROW) {
 763                 noSuccessor();
 764             }
 765         }
 766     }
 767 
 768     @Override
 769     public void visitIntInsn(final int opcode, final int operand) {
 770         lastCodeOffset = code.length;
 771         // Label currentBlock = this.currentBlock;
 772         if (currentBlock != null) {
 773             if (compute == FRAMES) {
 774                 currentBlock.frame.execute(opcode, operand, null, null);
 775             } else if (opcode != Opcodes.NEWARRAY) {
 776                 // updates current and max stack sizes only for NEWARRAY
 777                 // (stack size variation = 0 for BIPUSH or SIPUSH)
 778                 int size = stackSize + 1;
 779                 if (size > maxStackSize) {
 780                     maxStackSize = size;
 781                 }
 782                 stackSize = size;
 783             }
 784         }
 785         // adds the instruction to the bytecode of the method
 786         if (opcode == Opcodes.SIPUSH) {
 787             code.put12(opcode, operand);
 788         } else { // BIPUSH or NEWARRAY
 789             code.put11(opcode, operand);
 790         }
 791     }
 792 
 793     @Override
 794     public void visitVarInsn(final int opcode, final int var) {
 795         lastCodeOffset = code.length;
 796         // Label currentBlock = this.currentBlock;
 797         if (currentBlock != null) {
 798             if (compute == FRAMES) {
 799                 currentBlock.frame.execute(opcode, var, null, null);
 800             } else {
 801                 // updates current and max stack sizes
 802                 if (opcode == Opcodes.RET) {
 803                     // no stack change, but end of current block (no successor)
 804                     currentBlock.status |= Label.RET;
 805                     // save 'stackSize' here for future use
 806                     // (see {@link #findSubroutineSuccessors})
 807                     currentBlock.inputStackTop = stackSize;
 808                     noSuccessor();
 809                 } else { // xLOAD or xSTORE
 810                     int size = stackSize + Frame.SIZE[opcode];
 811                     if (size > maxStackSize) {
 812                         maxStackSize = size;
 813                     }
 814                     stackSize = size;
 815                 }
 816             }
 817         }
 818         if (compute != NOTHING) {


 835                 /* ILOAD_0 */
 836                 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
 837             } else {
 838                 /* ISTORE_0 */
 839                 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
 840             }
 841             code.putByte(opt);
 842         } else if (var >= 256) {
 843             code.putByte(196 /* WIDE */).put12(opcode, var);
 844         } else {
 845             code.put11(opcode, var);
 846         }
 847         if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
 848             visitLabel(new Label());
 849         }
 850     }
 851 
 852     @Override
 853     public void visitTypeInsn(final int opcode, final String type) {
 854         lastCodeOffset = code.length;
 855         Item i = cw.newClassItem(type);
 856         // Label currentBlock = this.currentBlock;
 857         if (currentBlock != null) {
 858             if (compute == FRAMES) {
 859                 currentBlock.frame.execute(opcode, code.length, cw, i);
 860             } else if (opcode == Opcodes.NEW) {
 861                 // updates current and max stack sizes only if opcode == NEW
 862                 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
 863                 int size = stackSize + 1;
 864                 if (size > maxStackSize) {
 865                     maxStackSize = size;
 866                 }
 867                 stackSize = size;
 868             }
 869         }
 870         // adds the instruction to the bytecode of the method
 871         code.put12(opcode, i.index);
 872     }
 873 
 874     @Override
 875     public void visitFieldInsn(final int opcode, final String owner,
 876             final String name, final String desc) {
 877         lastCodeOffset = code.length;
 878         Item i = cw.newFieldItem(owner, name, desc);
 879         // Label currentBlock = this.currentBlock;
 880         if (currentBlock != null) {
 881             if (compute == FRAMES) {
 882                 currentBlock.frame.execute(opcode, 0, cw, i);
 883             } else {
 884                 int size;
 885                 // computes the stack size variation
 886                 char c = desc.charAt(0);
 887                 switch (opcode) {
 888                 case Opcodes.GETSTATIC:
 889                     size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
 890                     break;
 891                 case Opcodes.PUTSTATIC:
 892                     size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
 893                     break;
 894                 case Opcodes.GETFIELD:
 895                     size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
 896                     break;
 897                 // case Constants.PUTFIELD:
 898                 default:
 899                     size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
 900                     break;
 901                 }
 902                 // updates current and max stack sizes
 903                 if (size > maxStackSize) {
 904                     maxStackSize = size;
 905                 }
 906                 stackSize = size;
 907             }
 908         }
 909         // adds the instruction to the bytecode of the method
 910         code.put12(opcode, i.index);
 911     }
 912 
 913     @Override
 914     public void visitMethodInsn(final int opcode, final String owner,
 915             final String name, final String desc, final boolean itf) {
 916         lastCodeOffset = code.length;
 917         Item i = cw.newMethodItem(owner, name, desc, itf);
 918         int argSize = i.intVal;
 919         // Label currentBlock = this.currentBlock;
 920         if (currentBlock != null) {
 921             if (compute == FRAMES) {
 922                 currentBlock.frame.execute(opcode, 0, cw, i);
 923             } else {
 924                 /*
 925                  * computes the stack size variation. In order not to recompute
 926                  * several times this variation for the same Item, we use the
 927                  * intVal field of this item to store this variation, once it
 928                  * has been computed. More precisely this intVal field stores
 929                  * the sizes of the arguments and of the return value
 930                  * corresponding to desc.
 931                  */
 932                 if (argSize == 0) {
 933                     // the above sizes have not been computed yet,
 934                     // so we compute them...
 935                     argSize = Type.getArgumentsAndReturnSizes(desc);
 936                     // ... and we save them in order
 937                     // not to recompute them in the future
 938                     i.intVal = argSize;
 939                 }
 940                 int size;
 941                 if (opcode == Opcodes.INVOKESTATIC) {


 953         // adds the instruction to the bytecode of the method
 954         if (opcode == Opcodes.INVOKEINTERFACE) {
 955             if (argSize == 0) {
 956                 argSize = Type.getArgumentsAndReturnSizes(desc);
 957                 i.intVal = argSize;
 958             }
 959             code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
 960         } else {
 961             code.put12(opcode, i.index);
 962         }
 963     }
 964 
 965     @Override
 966     public void visitInvokeDynamicInsn(final String name, final String desc,
 967             final Handle bsm, final Object... bsmArgs) {
 968         lastCodeOffset = code.length;
 969         Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
 970         int argSize = i.intVal;
 971         // Label currentBlock = this.currentBlock;
 972         if (currentBlock != null) {
 973             if (compute == FRAMES) {
 974                 currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i);
 975             } else {
 976                 /*
 977                  * computes the stack size variation. In order not to recompute
 978                  * several times this variation for the same Item, we use the
 979                  * intVal field of this item to store this variation, once it
 980                  * has been computed. More precisely this intVal field stores
 981                  * the sizes of the arguments and of the return value
 982                  * corresponding to desc.
 983                  */
 984                 if (argSize == 0) {
 985                     // the above sizes have not been computed yet,
 986                     // so we compute them...
 987                     argSize = Type.getArgumentsAndReturnSizes(desc);
 988                     // ... and we save them in order
 989                     // not to recompute them in the future
 990                     i.intVal = argSize;
 991                 }
 992                 int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
 993 
 994                 // updates current and max stack sizes
 995                 if (size > maxStackSize) {
 996                     maxStackSize = size;
 997                 }
 998                 stackSize = size;
 999             }
1000         }
1001         // adds the instruction to the bytecode of the method
1002         code.put12(Opcodes.INVOKEDYNAMIC, i.index);
1003         code.putShort(0);
1004     }
1005 
1006     @Override
1007     public void visitJumpInsn(final int opcode, final Label label) {


1008         lastCodeOffset = code.length;
1009         Label nextInsn = null;
1010         // Label currentBlock = this.currentBlock;
1011         if (currentBlock != null) {
1012             if (compute == FRAMES) {
1013                 currentBlock.frame.execute(opcode, 0, null, null);
1014                 // 'label' is the target of a jump instruction
1015                 label.getFirst().status |= Label.TARGET;
1016                 // adds 'label' as a successor of this basic block
1017                 addSuccessor(Edge.NORMAL, label);
1018                 if (opcode != Opcodes.GOTO) {
1019                     // creates a Label for the next basic block
1020                     nextInsn = new Label();
1021                 }


1022             } else {
1023                 if (opcode == Opcodes.JSR) {
1024                     if ((label.status & Label.SUBROUTINE) == 0) {
1025                         label.status |= Label.SUBROUTINE;
1026                         ++subroutines;
1027                     }
1028                     currentBlock.status |= Label.JSR;
1029                     addSuccessor(stackSize + 1, label);
1030                     // creates a Label for the next basic block
1031                     nextInsn = new Label();
1032                     /*
1033                      * note that, by construction in this method, a JSR block
1034                      * has at least two successors in the control flow graph:
1035                      * the first one leads the next instruction after the JSR,
1036                      * while the second one leads to the JSR target.
1037                      */
1038                 } else {
1039                     // updates current stack size (max stack size unchanged
1040                     // because stack size variation always negative in this
1041                     // case)
1042                     stackSize += Frame.SIZE[opcode];
1043                     addSuccessor(stackSize, label);
1044                 }
1045             }
1046         }
1047         // adds the instruction to the bytecode of the method
1048         if ((label.status & Label.RESOLVED) != 0
1049                 && label.position - code.length < Short.MIN_VALUE) {
1050             /*
1051              * case of a backward jump with an offset < -32768. In this case we
1052              * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
1053              * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
1054              * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
1055              * designates the instruction just after the GOTO_W.
1056              */
1057             if (opcode == Opcodes.GOTO) {
1058                 code.putByte(200); // GOTO_W
1059             } else if (opcode == Opcodes.JSR) {
1060                 code.putByte(201); // JSR_W
1061             } else {
1062                 // if the IF instruction is transformed into IFNOT GOTO_W the
1063                 // next instruction becomes the target of the IFNOT instruction
1064                 if (nextInsn != null) {
1065                     nextInsn.status |= Label.TARGET;
1066                 }
1067                 code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
1068                         : opcode ^ 1);
1069                 code.putShort(8); // jump offset
1070                 code.putByte(200); // GOTO_W




1071             }
1072             label.put(this, code, code.length - 1, true);








1073         } else {
1074             /*
1075              * case of a backward jump with an offset >= -32768, or of a forward
1076              * jump with, of course, an unknown offset. In these cases we store
1077              * the offset in 2 bytes (which will be increased in
1078              * resizeInstructions, if needed).
1079              */
1080             code.putByte(opcode);
1081             label.put(this, code, code.length - 1, false);
1082         }
1083         if (currentBlock != null) {
1084             if (nextInsn != null) {
1085                 // if the jump instruction is not a GOTO, the next instruction
1086                 // is also a successor of this instruction. Calling visitLabel
1087                 // adds the label of this next instruction as a successor of the
1088                 // current block, and starts a new basic block
1089                 visitLabel(nextInsn);
1090             }
1091             if (opcode == Opcodes.GOTO) {
1092                 noSuccessor();
1093             }
1094         }
1095     }
1096 
1097     @Override
1098     public void visitLabel(final Label label) {
1099         // resolves previous forward references to label, if any
1100         resize |= label.resolve(this, code.length, code.data);
1101         // updates currentBlock
1102         if ((label.status & Label.DEBUG) != 0) {
1103             return;
1104         }
1105         if (compute == FRAMES) {
1106             if (currentBlock != null) {
1107                 if (label.position == currentBlock.position) {
1108                     // successive labels, do not start a new basic block
1109                     currentBlock.status |= (label.status & Label.TARGET);
1110                     label.frame = currentBlock.frame;
1111                     return;
1112                 }
1113                 // ends current block (with one new successor)
1114                 addSuccessor(Edge.NORMAL, label);
1115             }
1116             // begins a new current block
1117             currentBlock = label;
1118             if (label.frame == null) {
1119                 label.frame = new Frame();
1120                 label.frame.owner = label;
1121             }
1122             // updates the basic block list
1123             if (previousBlock != null) {
1124                 if (label.position == previousBlock.position) {
1125                     previousBlock.status |= (label.status & Label.TARGET);
1126                     label.frame = previousBlock.frame;
1127                     currentBlock = previousBlock;
1128                     return;
1129                 }
1130                 previousBlock.successor = label;
1131             }
1132             previousBlock = label;












1133         } else if (compute == MAXS) {
1134             if (currentBlock != null) {
1135                 // ends current block (with one new successor)
1136                 currentBlock.outputStackMax = maxStackSize;
1137                 addSuccessor(stackSize, label);
1138             }
1139             // begins a new current block
1140             currentBlock = label;
1141             // resets the relative current and max stack sizes
1142             stackSize = 0;
1143             maxStackSize = 0;
1144             // updates the basic block list
1145             if (previousBlock != null) {
1146                 previousBlock.successor = label;
1147             }
1148             previousBlock = label;
1149         }
1150     }
1151 
1152     @Override
1153     public void visitLdcInsn(final Object cst) {
1154         lastCodeOffset = code.length;
1155         Item i = cw.newConstItem(cst);
1156         // Label currentBlock = this.currentBlock;
1157         if (currentBlock != null) {
1158             if (compute == FRAMES) {
1159                 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
1160             } else {
1161                 int size;
1162                 // computes the stack size variation
1163                 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1164                     size = stackSize + 2;
1165                 } else {
1166                     size = stackSize + 1;
1167                 }
1168                 // updates current and max stack sizes
1169                 if (size > maxStackSize) {
1170                     maxStackSize = size;
1171                 }
1172                 stackSize = size;
1173             }
1174         }
1175         // adds the instruction to the bytecode of the method
1176         int index = i.index;
1177         if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1178             code.put12(20 /* LDC2_W */, index);
1179         } else if (index >= 256) {
1180             code.put12(19 /* LDC_W */, index);
1181         } else {
1182             code.put11(Opcodes.LDC, index);
1183         }
1184     }
1185 
1186     @Override
1187     public void visitIincInsn(final int var, final int increment) {
1188         lastCodeOffset = code.length;
1189         if (currentBlock != null) {
1190             if (compute == FRAMES) {
1191                 currentBlock.frame.execute(Opcodes.IINC, var, null, null);
1192             }
1193         }
1194         if (compute != NOTHING) {
1195             // updates max locals
1196             int n = var + 1;
1197             if (n > maxLocals) {
1198                 maxLocals = n;
1199             }
1200         }
1201         // adds the instruction to the bytecode of the method
1202         if ((var > 255) || (increment > 127) || (increment < -128)) {
1203             code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
1204                     .putShort(increment);
1205         } else {
1206             code.putByte(Opcodes.IINC).put11(var, increment);
1207         }
1208     }
1209 
1210     @Override


1254                     addSuccessor(Edge.NORMAL, labels[i]);
1255                     labels[i].getFirst().status |= Label.TARGET;
1256                 }
1257             } else {
1258                 // updates current stack size (max stack size unchanged)
1259                 --stackSize;
1260                 // adds current block successors
1261                 addSuccessor(stackSize, dflt);
1262                 for (int i = 0; i < labels.length; ++i) {
1263                     addSuccessor(stackSize, labels[i]);
1264                 }
1265             }
1266             // ends current block
1267             noSuccessor();
1268         }
1269     }
1270 
1271     @Override
1272     public void visitMultiANewArrayInsn(final String desc, final int dims) {
1273         lastCodeOffset = code.length;
1274         Item i = cw.newClassItem(desc);
1275         // Label currentBlock = this.currentBlock;
1276         if (currentBlock != null) {
1277             if (compute == FRAMES) {
1278                 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
1279             } else {
1280                 // updates current stack size (max stack size unchanged because
1281                 // stack size variation always negative or null)
1282                 stackSize += 1 - dims;
1283             }
1284         }
1285         // adds the instruction to the bytecode of the method
1286         code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
1287     }
1288 
1289     @Override
1290     public AnnotationVisitor visitInsnAnnotation(int typeRef,
1291             TypePath typePath, String desc, boolean visible) {
1292         if (!ClassReader.ANNOTATIONS) {
1293             return null;
1294         }
1295         ByteVector bv = new ByteVector();
1296         // write target_type and target_info
1297         typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
1298         AnnotationWriter.putTarget(typeRef, typePath, bv);
1299         // write type, and reserve space for values count
1300         bv.putShort(cw.newUTF8(desc)).putShort(0);
1301         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1302                 bv.length - 2);
1303         if (visible) {
1304             aw.next = ctanns;
1305             ctanns = aw;
1306         } else {
1307             aw.next = ictanns;
1308             ictanns = aw;
1309         }
1310         return aw;
1311     }
1312 
1313     @Override
1314     public void visitTryCatchBlock(final Label start, final Label end,
1315             final Label handler, final String type) {
1316         ++handlerCount;
1317         Handler h = new Handler();
1318         h.start = start;
1319         h.end = end;
1320         h.handler = handler;
1321         h.desc = type;
1322         h.type = type != null ? cw.newClass(type) : 0;
1323         if (lastHandler == null) {
1324             firstHandler = h;
1325         } else {
1326             lastHandler.next = h;
1327         }
1328         lastHandler = h;
1329     }
1330 
1331     @Override
1332     public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
1333             TypePath typePath, String desc, boolean visible) {
1334         if (!ClassReader.ANNOTATIONS) {
1335             return null;
1336         }
1337         ByteVector bv = new ByteVector();
1338         // write target_type and target_info
1339         AnnotationWriter.putTarget(typeRef, typePath, bv);
1340         // write type, and reserve space for values count
1341         bv.putShort(cw.newUTF8(desc)).putShort(0);
1342         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1343                 bv.length - 2);
1344         if (visible) {
1345             aw.next = ctanns;
1346             ctanns = aw;
1347         } else {
1348             aw.next = ictanns;
1349             ictanns = aw;
1350         }
1351         return aw;
1352     }
1353 
1354     @Override
1355     public void visitLocalVariable(final String name, final String desc,
1356             final String signature, final Label start, final Label end,


1370         }
1371         ++localVarCount;
1372         localVar.putShort(start.position)
1373                 .putShort(end.position - start.position)
1374                 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc))
1375                 .putShort(index);
1376         if (compute != NOTHING) {
1377             // updates max locals
1378             char c = desc.charAt(0);
1379             int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1380             if (n > maxLocals) {
1381                 maxLocals = n;
1382             }
1383         }
1384     }
1385 
1386     @Override
1387     public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
1388             TypePath typePath, Label[] start, Label[] end, int[] index,
1389             String desc, boolean visible) {
1390         if (!ClassReader.ANNOTATIONS) {
1391             return null;
1392         }
1393         ByteVector bv = new ByteVector();
1394         // write target_type and target_info
1395         bv.putByte(typeRef >>> 24).putShort(start.length);
1396         for (int i = 0; i < start.length; ++i) {
1397             bv.putShort(start[i].position)
1398                     .putShort(end[i].position - start[i].position)
1399                     .putShort(index[i]);
1400         }
1401         if (typePath == null) {
1402             bv.putByte(0);
1403         } else {
1404             int length = typePath.b[typePath.offset] * 2 + 1;
1405             bv.putByteArray(typePath.b, typePath.offset, length);
1406         }
1407         // write type, and reserve space for values count
1408         bv.putShort(cw.newUTF8(desc)).putShort(0);
1409         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1410                 bv.length - 2);
1411         if (visible) {
1412             aw.next = ctanns;
1413             ctanns = aw;
1414         } else {
1415             aw.next = ictanns;
1416             ictanns = aw;
1417         }
1418         return aw;
1419     }
1420 
1421     @Override
1422     public void visitLineNumber(final int line, final Label start) {
1423         if (lineNumber == null) {
1424             lineNumber = new ByteVector();
1425         }
1426         ++lineNumberCount;
1427         lineNumber.putShort(start.position);
1428         lineNumber.putShort(line);
1429     }
1430 
1431     @Override
1432     public void visitMaxs(final int maxStack, final int maxLocals) {
1433         if (resize) {
1434             // replaces the temporary jump opcodes introduced by Label.resolve.
1435             if (ClassReader.RESIZE) {
1436                 resizeInstructions();
1437             } else {
1438                 throw new RuntimeException("Method code too large!");
1439             }
1440         }
1441         if (ClassReader.FRAMES && compute == FRAMES) {
1442             // completes the control flow graph with exception handler blocks
1443             Handler handler = firstHandler;
1444             while (handler != null) {
1445                 Label l = handler.start.getFirst();
1446                 Label h = handler.handler.getFirst();
1447                 Label e = handler.end.getFirst();
1448                 // computes the kind of the edges to 'h'
1449                 String t = handler.desc == null ? "java/lang/Throwable"
1450                         : handler.desc;
1451                 int kind = Frame.OBJECT | cw.addType(t);
1452                 // h is an exception handler
1453                 h.status |= Label.TARGET;
1454                 // adds 'h' as a successor of labels between 'start' and 'end'
1455                 while (l != e) {
1456                     // creates an edge to 'h'
1457                     Edge b = new Edge();
1458                     b.info = kind;
1459                     b.successor = h;
1460                     // adds it to the successors of 'l'
1461                     b.next = l.successors;
1462                     l.successors = b;
1463                     // goes to the next label
1464                     l = l.successor;
1465                 }
1466                 handler = handler.next;
1467             }
1468 
1469             // creates and visits the first (implicit) frame
1470             Frame f = labels.frame;
1471             Type[] args = Type.getArgumentTypes(descriptor);
1472             f.initInputFrame(cw, access, args, this.maxLocals);
1473             visitFrame(f);
1474 
1475             /*
1476              * fix point algorithm: mark the first basic block as 'changed'
1477              * (i.e. put it in the 'changed' list) and, while there are changed
1478              * basic blocks, choose one, mark it as unchanged, and update its
1479              * successors (which can be changed in the process).
1480              */
1481             int max = 0;
1482             Label changed = labels;
1483             while (changed != null) {
1484                 // removes a basic block from the list of changed basic blocks
1485                 Label l = changed;
1486                 changed = changed.next;
1487                 l.next = null;
1488                 f = l.frame;
1489                 // a reachable jump target must be stored in the stack map
1490                 if ((l.status & Label.TARGET) != 0) {
1491                     l.status |= Label.STORE;
1492                 }


1700         // ...and adds it to the successor list of the currentBlock block
1701         b.next = currentBlock.successors;
1702         currentBlock.successors = b;
1703     }
1704 
1705     /**
1706      * Ends the current basic block. This method must be used in the case where
1707      * the current basic block does not have any successor.
1708      */
1709     private void noSuccessor() {
1710         if (compute == FRAMES) {
1711             Label l = new Label();
1712             l.frame = new Frame();
1713             l.frame.owner = l;
1714             l.resolve(this, code.length, code.data);
1715             previousBlock.successor = l;
1716             previousBlock = l;
1717         } else {
1718             currentBlock.outputStackMax = maxStackSize;
1719         }

1720         currentBlock = null;
1721     }

1722 
1723     // ------------------------------------------------------------------------
1724     // Utility methods: stack map frames
1725     // ------------------------------------------------------------------------
1726 
1727     /**
1728      * Visits a frame that has been computed from scratch.
1729      *
1730      * @param f
1731      *            the frame that must be visited.
1732      */
1733     private void visitFrame(final Frame f) {
1734         int i, t;
1735         int nTop = 0;
1736         int nLocal = 0;
1737         int nStack = 0;
1738         int[] locals = f.inputLocals;
1739         int[] stacks = f.inputStack;
1740         // computes the number of locals (ignores TOP types that are just after
1741         // a LONG or a DOUBLE, and all trailing TOP types)


1772         for (i = 0; i < stacks.length; ++i) {
1773             t = stacks[i];
1774             frame[frameIndex++] = t;
1775             if (t == Frame.LONG || t == Frame.DOUBLE) {
1776                 ++i;
1777             }
1778         }
1779         endFrame();
1780     }
1781 
1782     /**
1783      * Visit the implicit first frame of this method.
1784      */
1785     private void visitImplicitFirstFrame() {
1786         // There can be at most descriptor.length() + 1 locals
1787         int frameIndex = startFrame(0, descriptor.length() + 1, 0);
1788         if ((access & Opcodes.ACC_STATIC) == 0) {
1789             if ((access & ACC_CONSTRUCTOR) == 0) {
1790                 frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
1791             } else {
1792                 frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS;
1793             }
1794         }
1795         int i = 1;
1796         loop: while (true) {
1797             int j = i;
1798             switch (descriptor.charAt(i++)) {
1799             case 'Z':
1800             case 'C':
1801             case 'B':
1802             case 'S':
1803             case 'I':
1804                 frame[frameIndex++] = 1; // Opcodes.INTEGER;
1805                 break;
1806             case 'F':
1807                 frame[frameIndex++] = 2; // Opcodes.FLOAT;
1808                 break;
1809             case 'J':
1810                 frame[frameIndex++] = 4; // Opcodes.LONG;
1811                 break;
1812             case 'D':
1813                 frame[frameIndex++] = 3; // Opcodes.DOUBLE;
1814                 break;
1815             case '[':
1816                 while (descriptor.charAt(i) == '[') {
1817                     ++i;
1818                 }
1819                 if (descriptor.charAt(i) == 'L') {
1820                     ++i;
1821                     while (descriptor.charAt(i) != ';') {
1822                         ++i;
1823                     }
1824                 }
1825                 frame[frameIndex++] = Frame.OBJECT
1826                         | cw.addType(descriptor.substring(j, ++i));
1827                 break;
1828             case 'L':
1829                 while (descriptor.charAt(i) != ';') {
1830                     ++i;
1831                 }
1832                 frame[frameIndex++] = Frame.OBJECT
1833                         | cw.addType(descriptor.substring(j + 1, i++));
1834                 break;
1835             default:
1836                 break loop;
1837             }
1838         }
1839         frame[1] = frameIndex - 3;
1840         endFrame();
1841     }
1842 
1843     /**
1844      * Starts the visit of a stack map frame.
1845      *
1846      * @param offset


2066             }
2067             cw.newUTF8("Code");
2068             size += 18 + code.length + 8 * handlerCount;
2069             if (localVar != null) {
2070                 cw.newUTF8("LocalVariableTable");
2071                 size += 8 + localVar.length;
2072             }
2073             if (localVarType != null) {
2074                 cw.newUTF8("LocalVariableTypeTable");
2075                 size += 8 + localVarType.length;
2076             }
2077             if (lineNumber != null) {
2078                 cw.newUTF8("LineNumberTable");
2079                 size += 8 + lineNumber.length;
2080             }
2081             if (stackMap != null) {
2082                 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2083                 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
2084                 size += 8 + stackMap.length;
2085             }
2086             if (ClassReader.ANNOTATIONS && ctanns != null) {
2087                 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2088                 size += 8 + ctanns.getSize();
2089             }
2090             if (ClassReader.ANNOTATIONS && ictanns != null) {
2091                 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2092                 size += 8 + ictanns.getSize();
2093             }
2094             if (cattrs != null) {
2095                 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2096                         maxLocals);
2097             }
2098         }
2099         if (exceptionCount > 0) {
2100             cw.newUTF8("Exceptions");
2101             size += 8 + 2 * exceptionCount;
2102         }
2103         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2104             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2105                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2106                 cw.newUTF8("Synthetic");
2107                 size += 6;
2108             }
2109         }
2110         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2111             cw.newUTF8("Deprecated");
2112             size += 6;
2113         }
2114         if (ClassReader.SIGNATURES && signature != null) {
2115             cw.newUTF8("Signature");
2116             cw.newUTF8(signature);
2117             size += 8;
2118         }
2119         if (methodParameters != null) {
2120             cw.newUTF8("MethodParameters");
2121             size += 7 + methodParameters.length;
2122         }
2123         if (ClassReader.ANNOTATIONS && annd != null) {
2124             cw.newUTF8("AnnotationDefault");
2125             size += 6 + annd.length;
2126         }
2127         if (ClassReader.ANNOTATIONS && anns != null) {
2128             cw.newUTF8("RuntimeVisibleAnnotations");
2129             size += 8 + anns.getSize();
2130         }
2131         if (ClassReader.ANNOTATIONS && ianns != null) {
2132             cw.newUTF8("RuntimeInvisibleAnnotations");
2133             size += 8 + ianns.getSize();
2134         }
2135         if (ClassReader.ANNOTATIONS && tanns != null) {
2136             cw.newUTF8("RuntimeVisibleTypeAnnotations");
2137             size += 8 + tanns.getSize();
2138         }
2139         if (ClassReader.ANNOTATIONS && itanns != null) {
2140             cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2141             size += 8 + itanns.getSize();
2142         }
2143         if (ClassReader.ANNOTATIONS && panns != null) {
2144             cw.newUTF8("RuntimeVisibleParameterAnnotations");
2145             size += 7 + 2 * (panns.length - synthetics);
2146             for (int i = panns.length - 1; i >= synthetics; --i) {
2147                 size += panns[i] == null ? 0 : panns[i].getSize();
2148             }
2149         }
2150         if (ClassReader.ANNOTATIONS && ipanns != null) {
2151             cw.newUTF8("RuntimeInvisibleParameterAnnotations");
2152             size += 7 + 2 * (ipanns.length - synthetics);
2153             for (int i = ipanns.length - 1; i >= synthetics; --i) {
2154                 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
2155             }
2156         }
2157         if (attrs != null) {
2158             size += attrs.getSize(cw, null, 0, -1, -1);
2159         }
2160         return size;
2161     }
2162 
2163     /**
2164      * Puts the bytecode of this method in the given byte vector.
2165      *
2166      * @param out
2167      *            the byte vector into which the bytecode of this method must be
2168      *            copied.
2169      */
2170     final void put(final ByteVector out) {


2176         if (classReaderOffset != 0) {
2177             out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
2178             return;
2179         }
2180         int attributeCount = 0;
2181         if (code.length > 0) {
2182             ++attributeCount;
2183         }
2184         if (exceptionCount > 0) {
2185             ++attributeCount;
2186         }
2187         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2188             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2189                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2190                 ++attributeCount;
2191             }
2192         }
2193         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2194             ++attributeCount;
2195         }
2196         if (ClassReader.SIGNATURES && signature != null) {
2197             ++attributeCount;
2198         }
2199         if (methodParameters != null) {
2200             ++attributeCount;
2201         }
2202         if (ClassReader.ANNOTATIONS && annd != null) {
2203             ++attributeCount;
2204         }
2205         if (ClassReader.ANNOTATIONS && anns != null) {
2206             ++attributeCount;
2207         }
2208         if (ClassReader.ANNOTATIONS && ianns != null) {
2209             ++attributeCount;
2210         }
2211         if (ClassReader.ANNOTATIONS && tanns != null) {
2212             ++attributeCount;
2213         }
2214         if (ClassReader.ANNOTATIONS && itanns != null) {
2215             ++attributeCount;
2216         }
2217         if (ClassReader.ANNOTATIONS && panns != null) {
2218             ++attributeCount;
2219         }
2220         if (ClassReader.ANNOTATIONS && ipanns != null) {
2221             ++attributeCount;
2222         }
2223         if (attrs != null) {
2224             attributeCount += attrs.getCount();
2225         }
2226         out.putShort(attributeCount);
2227         if (code.length > 0) {
2228             int size = 12 + code.length + 8 * handlerCount;
2229             if (localVar != null) {
2230                 size += 8 + localVar.length;
2231             }
2232             if (localVarType != null) {
2233                 size += 8 + localVarType.length;
2234             }
2235             if (lineNumber != null) {
2236                 size += 8 + lineNumber.length;
2237             }
2238             if (stackMap != null) {
2239                 size += 8 + stackMap.length;
2240             }
2241             if (ClassReader.ANNOTATIONS && ctanns != null) {
2242                 size += 8 + ctanns.getSize();
2243             }
2244             if (ClassReader.ANNOTATIONS && ictanns != null) {
2245                 size += 8 + ictanns.getSize();
2246             }
2247             if (cattrs != null) {
2248                 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2249                         maxLocals);
2250             }
2251             out.putShort(cw.newUTF8("Code")).putInt(size);
2252             out.putShort(maxStack).putShort(maxLocals);
2253             out.putInt(code.length).putByteArray(code.data, 0, code.length);
2254             out.putShort(handlerCount);
2255             if (handlerCount > 0) {
2256                 Handler h = firstHandler;
2257                 while (h != null) {
2258                     out.putShort(h.start.position).putShort(h.end.position)
2259                             .putShort(h.handler.position).putShort(h.type);
2260                     h = h.next;
2261                 }
2262             }
2263             attributeCount = 0;
2264             if (localVar != null) {
2265                 ++attributeCount;
2266             }
2267             if (localVarType != null) {
2268                 ++attributeCount;
2269             }
2270             if (lineNumber != null) {
2271                 ++attributeCount;
2272             }
2273             if (stackMap != null) {
2274                 ++attributeCount;
2275             }
2276             if (ClassReader.ANNOTATIONS && ctanns != null) {
2277                 ++attributeCount;
2278             }
2279             if (ClassReader.ANNOTATIONS && ictanns != null) {
2280                 ++attributeCount;
2281             }
2282             if (cattrs != null) {
2283                 attributeCount += cattrs.getCount();
2284             }
2285             out.putShort(attributeCount);
2286             if (localVar != null) {
2287                 out.putShort(cw.newUTF8("LocalVariableTable"));
2288                 out.putInt(localVar.length + 2).putShort(localVarCount);
2289                 out.putByteArray(localVar.data, 0, localVar.length);
2290             }
2291             if (localVarType != null) {
2292                 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
2293                 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
2294                 out.putByteArray(localVarType.data, 0, localVarType.length);
2295             }
2296             if (lineNumber != null) {
2297                 out.putShort(cw.newUTF8("LineNumberTable"));
2298                 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
2299                 out.putByteArray(lineNumber.data, 0, lineNumber.length);
2300             }
2301             if (stackMap != null) {
2302                 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2303                 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
2304                 out.putInt(stackMap.length + 2).putShort(frameCount);
2305                 out.putByteArray(stackMap.data, 0, stackMap.length);
2306             }
2307             if (ClassReader.ANNOTATIONS && ctanns != null) {
2308                 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2309                 ctanns.put(out);
2310             }
2311             if (ClassReader.ANNOTATIONS && ictanns != null) {
2312                 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2313                 ictanns.put(out);
2314             }
2315             if (cattrs != null) {
2316                 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
2317             }
2318         }
2319         if (exceptionCount > 0) {
2320             out.putShort(cw.newUTF8("Exceptions")).putInt(
2321                     2 * exceptionCount + 2);
2322             out.putShort(exceptionCount);
2323             for (int i = 0; i < exceptionCount; ++i) {
2324                 out.putShort(exceptions[i]);
2325             }
2326         }
2327         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2328             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2329                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2330                 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
2331             }
2332         }
2333         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2334             out.putShort(cw.newUTF8("Deprecated")).putInt(0);
2335         }
2336         if (ClassReader.SIGNATURES && signature != null) {
2337             out.putShort(cw.newUTF8("Signature")).putInt(2)
2338                     .putShort(cw.newUTF8(signature));
2339         }
2340         if (methodParameters != null) {
2341             out.putShort(cw.newUTF8("MethodParameters"));
2342             out.putInt(methodParameters.length + 1).putByte(
2343                     methodParametersCount);
2344             out.putByteArray(methodParameters.data, 0, methodParameters.length);
2345         }
2346         if (ClassReader.ANNOTATIONS && annd != null) {
2347             out.putShort(cw.newUTF8("AnnotationDefault"));
2348             out.putInt(annd.length);
2349             out.putByteArray(annd.data, 0, annd.length);
2350         }
2351         if (ClassReader.ANNOTATIONS && anns != null) {
2352             out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2353             anns.put(out);
2354         }
2355         if (ClassReader.ANNOTATIONS && ianns != null) {
2356             out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2357             ianns.put(out);
2358         }
2359         if (ClassReader.ANNOTATIONS && tanns != null) {
2360             out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2361             tanns.put(out);
2362         }
2363         if (ClassReader.ANNOTATIONS && itanns != null) {
2364             out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2365             itanns.put(out);
2366         }
2367         if (ClassReader.ANNOTATIONS && panns != null) {
2368             out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
2369             AnnotationWriter.put(panns, synthetics, out);
2370         }
2371         if (ClassReader.ANNOTATIONS && ipanns != null) {
2372             out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
2373             AnnotationWriter.put(ipanns, synthetics, out);
2374         }
2375         if (attrs != null) {
2376             attrs.put(cw, null, 0, -1, -1, out);
2377         }
2378     }
2379 
2380     // ------------------------------------------------------------------------
2381     // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
2382     // ------------------------------------------------------------------------
2383 
2384     /**
2385      * Resizes and replaces the temporary instructions inserted by
2386      * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
2387      * and instruction addresses consistent. This may require to resize other
2388      * existing instructions, or even to introduce new instructions: for
2389      * example, increasing the size of an instruction by 2 at the middle of a
2390      * method can increases the offset of an IFEQ instruction from 32766 to
2391      * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
2392      * 32765. This, in turn, may require to increase the size of another jump
2393      * instruction, and so on... All these operations are handled automatically
2394      * by this method.
2395      * <p>
2396      * <i>This method must be called after all the method that is being built
2397      * has been visited</i>. In particular, the {@link Label Label} objects used
2398      * to construct the method are no longer valid after this method has been
2399      * called.
2400      */
2401     private void resizeInstructions() {
2402         byte[] b = code.data; // bytecode of the method
2403         int u, v, label; // indexes in b
2404         int i, j; // loop indexes
2405         /*
2406          * 1st step: As explained above, resizing an instruction may require to
2407          * resize another one, which may require to resize yet another one, and
2408          * so on. The first step of the algorithm consists in finding all the
2409          * instructions that need to be resized, without modifying the code.
2410          * This is done by the following "fix point" algorithm:
2411          *
2412          * Parse the code to find the jump instructions whose offset will need
2413          * more than 2 bytes to be stored (the future offset is computed from
2414          * the current offset and from the number of bytes that will be inserted
2415          * or removed between the source and target instructions). For each such
2416          * instruction, adds an entry in (a copy of) the indexes and sizes
2417          * arrays (if this has not already been done in a previous iteration!).
2418          *
2419          * If at least one entry has been added during the previous step, go
2420          * back to the beginning, otherwise stop.
2421          *
2422          * In fact the real algorithm is complicated by the fact that the size
2423          * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
2424          * position in the bytecode (because of padding). In order to ensure the
2425          * convergence of the algorithm, the number of bytes to be added or
2426          * removed from these instructions is over estimated during the previous
2427          * loop, and computed exactly only after the loop is finished (this
2428          * requires another pass to parse the bytecode of the method).
2429          */
2430         int[] allIndexes = new int[0]; // copy of indexes
2431         int[] allSizes = new int[0]; // copy of sizes
2432         boolean[] resize; // instructions to be resized
2433         int newOffset; // future offset of a jump instruction
2434 
2435         resize = new boolean[code.length];
2436 
2437         // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
2438         int state = 3;
2439         do {
2440             if (state == 3) {
2441                 state = 2;
2442             }
2443             u = 0;
2444             while (u < b.length) {
2445                 int opcode = b[u] & 0xFF; // opcode of current instruction
2446                 int insert = 0; // bytes to be added after this instruction
2447 
2448                 switch (ClassWriter.TYPE[opcode]) {
2449                 case ClassWriter.NOARG_INSN:
2450                 case ClassWriter.IMPLVAR_INSN:
2451                     u += 1;
2452                     break;
2453                 case ClassWriter.LABEL_INSN:
2454                     if (opcode > 201) {
2455                         // converts temporary opcodes 202 to 217, 218 and
2456                         // 219 to IFEQ ... JSR (inclusive), IFNULL and
2457                         // IFNONNULL
2458                         opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2459                         label = u + readUnsignedShort(b, u + 1);
2460                     } else {
2461                         label = u + readShort(b, u + 1);
2462                     }
2463                     newOffset = getNewOffset(allIndexes, allSizes, u, label);
2464                     if (newOffset < Short.MIN_VALUE
2465                             || newOffset > Short.MAX_VALUE) {
2466                         if (!resize[u]) {
2467                             if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
2468                                 // two additional bytes will be required to
2469                                 // replace this GOTO or JSR instruction with
2470                                 // a GOTO_W or a JSR_W
2471                                 insert = 2;
2472                             } else {
2473                                 // five additional bytes will be required to
2474                                 // replace this IFxxx <l> instruction with
2475                                 // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
2476                                 // is the "opposite" opcode of IFxxx (i.e.,
2477                                 // IFNE for IFEQ) and where <l'> designates
2478                                 // the instruction just after the GOTO_W.
2479                                 insert = 5;
2480                             }
2481                             resize[u] = true;
2482                         }
2483                     }
2484                     u += 3;
2485                     break;
2486                 case ClassWriter.LABELW_INSN:
2487                     u += 5;
2488                     break;
2489                 case ClassWriter.TABL_INSN:
2490                     if (state == 1) {
2491                         // true number of bytes to be added (or removed)
2492                         // from this instruction = (future number of padding
2493                         // bytes - current number of padding byte) -
2494                         // previously over estimated variation =
2495                         // = ((3 - newOffset%4) - (3 - u%4)) - u%4
2496                         // = (-newOffset%4 + u%4) - u%4
2497                         // = -(newOffset & 3)
2498                         newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2499                         insert = -(newOffset & 3);
2500                     } else if (!resize[u]) {
2501                         // over estimation of the number of bytes to be
2502                         // added to this instruction = 3 - current number
2503                         // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
2504                         insert = u & 3;
2505                         resize[u] = true;
2506                     }
2507                     // skips instruction
2508                     u = u + 4 - (u & 3);
2509                     u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
2510                     break;
2511                 case ClassWriter.LOOK_INSN:
2512                     if (state == 1) {
2513                         // like TABL_INSN
2514                         newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2515                         insert = -(newOffset & 3);
2516                     } else if (!resize[u]) {
2517                         // like TABL_INSN
2518                         insert = u & 3;
2519                         resize[u] = true;
2520                     }
2521                     // skips instruction
2522                     u = u + 4 - (u & 3);
2523                     u += 8 * readInt(b, u + 4) + 8;
2524                     break;
2525                 case ClassWriter.WIDE_INSN:
2526                     opcode = b[u + 1] & 0xFF;
2527                     if (opcode == Opcodes.IINC) {
2528                         u += 6;
2529                     } else {
2530                         u += 4;
2531                     }
2532                     break;
2533                 case ClassWriter.VAR_INSN:
2534                 case ClassWriter.SBYTE_INSN:
2535                 case ClassWriter.LDC_INSN:
2536                     u += 2;
2537                     break;
2538                 case ClassWriter.SHORT_INSN:
2539                 case ClassWriter.LDCW_INSN:
2540                 case ClassWriter.FIELDORMETH_INSN:
2541                 case ClassWriter.TYPE_INSN:
2542                 case ClassWriter.IINC_INSN:
2543                     u += 3;
2544                     break;
2545                 case ClassWriter.ITFMETH_INSN:
2546                 case ClassWriter.INDYMETH_INSN:
2547                     u += 5;
2548                     break;
2549                 // case ClassWriter.MANA_INSN:
2550                 default:
2551                     u += 4;
2552                     break;
2553                 }
2554                 if (insert != 0) {
2555                     // adds a new (u, insert) entry in the allIndexes and
2556                     // allSizes arrays
2557                     int[] newIndexes = new int[allIndexes.length + 1];
2558                     int[] newSizes = new int[allSizes.length + 1];
2559                     System.arraycopy(allIndexes, 0, newIndexes, 0,
2560                             allIndexes.length);
2561                     System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
2562                     newIndexes[allIndexes.length] = u;
2563                     newSizes[allSizes.length] = insert;
2564                     allIndexes = newIndexes;
2565                     allSizes = newSizes;
2566                     if (insert > 0) {
2567                         state = 3;
2568                     }
2569                 }
2570             }
2571             if (state < 3) {
2572                 --state;
2573             }
2574         } while (state != 0);
2575 
2576         // 2nd step:
2577         // copies the bytecode of the method into a new bytevector, updates the
2578         // offsets, and inserts (or removes) bytes as requested.
2579 
2580         ByteVector newCode = new ByteVector(code.length);
2581 
2582         u = 0;
2583         while (u < code.length) {
2584             int opcode = b[u] & 0xFF;
2585             switch (ClassWriter.TYPE[opcode]) {
2586             case ClassWriter.NOARG_INSN:
2587             case ClassWriter.IMPLVAR_INSN:
2588                 newCode.putByte(opcode);
2589                 u += 1;
2590                 break;
2591             case ClassWriter.LABEL_INSN:
2592                 if (opcode > 201) {
2593                     // changes temporary opcodes 202 to 217 (inclusive), 218
2594                     // and 219 to IFEQ ... JSR (inclusive), IFNULL and
2595                     // IFNONNULL
2596                     opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2597                     label = u + readUnsignedShort(b, u + 1);
2598                 } else {
2599                     label = u + readShort(b, u + 1);
2600                 }
2601                 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2602                 if (resize[u]) {
2603                     // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
2604                     // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
2605                     // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
2606                     // and where <l'> designates the instruction just after
2607                     // the GOTO_W.
2608                     if (opcode == Opcodes.GOTO) {
2609                         newCode.putByte(200); // GOTO_W
2610                     } else if (opcode == Opcodes.JSR) {
2611                         newCode.putByte(201); // JSR_W
2612                     } else {
2613                         newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
2614                                 : opcode ^ 1);
2615                         newCode.putShort(8); // jump offset
2616                         newCode.putByte(200); // GOTO_W
2617                         // newOffset now computed from start of GOTO_W
2618                         newOffset -= 3;
2619                     }
2620                     newCode.putInt(newOffset);
2621                 } else {
2622                     newCode.putByte(opcode);
2623                     newCode.putShort(newOffset);
2624                 }
2625                 u += 3;
2626                 break;
2627             case ClassWriter.LABELW_INSN:
2628                 label = u + readInt(b, u + 1);
2629                 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2630                 newCode.putByte(opcode);
2631                 newCode.putInt(newOffset);
2632                 u += 5;
2633                 break;
2634             case ClassWriter.TABL_INSN:
2635                 // skips 0 to 3 padding bytes
2636                 v = u;
2637                 u = u + 4 - (v & 3);
2638                 // reads and copies instruction
2639                 newCode.putByte(Opcodes.TABLESWITCH);
2640                 newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
2641                 label = v + readInt(b, u);
2642                 u += 4;
2643                 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2644                 newCode.putInt(newOffset);
2645                 j = readInt(b, u);
2646                 u += 4;
2647                 newCode.putInt(j);
2648                 j = readInt(b, u) - j + 1;
2649                 u += 4;
2650                 newCode.putInt(readInt(b, u - 4));
2651                 for (; j > 0; --j) {
2652                     label = v + readInt(b, u);
2653                     u += 4;
2654                     newOffset = getNewOffset(allIndexes, allSizes, v, label);
2655                     newCode.putInt(newOffset);
2656                 }
2657                 break;
2658             case ClassWriter.LOOK_INSN:
2659                 // skips 0 to 3 padding bytes
2660                 v = u;
2661                 u = u + 4 - (v & 3);
2662                 // reads and copies instruction
2663                 newCode.putByte(Opcodes.LOOKUPSWITCH);
2664                 newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
2665                 label = v + readInt(b, u);
2666                 u += 4;
2667                 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2668                 newCode.putInt(newOffset);
2669                 j = readInt(b, u);
2670                 u += 4;
2671                 newCode.putInt(j);
2672                 for (; j > 0; --j) {
2673                     newCode.putInt(readInt(b, u));
2674                     u += 4;
2675                     label = v + readInt(b, u);
2676                     u += 4;
2677                     newOffset = getNewOffset(allIndexes, allSizes, v, label);
2678                     newCode.putInt(newOffset);
2679                 }
2680                 break;
2681             case ClassWriter.WIDE_INSN:
2682                 opcode = b[u + 1] & 0xFF;
2683                 if (opcode == Opcodes.IINC) {
2684                     newCode.putByteArray(b, u, 6);
2685                     u += 6;
2686                 } else {
2687                     newCode.putByteArray(b, u, 4);
2688                     u += 4;
2689                 }
2690                 break;
2691             case ClassWriter.VAR_INSN:
2692             case ClassWriter.SBYTE_INSN:
2693             case ClassWriter.LDC_INSN:
2694                 newCode.putByteArray(b, u, 2);
2695                 u += 2;
2696                 break;
2697             case ClassWriter.SHORT_INSN:
2698             case ClassWriter.LDCW_INSN:
2699             case ClassWriter.FIELDORMETH_INSN:
2700             case ClassWriter.TYPE_INSN:
2701             case ClassWriter.IINC_INSN:
2702                 newCode.putByteArray(b, u, 3);
2703                 u += 3;
2704                 break;
2705             case ClassWriter.ITFMETH_INSN:
2706             case ClassWriter.INDYMETH_INSN:
2707                 newCode.putByteArray(b, u, 5);
2708                 u += 5;
2709                 break;
2710             // case MANA_INSN:
2711             default:
2712                 newCode.putByteArray(b, u, 4);
2713                 u += 4;
2714                 break;
2715             }
2716         }
2717 
2718         // updates the stack map frame labels
2719         if (compute == FRAMES) {
2720             Label l = labels;
2721             while (l != null) {
2722                 /*
2723                  * Detects the labels that are just after an IF instruction that
2724                  * has been resized with the IFNOT GOTO_W pattern. These labels
2725                  * are now the target of a jump instruction (the IFNOT
2726                  * instruction). Note that we need the original label position
2727                  * here. getNewOffset must therefore never have been called for
2728                  * this label.
2729                  */
2730                 u = l.position - 3;
2731                 if (u >= 0 && resize[u]) {
2732                     l.status |= Label.TARGET;
2733                 }
2734                 getNewOffset(allIndexes, allSizes, l);
2735                 l = l.successor;
2736             }
2737             // Update the offsets in the uninitialized types
2738             if (cw.typeTable != null) {
2739                 for (i = 0; i < cw.typeTable.length; ++i) {
2740                     Item item = cw.typeTable[i];
2741                     if (item != null && item.type == ClassWriter.TYPE_UNINIT) {
2742                         item.intVal = getNewOffset(allIndexes, allSizes, 0,
2743                                 item.intVal);
2744                     }
2745                 }
2746             }
2747             // The stack map frames are not serialized yet, so we don't need
2748             // to update them. They will be serialized in visitMaxs.
2749         } else if (frameCount > 0) {
2750             /*
2751              * Resizing an existing stack map frame table is really hard. Not
2752              * only the table must be parsed to update the offets, but new
2753              * frames may be needed for jump instructions that were inserted by
2754              * this method. And updating the offsets or inserting frames can
2755              * change the format of the following frames, in case of packed
2756              * frames. In practice the whole table must be recomputed. For this
2757              * the frames are marked as potentially invalid. This will cause the
2758              * whole class to be reread and rewritten with the COMPUTE_FRAMES
2759              * option (see the ClassWriter.toByteArray method). This is not very
2760              * efficient but is much easier and requires much less code than any
2761              * other method I can think of.
2762              */
2763             cw.invalidFrames = true;
2764         }
2765         // updates the exception handler block labels
2766         Handler h = firstHandler;
2767         while (h != null) {
2768             getNewOffset(allIndexes, allSizes, h.start);
2769             getNewOffset(allIndexes, allSizes, h.end);
2770             getNewOffset(allIndexes, allSizes, h.handler);
2771             h = h.next;
2772         }
2773         // updates the instructions addresses in the
2774         // local var and line number tables
2775         for (i = 0; i < 2; ++i) {
2776             ByteVector bv = i == 0 ? localVar : localVarType;
2777             if (bv != null) {
2778                 b = bv.data;
2779                 u = 0;
2780                 while (u < bv.length) {
2781                     label = readUnsignedShort(b, u);
2782                     newOffset = getNewOffset(allIndexes, allSizes, 0, label);
2783                     writeShort(b, u, newOffset);
2784                     label += readUnsignedShort(b, u + 2);
2785                     newOffset = getNewOffset(allIndexes, allSizes, 0, label)
2786                             - newOffset;
2787                     writeShort(b, u + 2, newOffset);
2788                     u += 10;
2789                 }
2790             }
2791         }
2792         if (lineNumber != null) {
2793             b = lineNumber.data;
2794             u = 0;
2795             while (u < lineNumber.length) {
2796                 writeShort(
2797                         b,
2798                         u,
2799                         getNewOffset(allIndexes, allSizes, 0,
2800                                 readUnsignedShort(b, u)));
2801                 u += 4;
2802             }
2803         }
2804         // updates the labels of the other attributes
2805         Attribute attr = cattrs;
2806         while (attr != null) {
2807             Label[] labels = attr.getLabels();
2808             if (labels != null) {
2809                 for (i = labels.length - 1; i >= 0; --i) {
2810                     getNewOffset(allIndexes, allSizes, labels[i]);
2811                 }
2812             }
2813             attr = attr.next;
2814         }
2815 
2816         // replaces old bytecodes with new ones
2817         code = newCode;
2818     }
2819 
2820     /**
2821      * Reads an unsigned short value in the given byte array.
2822      *
2823      * @param b
2824      *            a byte array.
2825      * @param index
2826      *            the start index of the value to be read.
2827      * @return the read value.
2828      */
2829     static int readUnsignedShort(final byte[] b, final int index) {
2830         return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2831     }
2832 
2833     /**
2834      * Reads a signed short value in the given byte array.
2835      *
2836      * @param b
2837      *            a byte array.
2838      * @param index
2839      *            the start index of the value to be read.
2840      * @return the read value.
2841      */
2842     static short readShort(final byte[] b, final int index) {
2843         return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2844     }
2845 
2846     /**
2847      * Reads a signed int value in the given byte array.
2848      *
2849      * @param b
2850      *            a byte array.
2851      * @param index
2852      *            the start index of the value to be read.
2853      * @return the read value.
2854      */
2855     static int readInt(final byte[] b, final int index) {
2856         return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2857                 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2858     }
2859 
2860     /**
2861      * Writes a short value in the given byte array.
2862      *
2863      * @param b
2864      *            a byte array.
2865      * @param index
2866      *            where the first byte of the short value must be written.
2867      * @param s
2868      *            the value to be written in the given byte array.
2869      */
2870     static void writeShort(final byte[] b, final int index, final int s) {
2871         b[index] = (byte) (s >>> 8);
2872         b[index + 1] = (byte) s;
2873     }
2874 
2875     /**
2876      * Computes the future value of a bytecode offset.
2877      * <p>
2878      * Note: it is possible to have several entries for the same instruction in
2879      * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and
2880      * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b').
2881      *
2882      * @param indexes
2883      *            current positions of the instructions to be resized. Each
2884      *            instruction must be designated by the index of its <i>last</i>
2885      *            byte, plus one (or, in other words, by the index of the
2886      *            <i>first</i> byte of the <i>next</i> instruction).
2887      * @param sizes
2888      *            the number of bytes to be <i>added</i> to the above
2889      *            instructions. More precisely, for each i < <tt>len</tt>,
2890      *            <tt>sizes</tt>[i] bytes will be added at the end of the
2891      *            instruction designated by <tt>indexes</tt>[i] or, if
2892      *            <tt>sizes</tt>[i] is negative, the <i>last</i> |
2893      *            <tt>sizes[i]</tt>| bytes of the instruction will be removed
2894      *            (the instruction size <i>must not</i> become negative or
2895      *            null).
2896      * @param begin
2897      *            index of the first byte of the source instruction.
2898      * @param end
2899      *            index of the first byte of the target instruction.
2900      * @return the future value of the given bytecode offset.
2901      */
2902     static int getNewOffset(final int[] indexes, final int[] sizes,
2903             final int begin, final int end) {
2904         int offset = end - begin;
2905         for (int i = 0; i < indexes.length; ++i) {
2906             if (begin < indexes[i] && indexes[i] <= end) {
2907                 // forward jump
2908                 offset += sizes[i];
2909             } else if (end < indexes[i] && indexes[i] <= begin) {
2910                 // backward jump
2911                 offset -= sizes[i];
2912             }
2913         }
2914         return offset;
2915     }
2916 
2917     /**
2918      * Updates the offset of the given label.
2919      *
2920      * @param indexes
2921      *            current positions of the instructions to be resized. Each
2922      *            instruction must be designated by the index of its <i>last</i>
2923      *            byte, plus one (or, in other words, by the index of the
2924      *            <i>first</i> byte of the <i>next</i> instruction).
2925      * @param sizes
2926      *            the number of bytes to be <i>added</i> to the above
2927      *            instructions. More precisely, for each i < <tt>len</tt>,
2928      *            <tt>sizes</tt>[i] bytes will be added at the end of the
2929      *            instruction designated by <tt>indexes</tt>[i] or, if
2930      *            <tt>sizes</tt>[i] is negative, the <i>last</i> |
2931      *            <tt>sizes[i]</tt>| bytes of the instruction will be removed
2932      *            (the instruction size <i>must not</i> become negative or
2933      *            null).
2934      * @param label
2935      *            the label whose offset must be updated.
2936      */
2937     static void getNewOffset(final int[] indexes, final int[] sizes,
2938             final Label label) {
2939         if ((label.status & Label.RESIZED) == 0) {
2940             label.position = getNewOffset(indexes, sizes, 0, label.position);
2941             label.status |= Label.RESIZED;
2942         }
2943     }
2944 }


 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.


 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     /**


 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     /**


 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             }


 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                     }


 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) {


 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) {


 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


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,


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                 }


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)


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


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) {


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 }
< prev index next >