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