View Javadoc
1   /*
2    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3    *
4    * This code is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU General Public License version 2 only, as
6    * published by the Free Software Foundation.  Oracle designates this
7    * particular file as subject to the "Classpath" exception as provided
8    * by Oracle in the LICENSE file that accompanied this code.
9    *
10   * This code is distributed in the hope that it will be useful, but WITHOUT
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13   * version 2 for more details (a copy is included in the LICENSE file that
14   * accompanied this code).
15   *
16   * You should have received a copy of the GNU General Public License version
17   * 2 along with this work; if not, write to the Free Software Foundation,
18   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19   *
20   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21   * or visit www.oracle.com if you need additional information or have any
22   * questions.
23   */
24  
25  /*
26   * This file is available under and governed by the GNU General Public
27   * License version 2 only, as published by the Free Software Foundation.
28   * However, the following notice accompanied the original version of this
29   * file:
30   *
31   * ASM: a very small and fast Java bytecode manipulation framework
32   * Copyright (c) 2000-2011 INRIA, France Telecom
33   * All rights reserved.
34   *
35   * Redistribution and use in source and binary forms, with or without
36   * modification, are permitted provided that the following conditions
37   * are met:
38   * 1. Redistributions of source code must retain the above copyright
39   *    notice, this list of conditions and the following disclaimer.
40   * 2. Redistributions in binary form must reproduce the above copyright
41   *    notice, this list of conditions and the following disclaimer in the
42   *    documentation and/or other materials provided with the distribution.
43   * 3. Neither the name of the copyright holders nor the names of its
44   *    contributors may be used to endorse or promote products derived from
45   *    this software without specific prior written permission.
46   *
47   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57   * THE POSSIBILITY OF SUCH DAMAGE.
58   */
59  package jdk.internal.org.objectweb.asm;
60  
61  /**
62   * A {@link MethodVisitor} that generates methods in bytecode form. Each visit
63   * method of this class appends the bytecode corresponding to the visited
64   * instruction to a byte vector, in the order these methods are called.
65   *
66   * @author Eric Bruneton
67   * @author Eugene Kuleshov
68   */
69  class MethodWriter extends MethodVisitor {
70  
71      /**
72       * Pseudo access flag used to denote constructors.
73       */
74      static final int ACC_CONSTRUCTOR = 0x80000;
75  
76      /**
77       * Frame has exactly the same locals as the previous stack map frame and
78       * number of stack items is zero.
79       */
80      static final int SAME_FRAME = 0; // to 63 (0-3f)
81  
82      /**
83       * Frame has exactly the same locals as the previous stack map frame and
84       * number of stack items is 1
85       */
86      static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
87  
88      /**
89       * Reserved for future use
90       */
91      static final int RESERVED = 128;
92  
93      /**
94       * Frame has exactly the same locals as the previous stack map frame and
95       * number of stack items is 1. Offset is bigger then 63;
96       */
97      static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
98  
99      /**
100      * Frame where current locals are the same as the locals in the previous
101      * frame, except that the k last locals are absent. The value of k is given
102      * by the formula 251-frame_type.
103      */
104     static final int CHOP_FRAME = 248; // to 250 (f8-fA)
105 
106     /**
107      * Frame has exactly the same locals as the previous stack map frame and
108      * number of stack items is zero. Offset is bigger then 63;
109      */
110     static final int SAME_FRAME_EXTENDED = 251; // fb
111 
112     /**
113      * Frame where current locals are the same as the locals in the previous
114      * frame, except that k additional locals are defined. The value of k is
115      * given by the formula frame_type-251.
116      */
117     static final int APPEND_FRAME = 252; // to 254 // fc-fe
118 
119     /**
120      * Full frame
121      */
122     static final int FULL_FRAME = 255; // ff
123 
124     /**
125      * Indicates that the stack map frames must be recomputed from scratch. In
126      * this case the maximum stack size and number of local variables is also
127      * recomputed from scratch.
128      *
129      * @see #compute
130      */
131     private static final int FRAMES = 0;
132 
133     /**
134      * Indicates that the maximum stack size and number of local variables must
135      * be automatically computed.
136      *
137      * @see #compute
138      */
139     private static final int MAXS = 1;
140 
141     /**
142      * Indicates that nothing must be automatically computed.
143      *
144      * @see #compute
145      */
146     private static final int NOTHING = 2;
147 
148     /**
149      * The class writer to which this method must be added.
150      */
151     final ClassWriter cw;
152 
153     /**
154      * Access flags of this method.
155      */
156     private int access;
157 
158     /**
159      * The index of the constant pool item that contains the name of this
160      * method.
161      */
162     private final int name;
163 
164     /**
165      * The index of the constant pool item that contains the descriptor of this
166      * method.
167      */
168     private final int desc;
169 
170     /**
171      * The descriptor of this method.
172      */
173     private final String descriptor;
174 
175     /**
176      * The signature of this method.
177      */
178     String signature;
179 
180     /**
181      * If not zero, indicates that the code of this method must be copied from
182      * the ClassReader associated to this writer in <code>cw.cr</code>. More
183      * precisely, this field gives the index of the first byte to copied from
184      * <code>cw.cr.b</code>.
185      */
186     int classReaderOffset;
187 
188     /**
189      * If not zero, indicates that the code of this method must be copied from
190      * the ClassReader associated to this writer in <code>cw.cr</code>. More
191      * precisely, this field gives the number of bytes to copied from
192      * <code>cw.cr.b</code>.
193      */
194     int classReaderLength;
195 
196     /**
197      * Number of exceptions that can be thrown by this method.
198      */
199     int exceptionCount;
200 
201     /**
202      * The exceptions that can be thrown by this method. More precisely, this
203      * array contains the indexes of the constant pool items that contain the
204      * internal names of these exception classes.
205      */
206     int[] exceptions;
207 
208     /**
209      * The annotation default attribute of this method. May be <tt>null</tt>.
210      */
211     private ByteVector annd;
212 
213     /**
214      * The runtime visible annotations of this method. May be <tt>null</tt>.
215      */
216     private AnnotationWriter anns;
217 
218     /**
219      * The runtime invisible annotations of this method. May be <tt>null</tt>.
220      */
221     private AnnotationWriter ianns;
222 
223     /**
224      * The runtime visible type annotations of this method. May be <tt>null</tt>
225      * .
226      */
227     private AnnotationWriter tanns;
228 
229     /**
230      * The runtime invisible type annotations of this method. May be
231      * <tt>null</tt>.
232      */
233     private AnnotationWriter itanns;
234 
235     /**
236      * The runtime visible parameter annotations of this method. May be
237      * <tt>null</tt>.
238      */
239     private AnnotationWriter[] panns;
240 
241     /**
242      * The runtime invisible parameter annotations of this method. May be
243      * <tt>null</tt>.
244      */
245     private AnnotationWriter[] ipanns;
246 
247     /**
248      * The number of synthetic parameters of this method.
249      */
250     private int synthetics;
251 
252     /**
253      * The non standard attributes of the method.
254      */
255     private Attribute attrs;
256 
257     /**
258      * The bytecode of this method.
259      */
260     private ByteVector code = new ByteVector();
261 
262     /**
263      * Maximum stack size of this method.
264      */
265     private int maxStack;
266 
267     /**
268      * Maximum number of local variables for this method.
269      */
270     private int maxLocals;
271 
272     /**
273      * Number of local variables in the current stack map frame.
274      */
275     private int currentLocals;
276 
277     /**
278      * Number of stack map frames in the StackMapTable attribute.
279      */
280     private int frameCount;
281 
282     /**
283      * The StackMapTable attribute.
284      */
285     private ByteVector stackMap;
286 
287     /**
288      * The offset of the last frame that was written in the StackMapTable
289      * attribute.
290      */
291     private int previousFrameOffset;
292 
293     /**
294      * The last frame that was written in the StackMapTable attribute.
295      *
296      * @see #frame
297      */
298     private int[] previousFrame;
299 
300     /**
301      * The current stack map frame. The first element contains the offset of the
302      * instruction to which the frame corresponds, the second element is the
303      * number of locals and the third one is the number of stack elements. The
304      * local variables start at index 3 and are followed by the operand stack
305      * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] =
306      * nStack, frame[3] = nLocal. All types are encoded as integers, with the
307      * same format as the one used in {@link Label}, but limited to BASE types.
308      */
309     private int[] frame;
310 
311     /**
312      * Number of elements in the exception handler list.
313      */
314     private int handlerCount;
315 
316     /**
317      * The first element in the exception handler list.
318      */
319     private Handler firstHandler;
320 
321     /**
322      * The last element in the exception handler list.
323      */
324     private Handler lastHandler;
325 
326     /**
327      * Number of entries in the MethodParameters attribute.
328      */
329     private int methodParametersCount;
330 
331     /**
332      * The MethodParameters attribute.
333      */
334     private ByteVector methodParameters;
335 
336     /**
337      * Number of entries in the LocalVariableTable attribute.
338      */
339     private int localVarCount;
340 
341     /**
342      * The LocalVariableTable attribute.
343      */
344     private ByteVector localVar;
345 
346     /**
347      * Number of entries in the LocalVariableTypeTable attribute.
348      */
349     private int localVarTypeCount;
350 
351     /**
352      * The LocalVariableTypeTable attribute.
353      */
354     private ByteVector localVarType;
355 
356     /**
357      * Number of entries in the LineNumberTable attribute.
358      */
359     private int lineNumberCount;
360 
361     /**
362      * The LineNumberTable attribute.
363      */
364     private ByteVector lineNumber;
365 
366     /**
367      * The start offset of the last visited instruction.
368      */
369     private int lastCodeOffset;
370 
371     /**
372      * The runtime visible type annotations of the code. May be <tt>null</tt>.
373      */
374     private AnnotationWriter ctanns;
375 
376     /**
377      * The runtime invisible type annotations of the code. May be <tt>null</tt>.
378      */
379     private AnnotationWriter ictanns;
380 
381     /**
382      * The non standard attributes of the method's code.
383      */
384     private Attribute cattrs;
385 
386     /**
387      * Indicates if some jump instructions are too small and need to be resized.
388      */
389     private boolean resize;
390 
391     /**
392      * The number of subroutines in this method.
393      */
394     private int subroutines;
395 
396     // ------------------------------------------------------------------------
397 
398     /*
399      * Fields for the control flow graph analysis algorithm (used to compute the
400      * maximum stack size). A control flow graph contains one node per "basic
401      * block", and one edge per "jump" from one basic block to another. Each
402      * node (i.e., each basic block) is represented by the Label object that
403      * corresponds to the first instruction of this basic block. Each node also
404      * stores the list of its successors in the graph, as a linked list of Edge
405      * objects.
406      */
407 
408     /**
409      * Indicates what must be automatically computed.
410      *
411      * @see #FRAMES
412      * @see #MAXS
413      * @see #NOTHING
414      */
415     private final int compute;
416 
417     /**
418      * A list of labels. This list is the list of basic blocks in the method,
419      * i.e. a list of Label objects linked to each other by their
420      * {@link Label#successor} field, in the order they are visited by
421      * {@link MethodVisitor#visitLabel}, and starting with the first basic
422      * block.
423      */
424     private Label labels;
425 
426     /**
427      * The previous basic block.
428      */
429     private Label previousBlock;
430 
431     /**
432      * The current basic block.
433      */
434     private Label currentBlock;
435 
436     /**
437      * The (relative) stack size after the last visited instruction. This size
438      * is relative to the beginning of the current basic block, i.e., the true
439      * stack size after the last visited instruction is equal to the
440      * {@link Label#inputStackTop beginStackSize} of the current basic block
441      * plus <tt>stackSize</tt>.
442      */
443     private int stackSize;
444 
445     /**
446      * The (relative) maximum stack size after the last visited instruction.
447      * This size is relative to the beginning of the current basic block, i.e.,
448      * the true maximum stack size after the last visited instruction is equal
449      * to the {@link Label#inputStackTop beginStackSize} of the current basic
450      * block plus <tt>stackSize</tt>.
451      */
452     private int maxStackSize;
453 
454     // ------------------------------------------------------------------------
455     // Constructor
456     // ------------------------------------------------------------------------
457 
458     /**
459      * Constructs a new {@link MethodWriter}.
460      *
461      * @param cw
462      *            the class writer in which the method must be added.
463      * @param access
464      *            the method's access flags (see {@link Opcodes}).
465      * @param name
466      *            the method's name.
467      * @param desc
468      *            the method's descriptor (see {@link Type}).
469      * @param signature
470      *            the method's signature. May be <tt>null</tt>.
471      * @param exceptions
472      *            the internal names of the method's exceptions. May be
473      *            <tt>null</tt>.
474      * @param computeMaxs
475      *            <tt>true</tt> if the maximum stack size and number of local
476      *            variables must be automatically computed.
477      * @param computeFrames
478      *            <tt>true</tt> if the stack map tables must be recomputed from
479      *            scratch.
480      */
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             }
618             aw.next = ipanns[parameter];
619             ipanns[parameter] = aw;
620         }
621         return aw;
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                     }
690                 }
691             }
692 
693             switch (type) {
694             case Opcodes.F_FULL:
695                 currentLocals = nLocal;
696                 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal);
697                 for (int i = 0; i < nLocal; ++i) {
698                     writeFrameType(local[i]);
699                 }
700                 stackMap.putShort(nStack);
701                 for (int i = 0; i < nStack; ++i) {
702                     writeFrameType(stack[i]);
703                 }
704                 break;
705             case Opcodes.F_APPEND:
706                 currentLocals += nLocal;
707                 stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta);
708                 for (int i = 0; i < nLocal; ++i) {
709                     writeFrameType(local[i]);
710                 }
711                 break;
712             case Opcodes.F_CHOP:
713                 currentLocals -= nLocal;
714                 stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta);
715                 break;
716             case Opcodes.F_SAME:
717                 if (delta < 64) {
718                     stackMap.putByte(delta);
719                 } else {
720                     stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
721                 }
722                 break;
723             case Opcodes.F_SAME1:
724                 if (delta < 64) {
725                     stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
726                 } else {
727                     stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
728                             .putShort(delta);
729                 }
730                 writeFrameType(stack[0]);
731                 break;
732             }
733 
734             previousFrameOffset = code.length;
735             ++frameCount;
736         }
737 
738         maxStack = Math.max(maxStack, nStack);
739         maxLocals = Math.max(maxLocals, currentLocals);
740     }
741 
742     @Override
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) {
819             // updates max locals
820             int n;
821             if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
822                     || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) {
823                 n = var + 2;
824             } else {
825                 n = var + 1;
826             }
827             if (n > maxLocals) {
828                 maxLocals = n;
829             }
830         }
831         // adds the instruction to the bytecode of the method
832         if (var < 4 && opcode != Opcodes.RET) {
833             int opt;
834             if (opcode < Opcodes.ISTORE) {
835                 /* ILOAD_0 */
836                 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
837             } else {
838                 /* ISTORE_0 */
839                 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
840             }
841             code.putByte(opt);
842         } else if (var >= 256) {
843             code.putByte(196 /* WIDE */).put12(opcode, var);
844         } else {
845             code.put11(opcode, var);
846         }
847         if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
848             visitLabel(new Label());
849         }
850     }
851 
852     @Override
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) {
942                     size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
943                 } else {
944                     size = stackSize - (argSize >> 2) + (argSize & 0x03);
945                 }
946                 // updates current and max stack sizes
947                 if (size > maxStackSize) {
948                     maxStackSize = size;
949                 }
950                 stackSize = size;
951             }
952         }
953         // adds the instruction to the bytecode of the method
954         if (opcode == Opcodes.INVOKEINTERFACE) {
955             if (argSize == 0) {
956                 argSize = Type.getArgumentsAndReturnSizes(desc);
957                 i.intVal = argSize;
958             }
959             code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
960         } else {
961             code.put12(opcode, i.index);
962         }
963     }
964 
965     @Override
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
1211     public void visitTableSwitchInsn(final int min, final int max,
1212             final Label dflt, final Label... labels) {
1213         lastCodeOffset = code.length;
1214         // adds the instruction to the bytecode of the method
1215         int source = code.length;
1216         code.putByte(Opcodes.TABLESWITCH);
1217         code.putByteArray(null, 0, (4 - code.length % 4) % 4);
1218         dflt.put(this, code, source, true);
1219         code.putInt(min).putInt(max);
1220         for (int i = 0; i < labels.length; ++i) {
1221             labels[i].put(this, code, source, true);
1222         }
1223         // updates currentBlock
1224         visitSwitchInsn(dflt, labels);
1225     }
1226 
1227     @Override
1228     public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
1229             final Label[] labels) {
1230         lastCodeOffset = code.length;
1231         // adds the instruction to the bytecode of the method
1232         int source = code.length;
1233         code.putByte(Opcodes.LOOKUPSWITCH);
1234         code.putByteArray(null, 0, (4 - code.length % 4) % 4);
1235         dflt.put(this, code, source, true);
1236         code.putInt(labels.length);
1237         for (int i = 0; i < labels.length; ++i) {
1238             code.putInt(keys[i]);
1239             labels[i].put(this, code, source, true);
1240         }
1241         // updates currentBlock
1242         visitSwitchInsn(dflt, labels);
1243     }
1244 
1245     private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1246         // Label currentBlock = this.currentBlock;
1247         if (currentBlock != null) {
1248             if (compute == FRAMES) {
1249                 currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1250                 // adds current block successors
1251                 addSuccessor(Edge.NORMAL, dflt);
1252                 dflt.getFirst().status |= Label.TARGET;
1253                 for (int i = 0; i < labels.length; ++i) {
1254                     addSuccessor(Edge.NORMAL, labels[i]);
1255                     labels[i].getFirst().status |= Label.TARGET;
1256                 }
1257             } else {
1258                 // updates current stack size (max stack size unchanged)
1259                 --stackSize;
1260                 // adds current block successors
1261                 addSuccessor(stackSize, dflt);
1262                 for (int i = 0; i < labels.length; ++i) {
1263                     addSuccessor(stackSize, labels[i]);
1264                 }
1265             }
1266             // ends current block
1267             noSuccessor();
1268         }
1269     }
1270 
1271     @Override
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,
1357             final int index) {
1358         if (signature != null) {
1359             if (localVarType == null) {
1360                 localVarType = new ByteVector();
1361             }
1362             ++localVarTypeCount;
1363             localVarType.putShort(start.position)
1364                     .putShort(end.position - start.position)
1365                     .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature))
1366                     .putShort(index);
1367         }
1368         if (localVar == null) {
1369             localVar = new ByteVector();
1370         }
1371         ++localVarCount;
1372         localVar.putShort(start.position)
1373                 .putShort(end.position - start.position)
1374                 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc))
1375                 .putShort(index);
1376         if (compute != NOTHING) {
1377             // updates max locals
1378             char c = desc.charAt(0);
1379             int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1380             if (n > maxLocals) {
1381                 maxLocals = n;
1382             }
1383         }
1384     }
1385 
1386     @Override
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 (ClassReader.FRAMES && compute == FRAMES) {
1434             // completes the control flow graph with exception handler blocks
1435             Handler handler = firstHandler;
1436             while (handler != null) {
1437                 Label l = handler.start.getFirst();
1438                 Label h = handler.handler.getFirst();
1439                 Label e = handler.end.getFirst();
1440                 // computes the kind of the edges to 'h'
1441                 String t = handler.desc == null ? "java/lang/Throwable"
1442                         : handler.desc;
1443                 int kind = Frame.OBJECT | cw.addType(t);
1444                 // h is an exception handler
1445                 h.status |= Label.TARGET;
1446                 // adds 'h' as a successor of labels between 'start' and 'end'
1447                 while (l != e) {
1448                     // creates an edge to 'h'
1449                     Edge b = new Edge();
1450                     b.info = kind;
1451                     b.successor = h;
1452                     // adds it to the successors of 'l'
1453                     b.next = l.successors;
1454                     l.successors = b;
1455                     // goes to the next label
1456                     l = l.successor;
1457                 }
1458                 handler = handler.next;
1459             }
1460 
1461             // creates and visits the first (implicit) frame
1462             Frame f = labels.frame;
1463             Type[] args = Type.getArgumentTypes(descriptor);
1464             f.initInputFrame(cw, access, args, this.maxLocals);
1465             visitFrame(f);
1466 
1467             /*
1468              * fix point algorithm: mark the first basic block as 'changed'
1469              * (i.e. put it in the 'changed' list) and, while there are changed
1470              * basic blocks, choose one, mark it as unchanged, and update its
1471              * successors (which can be changed in the process).
1472              */
1473             int max = 0;
1474             Label changed = labels;
1475             while (changed != null) {
1476                 // removes a basic block from the list of changed basic blocks
1477                 Label l = changed;
1478                 changed = changed.next;
1479                 l.next = null;
1480                 f = l.frame;
1481                 // a reachable jump target must be stored in the stack map
1482                 if ((l.status & Label.TARGET) != 0) {
1483                     l.status |= Label.STORE;
1484                 }
1485                 // all visited labels are reachable, by definition
1486                 l.status |= Label.REACHABLE;
1487                 // updates the (absolute) maximum stack size
1488                 int blockMax = f.inputStack.length + l.outputStackMax;
1489                 if (blockMax > max) {
1490                     max = blockMax;
1491                 }
1492                 // updates the successors of the current basic block
1493                 Edge e = l.successors;
1494                 while (e != null) {
1495                     Label n = e.successor.getFirst();
1496                     boolean change = f.merge(cw, n.frame, e.info);
1497                     if (change && n.next == null) {
1498                         // if n has changed and is not already in the 'changed'
1499                         // list, adds it to this list
1500                         n.next = changed;
1501                         changed = n;
1502                     }
1503                     e = e.next;
1504                 }
1505             }
1506 
1507             // visits all the frames that must be stored in the stack map
1508             Label l = labels;
1509             while (l != null) {
1510                 f = l.frame;
1511                 if ((l.status & Label.STORE) != 0) {
1512                     visitFrame(f);
1513                 }
1514                 if ((l.status & Label.REACHABLE) == 0) {
1515                     // finds start and end of dead basic block
1516                     Label k = l.successor;
1517                     int start = l.position;
1518                     int end = (k == null ? code.length : k.position) - 1;
1519                     // if non empty basic block
1520                     if (end >= start) {
1521                         max = Math.max(max, 1);
1522                         // replaces instructions with NOP ... NOP ATHROW
1523                         for (int i = start; i < end; ++i) {
1524                             code.data[i] = Opcodes.NOP;
1525                         }
1526                         code.data[end] = (byte) Opcodes.ATHROW;
1527                         // emits a frame for this unreachable block
1528                         int frameIndex = startFrame(start, 0, 1);
1529                         frame[frameIndex] = Frame.OBJECT
1530                                 | cw.addType("java/lang/Throwable");
1531                         endFrame();
1532                         // removes the start-end range from the exception
1533                         // handlers
1534                         firstHandler = Handler.remove(firstHandler, l, k);
1535                     }
1536                 }
1537                 l = l.successor;
1538             }
1539 
1540             handler = firstHandler;
1541             handlerCount = 0;
1542             while (handler != null) {
1543                 handlerCount += 1;
1544                 handler = handler.next;
1545             }
1546 
1547             this.maxStack = max;
1548         } else if (compute == MAXS) {
1549             // completes the control flow graph with exception handler blocks
1550             Handler handler = firstHandler;
1551             while (handler != null) {
1552                 Label l = handler.start;
1553                 Label h = handler.handler;
1554                 Label e = handler.end;
1555                 // adds 'h' as a successor of labels between 'start' and 'end'
1556                 while (l != e) {
1557                     // creates an edge to 'h'
1558                     Edge b = new Edge();
1559                     b.info = Edge.EXCEPTION;
1560                     b.successor = h;
1561                     // adds it to the successors of 'l'
1562                     if ((l.status & Label.JSR) == 0) {
1563                         b.next = l.successors;
1564                         l.successors = b;
1565                     } else {
1566                         // if l is a JSR block, adds b after the first two edges
1567                         // to preserve the hypothesis about JSR block successors
1568                         // order (see {@link #visitJumpInsn})
1569                         b.next = l.successors.next.next;
1570                         l.successors.next.next = b;
1571                     }
1572                     // goes to the next label
1573                     l = l.successor;
1574                 }
1575                 handler = handler.next;
1576             }
1577 
1578             if (subroutines > 0) {
1579                 // completes the control flow graph with the RET successors
1580                 /*
1581                  * first step: finds the subroutines. This step determines, for
1582                  * each basic block, to which subroutine(s) it belongs.
1583                  */
1584                 // finds the basic blocks that belong to the "main" subroutine
1585                 int id = 0;
1586                 labels.visitSubroutine(null, 1, subroutines);
1587                 // finds the basic blocks that belong to the real subroutines
1588                 Label l = labels;
1589                 while (l != null) {
1590                     if ((l.status & Label.JSR) != 0) {
1591                         // the subroutine is defined by l's TARGET, not by l
1592                         Label subroutine = l.successors.next.successor;
1593                         // if this subroutine has not been visited yet...
1594                         if ((subroutine.status & Label.VISITED) == 0) {
1595                             // ...assigns it a new id and finds its basic blocks
1596                             id += 1;
1597                             subroutine.visitSubroutine(null, (id / 32L) << 32
1598                                     | (1L << (id % 32)), subroutines);
1599                         }
1600                     }
1601                     l = l.successor;
1602                 }
1603                 // second step: finds the successors of RET blocks
1604                 l = labels;
1605                 while (l != null) {
1606                     if ((l.status & Label.JSR) != 0) {
1607                         Label L = labels;
1608                         while (L != null) {
1609                             L.status &= ~Label.VISITED2;
1610                             L = L.successor;
1611                         }
1612                         // the subroutine is defined by l's TARGET, not by l
1613                         Label subroutine = l.successors.next.successor;
1614                         subroutine.visitSubroutine(l, 0, subroutines);
1615                     }
1616                     l = l.successor;
1617                 }
1618             }
1619 
1620             /*
1621              * control flow analysis algorithm: while the block stack is not
1622              * empty, pop a block from this stack, update the max stack size,
1623              * compute the true (non relative) begin stack size of the
1624              * successors of this block, and push these successors onto the
1625              * stack (unless they have already been pushed onto the stack).
1626              * Note: by hypothesis, the {@link Label#inputStackTop} of the
1627              * blocks in the block stack are the true (non relative) beginning
1628              * stack sizes of these blocks.
1629              */
1630             int max = 0;
1631             Label stack = labels;
1632             while (stack != null) {
1633                 // pops a block from the stack
1634                 Label l = stack;
1635                 stack = stack.next;
1636                 // computes the true (non relative) max stack size of this block
1637                 int start = l.inputStackTop;
1638                 int blockMax = start + l.outputStackMax;
1639                 // updates the global max stack size
1640                 if (blockMax > max) {
1641                     max = blockMax;
1642                 }
1643                 // analyzes the successors of the block
1644                 Edge b = l.successors;
1645                 if ((l.status & Label.JSR) != 0) {
1646                     // ignores the first edge of JSR blocks (virtual successor)
1647                     b = b.next;
1648                 }
1649                 while (b != null) {
1650                     l = b.successor;
1651                     // if this successor has not already been pushed...
1652                     if ((l.status & Label.PUSHED) == 0) {
1653                         // computes its true beginning stack size...
1654                         l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start
1655                                 + b.info;
1656                         // ...and pushes it onto the stack
1657                         l.status |= Label.PUSHED;
1658                         l.next = stack;
1659                         stack = l;
1660                     }
1661                     b = b.next;
1662                 }
1663             }
1664             this.maxStack = Math.max(maxStack, max);
1665         } else {
1666             this.maxStack = maxStack;
1667             this.maxLocals = maxLocals;
1668         }
1669     }
1670 
1671     @Override
1672     public void visitEnd() {
1673     }
1674 
1675     // ------------------------------------------------------------------------
1676     // Utility methods: control flow analysis algorithm
1677     // ------------------------------------------------------------------------
1678 
1679     /**
1680      * Adds a successor to the {@link #currentBlock currentBlock} block.
1681      *
1682      * @param info
1683      *            information about the control flow edge to be added.
1684      * @param successor
1685      *            the successor block to be added to the current block.
1686      */
1687     private void addSuccessor(final int info, final Label successor) {
1688         // creates and initializes an Edge object...
1689         Edge b = new Edge();
1690         b.info = info;
1691         b.successor = successor;
1692         // ...and adds it to the successor list of the currentBlock block
1693         b.next = currentBlock.successors;
1694         currentBlock.successors = b;
1695     }
1696 
1697     /**
1698      * Ends the current basic block. This method must be used in the case where
1699      * the current basic block does not have any successor.
1700      */
1701     private void noSuccessor() {
1702         if (compute == FRAMES) {
1703             Label l = new Label();
1704             l.frame = new Frame();
1705             l.frame.owner = l;
1706             l.resolve(this, code.length, code.data);
1707             previousBlock.successor = l;
1708             previousBlock = l;
1709         } else {
1710             currentBlock.outputStackMax = maxStackSize;
1711         }
1712         currentBlock = null;
1713     }
1714 
1715     // ------------------------------------------------------------------------
1716     // Utility methods: stack map frames
1717     // ------------------------------------------------------------------------
1718 
1719     /**
1720      * Visits a frame that has been computed from scratch.
1721      *
1722      * @param f
1723      *            the frame that must be visited.
1724      */
1725     private void visitFrame(final Frame f) {
1726         int i, t;
1727         int nTop = 0;
1728         int nLocal = 0;
1729         int nStack = 0;
1730         int[] locals = f.inputLocals;
1731         int[] stacks = f.inputStack;
1732         // computes the number of locals (ignores TOP types that are just after
1733         // a LONG or a DOUBLE, and all trailing TOP types)
1734         for (i = 0; i < locals.length; ++i) {
1735             t = locals[i];
1736             if (t == Frame.TOP) {
1737                 ++nTop;
1738             } else {
1739                 nLocal += nTop + 1;
1740                 nTop = 0;
1741             }
1742             if (t == Frame.LONG || t == Frame.DOUBLE) {
1743                 ++i;
1744             }
1745         }
1746         // computes the stack size (ignores TOP types that are just after
1747         // a LONG or a DOUBLE)
1748         for (i = 0; i < stacks.length; ++i) {
1749             t = stacks[i];
1750             ++nStack;
1751             if (t == Frame.LONG || t == Frame.DOUBLE) {
1752                 ++i;
1753             }
1754         }
1755         // visits the frame and its content
1756         int frameIndex = startFrame(f.owner.position, nLocal, nStack);
1757         for (i = 0; nLocal > 0; ++i, --nLocal) {
1758             t = locals[i];
1759             frame[frameIndex++] = t;
1760             if (t == Frame.LONG || t == Frame.DOUBLE) {
1761                 ++i;
1762             }
1763         }
1764         for (i = 0; i < stacks.length; ++i) {
1765             t = stacks[i];
1766             frame[frameIndex++] = t;
1767             if (t == Frame.LONG || t == Frame.DOUBLE) {
1768                 ++i;
1769             }
1770         }
1771         endFrame();
1772     }
1773 
1774     /**
1775      * Visit the implicit first frame of this method.
1776      */
1777     private void visitImplicitFirstFrame() {
1778         // There can be at most descriptor.length() + 1 locals
1779         int frameIndex = startFrame(0, descriptor.length() + 1, 0);
1780         if ((access & Opcodes.ACC_STATIC) == 0) {
1781             if ((access & ACC_CONSTRUCTOR) == 0) {
1782                 frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
1783             } else {
1784                 frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS;
1785             }
1786         }
1787         int i = 1;
1788         loop: while (true) {
1789             int j = i;
1790             switch (descriptor.charAt(i++)) {
1791             case 'Z':
1792             case 'C':
1793             case 'B':
1794             case 'S':
1795             case 'I':
1796                 frame[frameIndex++] = 1; // Opcodes.INTEGER;
1797                 break;
1798             case 'F':
1799                 frame[frameIndex++] = 2; // Opcodes.FLOAT;
1800                 break;
1801             case 'J':
1802                 frame[frameIndex++] = 4; // Opcodes.LONG;
1803                 break;
1804             case 'D':
1805                 frame[frameIndex++] = 3; // Opcodes.DOUBLE;
1806                 break;
1807             case '[':
1808                 while (descriptor.charAt(i) == '[') {
1809                     ++i;
1810                 }
1811                 if (descriptor.charAt(i) == 'L') {
1812                     ++i;
1813                     while (descriptor.charAt(i) != ';') {
1814                         ++i;
1815                     }
1816                 }
1817                 frame[frameIndex++] = Frame.OBJECT
1818                         | cw.addType(descriptor.substring(j, ++i));
1819                 break;
1820             case 'L':
1821                 while (descriptor.charAt(i) != ';') {
1822                     ++i;
1823                 }
1824                 frame[frameIndex++] = Frame.OBJECT
1825                         | cw.addType(descriptor.substring(j + 1, i++));
1826                 break;
1827             default:
1828                 break loop;
1829             }
1830         }
1831         frame[1] = frameIndex - 3;
1832         endFrame();
1833     }
1834 
1835     /**
1836      * Starts the visit of a stack map frame.
1837      *
1838      * @param offset
1839      *            the offset of the instruction to which the frame corresponds.
1840      * @param nLocal
1841      *            the number of local variables in the frame.
1842      * @param nStack
1843      *            the number of stack elements in the frame.
1844      * @return the index of the next element to be written in this frame.
1845      */
1846     private int startFrame(final int offset, final int nLocal, final int nStack) {
1847         int n = 3 + nLocal + nStack;
1848         if (frame == null || frame.length < n) {
1849             frame = new int[n];
1850         }
1851         frame[0] = offset;
1852         frame[1] = nLocal;
1853         frame[2] = nStack;
1854         return 3;
1855     }
1856 
1857     /**
1858      * Checks if the visit of the current frame {@link #frame} is finished, and
1859      * if yes, write it in the StackMapTable attribute.
1860      */
1861     private void endFrame() {
1862         if (previousFrame != null) { // do not write the first frame
1863             if (stackMap == null) {
1864                 stackMap = new ByteVector();
1865             }
1866             writeFrame();
1867             ++frameCount;
1868         }
1869         previousFrame = frame;
1870         frame = null;
1871     }
1872 
1873     /**
1874      * Compress and writes the current frame {@link #frame} in the StackMapTable
1875      * attribute.
1876      */
1877     private void writeFrame() {
1878         int clocalsSize = frame[1];
1879         int cstackSize = frame[2];
1880         if ((cw.version & 0xFFFF) < Opcodes.V1_6) {
1881             stackMap.putShort(frame[0]).putShort(clocalsSize);
1882             writeFrameTypes(3, 3 + clocalsSize);
1883             stackMap.putShort(cstackSize);
1884             writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1885             return;
1886         }
1887         int localsSize = previousFrame[1];
1888         int type = FULL_FRAME;
1889         int k = 0;
1890         int delta;
1891         if (frameCount == 0) {
1892             delta = frame[0];
1893         } else {
1894             delta = frame[0] - previousFrame[0] - 1;
1895         }
1896         if (cstackSize == 0) {
1897             k = clocalsSize - localsSize;
1898             switch (k) {
1899             case -3:
1900             case -2:
1901             case -1:
1902                 type = CHOP_FRAME;
1903                 localsSize = clocalsSize;
1904                 break;
1905             case 0:
1906                 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
1907                 break;
1908             case 1:
1909             case 2:
1910             case 3:
1911                 type = APPEND_FRAME;
1912                 break;
1913             }
1914         } else if (clocalsSize == localsSize && cstackSize == 1) {
1915             type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME
1916                     : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1917         }
1918         if (type != FULL_FRAME) {
1919             // verify if locals are the same
1920             int l = 3;
1921             for (int j = 0; j < localsSize; j++) {
1922                 if (frame[l] != previousFrame[l]) {
1923                     type = FULL_FRAME;
1924                     break;
1925                 }
1926                 l++;
1927             }
1928         }
1929         switch (type) {
1930         case SAME_FRAME:
1931             stackMap.putByte(delta);
1932             break;
1933         case SAME_LOCALS_1_STACK_ITEM_FRAME:
1934             stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
1935             writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1936             break;
1937         case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1938             stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(
1939                     delta);
1940             writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1941             break;
1942         case SAME_FRAME_EXTENDED:
1943             stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
1944             break;
1945         case CHOP_FRAME:
1946             stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1947             break;
1948         case APPEND_FRAME:
1949             stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1950             writeFrameTypes(3 + localsSize, 3 + clocalsSize);
1951             break;
1952         // case FULL_FRAME:
1953         default:
1954             stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize);
1955             writeFrameTypes(3, 3 + clocalsSize);
1956             stackMap.putShort(cstackSize);
1957             writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1958         }
1959     }
1960 
1961     /**
1962      * Writes some types of the current frame {@link #frame} into the
1963      * StackMapTableAttribute. This method converts types from the format used
1964      * in {@link Label} to the format used in StackMapTable attributes. In
1965      * particular, it converts type table indexes to constant pool indexes.
1966      *
1967      * @param start
1968      *            index of the first type in {@link #frame} to write.
1969      * @param end
1970      *            index of last type in {@link #frame} to write (exclusive).
1971      */
1972     private void writeFrameTypes(final int start, final int end) {
1973         for (int i = start; i < end; ++i) {
1974             int t = frame[i];
1975             int d = t & Frame.DIM;
1976             if (d == 0) {
1977                 int v = t & Frame.BASE_VALUE;
1978                 switch (t & Frame.BASE_KIND) {
1979                 case Frame.OBJECT:
1980                     stackMap.putByte(7).putShort(
1981                             cw.newClass(cw.typeTable[v].strVal1));
1982                     break;
1983                 case Frame.UNINITIALIZED:
1984                     stackMap.putByte(8).putShort(cw.typeTable[v].intVal);
1985                     break;
1986                 default:
1987                     stackMap.putByte(v);
1988                 }
1989             } else {
1990                 StringBuffer buf = new StringBuffer();
1991                 d >>= 28;
1992                 while (d-- > 0) {
1993                     buf.append('[');
1994                 }
1995                 if ((t & Frame.BASE_KIND) == Frame.OBJECT) {
1996                     buf.append('L');
1997                     buf.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1);
1998                     buf.append(';');
1999                 } else {
2000                     switch (t & 0xF) {
2001                     case 1:
2002                         buf.append('I');
2003                         break;
2004                     case 2:
2005                         buf.append('F');
2006                         break;
2007                     case 3:
2008                         buf.append('D');
2009                         break;
2010                     case 9:
2011                         buf.append('Z');
2012                         break;
2013                     case 10:
2014                         buf.append('B');
2015                         break;
2016                     case 11:
2017                         buf.append('C');
2018                         break;
2019                     case 12:
2020                         buf.append('S');
2021                         break;
2022                     default:
2023                         buf.append('J');
2024                     }
2025                 }
2026                 stackMap.putByte(7).putShort(cw.newClass(buf.toString()));
2027             }
2028         }
2029     }
2030 
2031     private void writeFrameType(final Object type) {
2032         if (type instanceof String) {
2033             stackMap.putByte(7).putShort(cw.newClass((String) type));
2034         } else if (type instanceof Integer) {
2035             stackMap.putByte(((Integer) type).intValue());
2036         } else {
2037             stackMap.putByte(8).putShort(((Label) type).position);
2038         }
2039     }
2040 
2041     // ------------------------------------------------------------------------
2042     // Utility methods: dump bytecode array
2043     // ------------------------------------------------------------------------
2044 
2045     /**
2046      * Returns the size of the bytecode of this method.
2047      *
2048      * @return the size of the bytecode of this method.
2049      */
2050     final int getSize() {
2051         if (classReaderOffset != 0) {
2052             return 6 + classReaderLength;
2053         }
2054         if (resize) {
2055             // replaces the temporary jump opcodes introduced by Label.resolve.
2056             if (ClassReader.RESIZE) {
2057                 resizeInstructions();
2058             } else {
2059                 throw new RuntimeException("Method code too large!");
2060             }
2061         }
2062         int size = 8;
2063         if (code.length > 0) {
2064             if (code.length > 65536) {
2065                 throw new RuntimeException("Method code too large!");
2066             }
2067             cw.newUTF8("Code");
2068             size += 18 + code.length + 8 * handlerCount;
2069             if (localVar != null) {
2070                 cw.newUTF8("LocalVariableTable");
2071                 size += 8 + localVar.length;
2072             }
2073             if (localVarType != null) {
2074                 cw.newUTF8("LocalVariableTypeTable");
2075                 size += 8 + localVarType.length;
2076             }
2077             if (lineNumber != null) {
2078                 cw.newUTF8("LineNumberTable");
2079                 size += 8 + lineNumber.length;
2080             }
2081             if (stackMap != null) {
2082                 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2083                 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
2084                 size += 8 + stackMap.length;
2085             }
2086             if (ClassReader.ANNOTATIONS && ctanns != null) {
2087                 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2088                 size += 8 + ctanns.getSize();
2089             }
2090             if (ClassReader.ANNOTATIONS && ictanns != null) {
2091                 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2092                 size += 8 + ictanns.getSize();
2093             }
2094             if (cattrs != null) {
2095                 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2096                         maxLocals);
2097             }
2098         }
2099         if (exceptionCount > 0) {
2100             cw.newUTF8("Exceptions");
2101             size += 8 + 2 * exceptionCount;
2102         }
2103         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2104             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2105                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2106                 cw.newUTF8("Synthetic");
2107                 size += 6;
2108             }
2109         }
2110         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2111             cw.newUTF8("Deprecated");
2112             size += 6;
2113         }
2114         if (ClassReader.SIGNATURES && signature != null) {
2115             cw.newUTF8("Signature");
2116             cw.newUTF8(signature);
2117             size += 8;
2118         }
2119         if (methodParameters != null) {
2120             cw.newUTF8("MethodParameters");
2121             size += 7 + methodParameters.length;
2122         }
2123         if (ClassReader.ANNOTATIONS && annd != null) {
2124             cw.newUTF8("AnnotationDefault");
2125             size += 6 + annd.length;
2126         }
2127         if (ClassReader.ANNOTATIONS && anns != null) {
2128             cw.newUTF8("RuntimeVisibleAnnotations");
2129             size += 8 + anns.getSize();
2130         }
2131         if (ClassReader.ANNOTATIONS && ianns != null) {
2132             cw.newUTF8("RuntimeInvisibleAnnotations");
2133             size += 8 + ianns.getSize();
2134         }
2135         if (ClassReader.ANNOTATIONS && tanns != null) {
2136             cw.newUTF8("RuntimeVisibleTypeAnnotations");
2137             size += 8 + tanns.getSize();
2138         }
2139         if (ClassReader.ANNOTATIONS && itanns != null) {
2140             cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2141             size += 8 + itanns.getSize();
2142         }
2143         if (ClassReader.ANNOTATIONS && panns != null) {
2144             cw.newUTF8("RuntimeVisibleParameterAnnotations");
2145             size += 7 + 2 * (panns.length - synthetics);
2146             for (int i = panns.length - 1; i >= synthetics; --i) {
2147                 size += panns[i] == null ? 0 : panns[i].getSize();
2148             }
2149         }
2150         if (ClassReader.ANNOTATIONS && ipanns != null) {
2151             cw.newUTF8("RuntimeInvisibleParameterAnnotations");
2152             size += 7 + 2 * (ipanns.length - synthetics);
2153             for (int i = ipanns.length - 1; i >= synthetics; --i) {
2154                 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
2155             }
2156         }
2157         if (attrs != null) {
2158             size += attrs.getSize(cw, null, 0, -1, -1);
2159         }
2160         return size;
2161     }
2162 
2163     /**
2164      * Puts the bytecode of this method in the given byte vector.
2165      *
2166      * @param out
2167      *            the byte vector into which the bytecode of this method must be
2168      *            copied.
2169      */
2170     final void put(final ByteVector out) {
2171         final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
2172         int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED
2173                 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
2174                 | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
2175         out.putShort(access & ~mask).putShort(name).putShort(desc);
2176         if (classReaderOffset != 0) {
2177             out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
2178             return;
2179         }
2180         int attributeCount = 0;
2181         if (code.length > 0) {
2182             ++attributeCount;
2183         }
2184         if (exceptionCount > 0) {
2185             ++attributeCount;
2186         }
2187         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2188             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2189                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2190                 ++attributeCount;
2191             }
2192         }
2193         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2194             ++attributeCount;
2195         }
2196         if (ClassReader.SIGNATURES && signature != null) {
2197             ++attributeCount;
2198         }
2199         if (methodParameters != null) {
2200             ++attributeCount;
2201         }
2202         if (ClassReader.ANNOTATIONS && annd != null) {
2203             ++attributeCount;
2204         }
2205         if (ClassReader.ANNOTATIONS && anns != null) {
2206             ++attributeCount;
2207         }
2208         if (ClassReader.ANNOTATIONS && ianns != null) {
2209             ++attributeCount;
2210         }
2211         if (ClassReader.ANNOTATIONS && tanns != null) {
2212             ++attributeCount;
2213         }
2214         if (ClassReader.ANNOTATIONS && itanns != null) {
2215             ++attributeCount;
2216         }
2217         if (ClassReader.ANNOTATIONS && panns != null) {
2218             ++attributeCount;
2219         }
2220         if (ClassReader.ANNOTATIONS && ipanns != null) {
2221             ++attributeCount;
2222         }
2223         if (attrs != null) {
2224             attributeCount += attrs.getCount();
2225         }
2226         out.putShort(attributeCount);
2227         if (code.length > 0) {
2228             int size = 12 + code.length + 8 * handlerCount;
2229             if (localVar != null) {
2230                 size += 8 + localVar.length;
2231             }
2232             if (localVarType != null) {
2233                 size += 8 + localVarType.length;
2234             }
2235             if (lineNumber != null) {
2236                 size += 8 + lineNumber.length;
2237             }
2238             if (stackMap != null) {
2239                 size += 8 + stackMap.length;
2240             }
2241             if (ClassReader.ANNOTATIONS && ctanns != null) {
2242                 size += 8 + ctanns.getSize();
2243             }
2244             if (ClassReader.ANNOTATIONS && ictanns != null) {
2245                 size += 8 + ictanns.getSize();
2246             }
2247             if (cattrs != null) {
2248                 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2249                         maxLocals);
2250             }
2251             out.putShort(cw.newUTF8("Code")).putInt(size);
2252             out.putShort(maxStack).putShort(maxLocals);
2253             out.putInt(code.length).putByteArray(code.data, 0, code.length);
2254             out.putShort(handlerCount);
2255             if (handlerCount > 0) {
2256                 Handler h = firstHandler;
2257                 while (h != null) {
2258                     out.putShort(h.start.position).putShort(h.end.position)
2259                             .putShort(h.handler.position).putShort(h.type);
2260                     h = h.next;
2261                 }
2262             }
2263             attributeCount = 0;
2264             if (localVar != null) {
2265                 ++attributeCount;
2266             }
2267             if (localVarType != null) {
2268                 ++attributeCount;
2269             }
2270             if (lineNumber != null) {
2271                 ++attributeCount;
2272             }
2273             if (stackMap != null) {
2274                 ++attributeCount;
2275             }
2276             if (ClassReader.ANNOTATIONS && ctanns != null) {
2277                 ++attributeCount;
2278             }
2279             if (ClassReader.ANNOTATIONS && ictanns != null) {
2280                 ++attributeCount;
2281             }
2282             if (cattrs != null) {
2283                 attributeCount += cattrs.getCount();
2284             }
2285             out.putShort(attributeCount);
2286             if (localVar != null) {
2287                 out.putShort(cw.newUTF8("LocalVariableTable"));
2288                 out.putInt(localVar.length + 2).putShort(localVarCount);
2289                 out.putByteArray(localVar.data, 0, localVar.length);
2290             }
2291             if (localVarType != null) {
2292                 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
2293                 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
2294                 out.putByteArray(localVarType.data, 0, localVarType.length);
2295             }
2296             if (lineNumber != null) {
2297                 out.putShort(cw.newUTF8("LineNumberTable"));
2298                 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
2299                 out.putByteArray(lineNumber.data, 0, lineNumber.length);
2300             }
2301             if (stackMap != null) {
2302                 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2303                 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
2304                 out.putInt(stackMap.length + 2).putShort(frameCount);
2305                 out.putByteArray(stackMap.data, 0, stackMap.length);
2306             }
2307             if (ClassReader.ANNOTATIONS && ctanns != null) {
2308                 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2309                 ctanns.put(out);
2310             }
2311             if (ClassReader.ANNOTATIONS && ictanns != null) {
2312                 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2313                 ictanns.put(out);
2314             }
2315             if (cattrs != null) {
2316                 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
2317             }
2318         }
2319         if (exceptionCount > 0) {
2320             out.putShort(cw.newUTF8("Exceptions")).putInt(
2321                     2 * exceptionCount + 2);
2322             out.putShort(exceptionCount);
2323             for (int i = 0; i < exceptionCount; ++i) {
2324                 out.putShort(exceptions[i]);
2325             }
2326         }
2327         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2328             if ((cw.version & 0xFFFF) < Opcodes.V1_5
2329                     || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2330                 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
2331             }
2332         }
2333         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2334             out.putShort(cw.newUTF8("Deprecated")).putInt(0);
2335         }
2336         if (ClassReader.SIGNATURES && signature != null) {
2337             out.putShort(cw.newUTF8("Signature")).putInt(2)
2338                     .putShort(cw.newUTF8(signature));
2339         }
2340         if (methodParameters != null) {
2341             out.putShort(cw.newUTF8("MethodParameters"));
2342             out.putInt(methodParameters.length + 1).putByte(
2343                     methodParametersCount);
2344             out.putByteArray(methodParameters.data, 0, methodParameters.length);
2345         }
2346         if (ClassReader.ANNOTATIONS && annd != null) {
2347             out.putShort(cw.newUTF8("AnnotationDefault"));
2348             out.putInt(annd.length);
2349             out.putByteArray(annd.data, 0, annd.length);
2350         }
2351         if (ClassReader.ANNOTATIONS && anns != null) {
2352             out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2353             anns.put(out);
2354         }
2355         if (ClassReader.ANNOTATIONS && ianns != null) {
2356             out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2357             ianns.put(out);
2358         }
2359         if (ClassReader.ANNOTATIONS && tanns != null) {
2360             out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2361             tanns.put(out);
2362         }
2363         if (ClassReader.ANNOTATIONS && itanns != null) {
2364             out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2365             itanns.put(out);
2366         }
2367         if (ClassReader.ANNOTATIONS && panns != null) {
2368             out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
2369             AnnotationWriter.put(panns, synthetics, out);
2370         }
2371         if (ClassReader.ANNOTATIONS && ipanns != null) {
2372             out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
2373             AnnotationWriter.put(ipanns, synthetics, out);
2374         }
2375         if (attrs != null) {
2376             attrs.put(cw, null, 0, -1, -1, out);
2377         }
2378     }
2379 
2380     // ------------------------------------------------------------------------
2381     // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
2382     // ------------------------------------------------------------------------
2383 
2384     /**
2385      * Resizes and replaces the temporary instructions inserted by
2386      * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
2387      * and instruction addresses consistent. This may require to resize other
2388      * existing instructions, or even to introduce new instructions: for
2389      * example, increasing the size of an instruction by 2 at the middle of a
2390      * method can increases the offset of an IFEQ instruction from 32766 to
2391      * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
2392      * 32765. This, in turn, may require to increase the size of another jump
2393      * instruction, and so on... All these operations are handled automatically
2394      * by this method.
2395      * <p>
2396      * <i>This method must be called after all the method that is being built
2397      * has been visited</i>. In particular, the {@link Label Label} objects used
2398      * to construct the method are no longer valid after this method has been
2399      * called.
2400      */
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         // recomputes the stack map frames
2719         if (frameCount > 0) {
2720             if (compute == FRAMES) {
2721                 frameCount = 0;
2722                 stackMap = null;
2723                 previousFrame = null;
2724                 frame = null;
2725                 Frame f = new Frame();
2726                 f.owner = labels;
2727                 Type[] args = Type.getArgumentTypes(descriptor);
2728                 f.initInputFrame(cw, access, args, maxLocals);
2729                 visitFrame(f);
2730                 Label l = labels;
2731                 while (l != null) {
2732                     /*
2733                      * here we need the original label position. getNewOffset
2734                      * must therefore never have been called for this label.
2735                      */
2736                     u = l.position - 3;
2737                     if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) {
2738                         getNewOffset(allIndexes, allSizes, l);
2739                         // TODO update offsets in UNINITIALIZED values
2740                         visitFrame(l.frame);
2741                     }
2742                     l = l.successor;
2743                 }
2744             } else {
2745                 /*
2746                  * Resizing an existing stack map frame table is really hard.
2747                  * Not only the table must be parsed to update the offets, but
2748                  * new frames may be needed for jump instructions that were
2749                  * inserted by this method. And updating the offsets or
2750                  * inserting frames can change the format of the following
2751                  * frames, in case of packed frames. In practice the whole table
2752                  * must be recomputed. For this the frames are marked as
2753                  * potentially invalid. This will cause the whole class to be
2754                  * reread and rewritten with the COMPUTE_FRAMES option (see the
2755                  * ClassWriter.toByteArray method). This is not very efficient
2756                  * but is much easier and requires much less code than any other
2757                  * method I can think of.
2758                  */
2759                 cw.invalidFrames = true;
2760             }
2761         }
2762         // updates the exception handler block labels
2763         Handler h = firstHandler;
2764         while (h != null) {
2765             getNewOffset(allIndexes, allSizes, h.start);
2766             getNewOffset(allIndexes, allSizes, h.end);
2767             getNewOffset(allIndexes, allSizes, h.handler);
2768             h = h.next;
2769         }
2770         // updates the instructions addresses in the
2771         // local var and line number tables
2772         for (i = 0; i < 2; ++i) {
2773             ByteVector bv = i == 0 ? localVar : localVarType;
2774             if (bv != null) {
2775                 b = bv.data;
2776                 u = 0;
2777                 while (u < bv.length) {
2778                     label = readUnsignedShort(b, u);
2779                     newOffset = getNewOffset(allIndexes, allSizes, 0, label);
2780                     writeShort(b, u, newOffset);
2781                     label += readUnsignedShort(b, u + 2);
2782                     newOffset = getNewOffset(allIndexes, allSizes, 0, label)
2783                             - newOffset;
2784                     writeShort(b, u + 2, newOffset);
2785                     u += 10;
2786                 }
2787             }
2788         }
2789         if (lineNumber != null) {
2790             b = lineNumber.data;
2791             u = 0;
2792             while (u < lineNumber.length) {
2793                 writeShort(
2794                         b,
2795                         u,
2796                         getNewOffset(allIndexes, allSizes, 0,
2797                                 readUnsignedShort(b, u)));
2798                 u += 4;
2799             }
2800         }
2801         // updates the labels of the other attributes
2802         Attribute attr = cattrs;
2803         while (attr != null) {
2804             Label[] labels = attr.getLabels();
2805             if (labels != null) {
2806                 for (i = labels.length - 1; i >= 0; --i) {
2807                     getNewOffset(allIndexes, allSizes, labels[i]);
2808                 }
2809             }
2810             attr = attr.next;
2811         }
2812 
2813         // replaces old bytecodes with new ones
2814         code = newCode;
2815     }
2816 
2817     /**
2818      * Reads an unsigned short value in the given byte array.
2819      *
2820      * @param b
2821      *            a byte array.
2822      * @param index
2823      *            the start index of the value to be read.
2824      * @return the read value.
2825      */
2826     static int readUnsignedShort(final byte[] b, final int index) {
2827         return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2828     }
2829 
2830     /**
2831      * Reads a signed short value in the given byte array.
2832      *
2833      * @param b
2834      *            a byte array.
2835      * @param index
2836      *            the start index of the value to be read.
2837      * @return the read value.
2838      */
2839     static short readShort(final byte[] b, final int index) {
2840         return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2841     }
2842 
2843     /**
2844      * Reads a signed int value in the given byte array.
2845      *
2846      * @param b
2847      *            a byte array.
2848      * @param index
2849      *            the start index of the value to be read.
2850      * @return the read value.
2851      */
2852     static int readInt(final byte[] b, final int index) {
2853         return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2854                 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2855     }
2856 
2857     /**
2858      * Writes a short value in the given byte array.
2859      *
2860      * @param b
2861      *            a byte array.
2862      * @param index
2863      *            where the first byte of the short value must be written.
2864      * @param s
2865      *            the value to be written in the given byte array.
2866      */
2867     static void writeShort(final byte[] b, final int index, final int s) {
2868         b[index] = (byte) (s >>> 8);
2869         b[index + 1] = (byte) s;
2870     }
2871 
2872     /**
2873      * Computes the future value of a bytecode offset.
2874      * <p>
2875      * Note: it is possible to have several entries for the same instruction in
2876      * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and
2877      * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b').
2878      *
2879      * @param indexes
2880      *            current positions of the instructions to be resized. Each
2881      *            instruction must be designated by the index of its <i>last</i>
2882      *            byte, plus one (or, in other words, by the index of the
2883      *            <i>first</i> byte of the <i>next</i> instruction).
2884      * @param sizes
2885      *            the number of bytes to be <i>added</i> to the above
2886      *            instructions. More precisely, for each i < <tt>len</tt>,
2887      *            <tt>sizes</tt>[i] bytes will be added at the end of the
2888      *            instruction designated by <tt>indexes</tt>[i] or, if
2889      *            <tt>sizes</tt>[i] is negative, the <i>last</i> |
2890      *            <tt>sizes[i]</tt>| bytes of the instruction will be removed
2891      *            (the instruction size <i>must not</i> become negative or
2892      *            null).
2893      * @param begin
2894      *            index of the first byte of the source instruction.
2895      * @param end
2896      *            index of the first byte of the target instruction.
2897      * @return the future value of the given bytecode offset.
2898      */
2899     static int getNewOffset(final int[] indexes, final int[] sizes,
2900             final int begin, final int end) {
2901         int offset = end - begin;
2902         for (int i = 0; i < indexes.length; ++i) {
2903             if (begin < indexes[i] && indexes[i] <= end) {
2904                 // forward jump
2905                 offset += sizes[i];
2906             } else if (end < indexes[i] && indexes[i] <= begin) {
2907                 // backward jump
2908                 offset -= sizes[i];
2909             }
2910         }
2911         return offset;
2912     }
2913 
2914     /**
2915      * Updates the offset of the given label.
2916      *
2917      * @param indexes
2918      *            current positions of the instructions to be resized. Each
2919      *            instruction must be designated by the index of its <i>last</i>
2920      *            byte, plus one (or, in other words, by the index of the
2921      *            <i>first</i> byte of the <i>next</i> instruction).
2922      * @param sizes
2923      *            the number of bytes to be <i>added</i> to the above
2924      *            instructions. More precisely, for each i < <tt>len</tt>,
2925      *            <tt>sizes</tt>[i] bytes will be added at the end of the
2926      *            instruction designated by <tt>indexes</tt>[i] or, if
2927      *            <tt>sizes</tt>[i] is negative, the <i>last</i> |
2928      *            <tt>sizes[i]</tt>| bytes of the instruction will be removed
2929      *            (the instruction size <i>must not</i> become negative or
2930      *            null).
2931      * @param label
2932      *            the label whose offset must be updated.
2933      */
2934     static void getNewOffset(final int[] indexes, final int[] sizes,
2935             final Label label) {
2936         if ((label.status & Label.RESIZED) == 0) {
2937             label.position = getNewOffset(indexes, sizes, 0, label.position);
2938             label.status |= Label.RESIZED;
2939         }
2940     }
2941 }