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