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