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