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