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