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