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 a corresponding 'method_info' structure, as defined in the
63  * Java Virtual Machine Specification (JVMS).
64  *
65  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6">JVMS
66  *     4.6</a>
67  * @author Eric Bruneton
68  * @author Eugene Kuleshov
69  */
70 final class MethodWriter extends MethodVisitor {
71 
72     /** Indicates that nothing must be computed. */
73     static final int COMPUTE_NOTHING = 0;
74 
75     /**
76       * Indicates that the maximum stack size and the maximum number of local variables must be
77       * computed, from scratch.
78       */
79     static final int COMPUTE_MAX_STACK_AND_LOCAL = 1;
80 
81     /**
82       * Indicates that the maximum stack size and the maximum number of local variables must be
83       * computed, from the existing stack map frames. This can be done more efficiently than with the
84       * control flow graph algorithm used for {@link #COMPUTE_MAX_STACK_AND_LOCAL}, by using a linear
85       * scan of the bytecode instructions.
86       */
87     static final int COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES = 2;
88 
89     /**
90       * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not
91       * computed. They should all be of type F_NEW and should be sufficient to compute the content of
92       * the F_INSERT frames, together with the bytecode instructions between a F_NEW and a F_INSERT
93       * frame - and without any knowledge of the type hierarchy (by definition of F_INSERT).
94       */
95     static final int COMPUTE_INSERTED_FRAMES = 3;
96 
97     /**
98       * Indicates that all the stack map frames must be computed. In this case the maximum stack size
99       * and the maximum number of local variables is also computed.
100       */
101     static final int COMPUTE_ALL_FRAMES = 4;
102 
103     /** Indicates that {@link #STACK_SIZE_DELTA} is not applicable (not constant or never used). */
104     private static final int NA = 0;
105 
106     /**
107       * The stack size variation corresponding to each JVM opcode. The stack size variation for opcode
108       * 'o' is given by the array element at index 'o'.
109       *
110       * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html">JVMS 6</a>
111       */
112     private static final int[] STACK_SIZE_DELTA = {
113         0, // nop = 0 (0x0)
114         1, // aconst_null = 1 (0x1)
115         1, // iconst_m1 = 2 (0x2)
116         1, // iconst_0 = 3 (0x3)
117         1, // iconst_1 = 4 (0x4)
118         1, // iconst_2 = 5 (0x5)
119         1, // iconst_3 = 6 (0x6)
120         1, // iconst_4 = 7 (0x7)
121         1, // iconst_5 = 8 (0x8)
122         2, // lconst_0 = 9 (0x9)
123         2, // lconst_1 = 10 (0xa)
124         1, // fconst_0 = 11 (0xb)
125         1, // fconst_1 = 12 (0xc)
126         1, // fconst_2 = 13 (0xd)
127         2, // dconst_0 = 14 (0xe)
128         2, // dconst_1 = 15 (0xf)
129         1, // bipush = 16 (0x10)
130         1, // sipush = 17 (0x11)
131         1, // ldc = 18 (0x12)
132         NA, // ldc_w = 19 (0x13)
133         NA, // ldc2_w = 20 (0x14)
134         1, // iload = 21 (0x15)
135         2, // lload = 22 (0x16)
136         1, // fload = 23 (0x17)
137         2, // dload = 24 (0x18)
138         1, // aload = 25 (0x19)
139         NA, // iload_0 = 26 (0x1a)
140         NA, // iload_1 = 27 (0x1b)
141         NA, // iload_2 = 28 (0x1c)
142         NA, // iload_3 = 29 (0x1d)
143         NA, // lload_0 = 30 (0x1e)
144         NA, // lload_1 = 31 (0x1f)
145         NA, // lload_2 = 32 (0x20)
146         NA, // lload_3 = 33 (0x21)
147         NA, // fload_0 = 34 (0x22)
148         NA, // fload_1 = 35 (0x23)
149         NA, // fload_2 = 36 (0x24)
150         NA, // fload_3 = 37 (0x25)
151         NA, // dload_0 = 38 (0x26)
152         NA, // dload_1 = 39 (0x27)
153         NA, // dload_2 = 40 (0x28)
154         NA, // dload_3 = 41 (0x29)
155         NA, // aload_0 = 42 (0x2a)
156         NA, // aload_1 = 43 (0x2b)
157         NA, // aload_2 = 44 (0x2c)
158         NA, // aload_3 = 45 (0x2d)
159         -1, // iaload = 46 (0x2e)
160         0, // laload = 47 (0x2f)
161         -1, // faload = 48 (0x30)
162         0, // daload = 49 (0x31)
163         -1, // aaload = 50 (0x32)
164         -1, // baload = 51 (0x33)
165         -1, // caload = 52 (0x34)
166         -1, // saload = 53 (0x35)
167         -1, // istore = 54 (0x36)
168         -2, // lstore = 55 (0x37)
169         -1, // fstore = 56 (0x38)
170         -2, // dstore = 57 (0x39)
171         -1, // astore = 58 (0x3a)
172         NA, // istore_0 = 59 (0x3b)
173         NA, // istore_1 = 60 (0x3c)
174         NA, // istore_2 = 61 (0x3d)
175         NA, // istore_3 = 62 (0x3e)
176         NA, // lstore_0 = 63 (0x3f)
177         NA, // lstore_1 = 64 (0x40)
178         NA, // lstore_2 = 65 (0x41)
179         NA, // lstore_3 = 66 (0x42)
180         NA, // fstore_0 = 67 (0x43)
181         NA, // fstore_1 = 68 (0x44)
182         NA, // fstore_2 = 69 (0x45)
183         NA, // fstore_3 = 70 (0x46)
184         NA, // dstore_0 = 71 (0x47)
185         NA, // dstore_1 = 72 (0x48)
186         NA, // dstore_2 = 73 (0x49)
187         NA, // dstore_3 = 74 (0x4a)
188         NA, // astore_0 = 75 (0x4b)
189         NA, // astore_1 = 76 (0x4c)
190         NA, // astore_2 = 77 (0x4d)
191         NA, // astore_3 = 78 (0x4e)
192         -3, // iastore = 79 (0x4f)
193         -4, // lastore = 80 (0x50)
194         -3, // fastore = 81 (0x51)
195         -4, // dastore = 82 (0x52)
196         -3, // aastore = 83 (0x53)
197         -3, // bastore = 84 (0x54)
198         -3, // castore = 85 (0x55)
199         -3, // sastore = 86 (0x56)
200         -1, // pop = 87 (0x57)
201         -2, // pop2 = 88 (0x58)
202         1, // dup = 89 (0x59)
203         1, // dup_x1 = 90 (0x5a)
204         1, // dup_x2 = 91 (0x5b)
205         2, // dup2 = 92 (0x5c)
206         2, // dup2_x1 = 93 (0x5d)
207         2, // dup2_x2 = 94 (0x5e)
208         0, // swap = 95 (0x5f)
209         -1, // iadd = 96 (0x60)
210         -2, // ladd = 97 (0x61)
211         -1, // fadd = 98 (0x62)
212         -2, // dadd = 99 (0x63)
213         -1, // isub = 100 (0x64)
214         -2, // lsub = 101 (0x65)
215         -1, // fsub = 102 (0x66)
216         -2, // dsub = 103 (0x67)
217         -1, // imul = 104 (0x68)
218         -2, // lmul = 105 (0x69)
219         -1, // fmul = 106 (0x6a)
220         -2, // dmul = 107 (0x6b)
221         -1, // idiv = 108 (0x6c)
222         -2, // ldiv = 109 (0x6d)
223         -1, // fdiv = 110 (0x6e)
224         -2, // ddiv = 111 (0x6f)
225         -1, // irem = 112 (0x70)
226         -2, // lrem = 113 (0x71)
227         -1, // frem = 114 (0x72)
228         -2, // drem = 115 (0x73)
229         0, // ineg = 116 (0x74)
230         0, // lneg = 117 (0x75)
231         0, // fneg = 118 (0x76)
232         0, // dneg = 119 (0x77)
233         -1, // ishl = 120 (0x78)
234         -1, // lshl = 121 (0x79)
235         -1, // ishr = 122 (0x7a)
236         -1, // lshr = 123 (0x7b)
237         -1, // iushr = 124 (0x7c)
238         -1, // lushr = 125 (0x7d)
239         -1, // iand = 126 (0x7e)
240         -2, // land = 127 (0x7f)
241         -1, // ior = 128 (0x80)
242         -2, // lor = 129 (0x81)
243         -1, // ixor = 130 (0x82)
244         -2, // lxor = 131 (0x83)
245         0, // iinc = 132 (0x84)
246         1, // i2l = 133 (0x85)
247         0, // i2f = 134 (0x86)
248         1, // i2d = 135 (0x87)
249         -1, // l2i = 136 (0x88)
250         -1, // l2f = 137 (0x89)
251         0, // l2d = 138 (0x8a)
252         0, // f2i = 139 (0x8b)
253         1, // f2l = 140 (0x8c)
254         1, // f2d = 141 (0x8d)
255         -1, // d2i = 142 (0x8e)
256         0, // d2l = 143 (0x8f)
257         -1, // d2f = 144 (0x90)
258         0, // i2b = 145 (0x91)
259         0, // i2c = 146 (0x92)
260         0, // i2s = 147 (0x93)
261         -3, // lcmp = 148 (0x94)
262         -1, // fcmpl = 149 (0x95)
263         -1, // fcmpg = 150 (0x96)
264         -3, // dcmpl = 151 (0x97)
265         -3, // dcmpg = 152 (0x98)
266         -1, // ifeq = 153 (0x99)
267         -1, // ifne = 154 (0x9a)
268         -1, // iflt = 155 (0x9b)
269         -1, // ifge = 156 (0x9c)
270         -1, // ifgt = 157 (0x9d)
271         -1, // ifle = 158 (0x9e)
272         -2, // if_icmpeq = 159 (0x9f)
273         -2, // if_icmpne = 160 (0xa0)
274         -2, // if_icmplt = 161 (0xa1)
275         -2, // if_icmpge = 162 (0xa2)
276         -2, // if_icmpgt = 163 (0xa3)
277         -2, // if_icmple = 164 (0xa4)
278         -2, // if_acmpeq = 165 (0xa5)
279         -2, // if_acmpne = 166 (0xa6)
280         0, // goto = 167 (0xa7)
281         1, // jsr = 168 (0xa8)
282         0, // ret = 169 (0xa9)
283         -1, // tableswitch = 170 (0xaa)
284         -1, // lookupswitch = 171 (0xab)
285         -1, // ireturn = 172 (0xac)
286         -2, // lreturn = 173 (0xad)
287         -1, // freturn = 174 (0xae)
288         -2, // dreturn = 175 (0xaf)
289         -1, // areturn = 176 (0xb0)
290         0, // return = 177 (0xb1)
291         NA, // getstatic = 178 (0xb2)
292         NA, // putstatic = 179 (0xb3)
293         NA, // getfield = 180 (0xb4)
294         NA, // putfield = 181 (0xb5)
295         NA, // invokevirtual = 182 (0xb6)
296         NA, // invokespecial = 183 (0xb7)
297         NA, // invokestatic = 184 (0xb8)
298         NA, // invokeinterface = 185 (0xb9)
299         NA, // invokedynamic = 186 (0xba)
300         1, // new = 187 (0xbb)
301         0, // newarray = 188 (0xbc)
302         0, // anewarray = 189 (0xbd)
303         0, // arraylength = 190 (0xbe)
304         NA, // athrow = 191 (0xbf)
305         0, // checkcast = 192 (0xc0)
306         0, // instanceof = 193 (0xc1)
307         -1, // monitorenter = 194 (0xc2)
308         -1, // monitorexit = 195 (0xc3)
309         NA, // wide = 196 (0xc4)
310         NA, // multianewarray = 197 (0xc5)
311         -1, // ifnull = 198 (0xc6)
312         -1, // ifnonnull = 199 (0xc7)
313         NA, // goto_w = 200 (0xc8)
314         NA // jsr_w = 201 (0xc9)
315     };
316 
317     /** Where the constants used in this MethodWriter must be stored. */
318     private final SymbolTable symbolTable;
319 
320     // Note: fields are ordered as in the method_info structure, and those related to attributes are
321     // ordered as in Section 4.7 of the JVMS.
322 
323     /**
324       * The access_flags field of the method_info JVMS structure. This field can contain ASM specific
325       * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
326       * ClassFile structure.
327       */
328     private final int accessFlags;
329 
330     /** The name_index field of the method_info JVMS structure. */
331     private final int nameIndex;
332 
333     /** The name of this method. */
334     private final String name;
335 
336     /** The descriptor_index field of the method_info JVMS structure. */
337     private final int descriptorIndex;
338 
339     /** The descriptor of this method. */
340     private final String descriptor;
341 
342     // Code attribute fields and sub attributes:
343 
344     /** The max_stack field of the Code attribute. */
345     private int maxStack;
346 
347     /** The max_locals field of the Code attribute. */
348     private int maxLocals;
349 
350     /** The 'code' field of the Code attribute. */
351     private final ByteVector code = new ByteVector();
352 
353     /**
354       * The first element in the exception handler list (used to generate the exception_table of the
355       * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May
356       * be {@literal null}.
357       */
358     private Handler firstHandler;
359 
360     /**
361       * The last element in the exception handler list (used to generate the exception_table of the
362       * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May
363       * be {@literal null}.
364       */
365     private Handler lastHandler;
366 
367     /** The line_number_table_length field of the LineNumberTable code attribute. */
368     private int lineNumberTableLength;
369 
370     /** The line_number_table array of the LineNumberTable code attribute, or {@literal null}. */
371     private ByteVector lineNumberTable;
372 
373     /** The local_variable_table_length field of the LocalVariableTable code attribute. */
374     private int localVariableTableLength;
375 
376     /**
377       * The local_variable_table array of the LocalVariableTable code attribute, or {@literal null}.
378       */
379     private ByteVector localVariableTable;
380 
381     /** The local_variable_type_table_length field of the LocalVariableTypeTable code attribute. */
382     private int localVariableTypeTableLength;
383 
384     /**
385       * The local_variable_type_table array of the LocalVariableTypeTable code attribute, or {@literal
386       * null}.
387       */
388     private ByteVector localVariableTypeTable;
389 
390     /** The number_of_entries field of the StackMapTable code attribute. */
391     private int stackMapTableNumberOfEntries;
392 
393     /** The 'entries' array of the StackMapTable code attribute. */
394     private ByteVector stackMapTableEntries;
395 
396     /**
397       * The last runtime visible type annotation of the Code attribute. The previous ones can be
398       * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
399       */
400     private AnnotationWriter lastCodeRuntimeVisibleTypeAnnotation;
401 
402     /**
403       * The last runtime invisible type annotation of the Code attribute. The previous ones can be
404       * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
405       */
406     private AnnotationWriter lastCodeRuntimeInvisibleTypeAnnotation;
407 
408     /**
409       * The first non standard attribute of the Code attribute. The next ones can be accessed with the
410       * {@link Attribute#nextAttribute} field. May be {@literal null}.
411       *
412       * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
413       * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
414       * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the
415       * reverse order specified by the user.
416       */
417     private Attribute firstCodeAttribute;
418 
419     // Other method_info attributes:
420 
421     /** The number_of_exceptions field of the Exceptions attribute. */
422     private final int numberOfExceptions;
423 
424     /** The exception_index_table array of the Exceptions attribute, or {@literal null}. */
425     private final int[] exceptionIndexTable;
426 
427     /** The signature_index field of the Signature attribute. */
428     private final int signatureIndex;
429 
430     /**
431       * The last runtime visible annotation of this method. The previous ones can be accessed with the
432       * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
433       */
434     private AnnotationWriter lastRuntimeVisibleAnnotation;
435 
436     /**
437       * The last runtime invisible annotation of this method. The previous ones can be accessed with
438       * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
439       */
440     private AnnotationWriter lastRuntimeInvisibleAnnotation;
441 
442     /** The number of method parameters that can have runtime visible annotations, or 0. */
443     private int visibleAnnotableParameterCount;
444 
445     /**
446       * The runtime visible parameter annotations of this method. Each array element contains the last
447       * annotation of a parameter (which can be {@literal null} - the previous ones can be accessed
448       * with the {@link AnnotationWriter#previousAnnotation} field). May be {@literal null}.
449       */
450     private AnnotationWriter[] lastRuntimeVisibleParameterAnnotations;
451 
452     /** The number of method parameters that can have runtime visible annotations, or 0. */
453     private int invisibleAnnotableParameterCount;
454 
455     /**
456       * The runtime invisible parameter annotations of this method. Each array element contains the
457       * last annotation of a parameter (which can be {@literal null} - the previous ones can be
458       * accessed with the {@link AnnotationWriter#previousAnnotation} field). May be {@literal null}.
459       */
460     private AnnotationWriter[] lastRuntimeInvisibleParameterAnnotations;
461 
462     /**
463       * The last runtime visible type annotation of this method. The previous ones can be accessed with
464       * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
465       */
466     private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
467 
468     /**
469       * The last runtime invisible type annotation of this method. The previous ones can be accessed
470       * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
471       */
472     private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
473 
474     /** The default_value field of the AnnotationDefault attribute, or {@literal null}. */
475     private ByteVector defaultValue;
476 
477     /** The parameters_count field of the MethodParameters attribute. */
478     private int parametersCount;
479 
480     /** The 'parameters' array of the MethodParameters attribute, or {@literal null}. */
481     private ByteVector parameters;
482 
483     /**
484       * The first non standard attribute of this method. The next ones can be accessed with the {@link
485       * Attribute#nextAttribute} field. May be {@literal null}.
486       *
487       * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
488       * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
489       * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the
490       * reverse order specified by the user.
491       */
492     private Attribute firstAttribute;
493 
494     // -----------------------------------------------------------------------------------------------
495     // Fields used to compute the maximum stack size and number of locals, and the stack map frames
496     // -----------------------------------------------------------------------------------------------
497 
498     /**
499       * Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link
500       * #COMPUTE_INSERTED_FRAMES}, {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}.
501       */
502     private final int compute;
503 
504     /**
505       * The first basic block of the method. The next ones (in bytecode offset order) can be accessed
506       * with the {@link Label#nextBasicBlock} field.
507       */
508     private Label firstBasicBlock;
509 
510     /**
511       * The last basic block of the method (in bytecode offset order). This field is updated each time
512       * a basic block is encountered, and is used to append it at the end of the basic block list.
513       */
514     private Label lastBasicBlock;
515 
516     /**
517       * The current basic block, i.e. the basic block of the last visited instruction. When {@link
518       * #compute} is equal to {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_ALL_FRAMES}, this
519       * field is {@literal null} for unreachable code. When {@link #compute} is equal to {@link
520       * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES} or {@link #COMPUTE_INSERTED_FRAMES}, this field stays
521       * unchanged throughout the whole method (i.e. the whole code is seen as a single basic block;
522       * indeed, the existing frames are sufficient by hypothesis to compute any intermediate frame -
523       * and the maximum stack size as well - without using any control flow graph).
524       */
525     private Label currentBasicBlock;
526 
527     /**
528       * The relative stack size after the last visited instruction. This size is relative to the
529       * beginning of {@link #currentBasicBlock}, i.e. the true stack size after the last visited
530       * instruction is equal to the {@link Label#inputStackSize} of the current basic block plus {@link
531       * #relativeStackSize}. When {@link #compute} is equal to {@link
532       * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of
533       * the method, so this relative size is also equal to the absolute stack size after the last
534       * visited instruction.
535       */
536     private int relativeStackSize;
537 
538     /**
539       * The maximum relative stack size after the last visited instruction. This size is relative to
540       * the beginning of {@link #currentBasicBlock}, i.e. the true maximum stack size after the last
541       * visited instruction is equal to the {@link Label#inputStackSize} of the current basic block
542       * plus {@link #maxRelativeStackSize}.When {@link #compute} is equal to {@link
543       * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of
544       * the method, so this relative size is also equal to the absolute maximum stack size after the
545       * last visited instruction.
546       */
547     private int maxRelativeStackSize;
548 
549     /** The number of local variables in the last visited stack map frame. */
550     private int currentLocals;
551 
552     /** The bytecode offset of the last frame that was written in {@link #stackMapTableEntries}. */
553     private int previousFrameOffset;
554 
555     /**
556       * The last frame that was written in {@link #stackMapTableEntries}. This field has the same
557       * format as {@link #currentFrame}.
558       */
559     private int[] previousFrame;
560 
561     /**
562       * The current stack map frame. The first element contains the bytecode offset of the instruction
563       * to which the frame corresponds, the second element is the number of locals and the third one is
564       * the number of stack elements. The local variables start at index 3 and are followed by the
565       * operand stack elements. In summary frame[0] = offset, frame[1] = numLocal, frame[2] = numStack.
566       * Local variables and operand stack entries contain abstract types, as defined in {@link Frame},
567       * but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND} or {@link
568       * Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array entry.
569       */
570     private int[] currentFrame;
571 
572     /** Whether this method contains subroutines. */
573     private boolean hasSubroutines;
574 
575     // -----------------------------------------------------------------------------------------------
576     // Other miscellaneous status fields
577     // -----------------------------------------------------------------------------------------------
578 
579     /** Whether the bytecode of this method contains ASM specific instructions. */
580     private boolean hasAsmInstructions;
581 
582     /**
583       * The start offset of the last visited instruction. Used to set the offset field of type
584       * annotations of type 'offset_target' (see <a
585       * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS
586       * 4.7.20.1</a>).
587       */
588     private int lastBytecodeOffset;
589 
590     /**
591       * The offset in bytes in {@link SymbolTable#getSource} from which the method_info for this method
592       * (excluding its first 6 bytes) must be copied, or 0.
593       */
594     private int sourceOffset;
595 
596     /**
597       * The length in bytes in {@link SymbolTable#getSource} which must be copied to get the
598       * method_info for this method (excluding its first 6 bytes for access_flags, name_index and
599       * descriptor_index).
600       */
601     private int sourceLength;
602 
603     // -----------------------------------------------------------------------------------------------
604     // Constructor and accessors
605     // -----------------------------------------------------------------------------------------------
606 
607     /**
608       * Constructs a new {@link MethodWriter}.
609       *
610       * @param symbolTable where the constants used in this AnnotationWriter must be stored.
611       * @param access the method's access flags (see {@link Opcodes}).
612       * @param name the method's name.
613       * @param descriptor the method's descriptor (see {@link Type}).
614       * @param signature the method's signature. May be {@literal null}.
615       * @param exceptions the internal names of the method's exceptions. May be {@literal null}.
616       * @param compute indicates what must be computed (see #compute).
617       */
MethodWriter( final SymbolTable symbolTable, final int access, final String name, final String descriptor, final String signature, final String[] exceptions, final int compute)618     MethodWriter(
619             final SymbolTable symbolTable,
620             final int access,
621             final String name,
622             final String descriptor,
623             final String signature,
624             final String[] exceptions,
625             final int compute) {
626         super(/* latest api = */ Opcodes.ASM8);
627         this.symbolTable = symbolTable;
628         this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
629         this.nameIndex = symbolTable.addConstantUtf8(name);
630         this.name = name;
631         this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
632         this.descriptor = descriptor;
633         this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature);
634         if (exceptions != null && exceptions.length > 0) {
635             numberOfExceptions = exceptions.length;
636             this.exceptionIndexTable = new int[numberOfExceptions];
637             for (int i = 0; i < numberOfExceptions; ++i) {
638                 this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index;
639             }
640         } else {
641             numberOfExceptions = 0;
642             this.exceptionIndexTable = null;
643         }
644         this.compute = compute;
645         if (compute != COMPUTE_NOTHING) {
646             // Update maxLocals and currentLocals.
647             int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
648             if ((access & Opcodes.ACC_STATIC) != 0) {
649                 --argumentsSize;
650             }
651             maxLocals = argumentsSize;
652             currentLocals = argumentsSize;
653             // Create and visit the label for the first basic block.
654             firstBasicBlock = new Label();
655             visitLabel(firstBasicBlock);
656         }
657     }
658 
hasFrames()659     boolean hasFrames() {
660         return stackMapTableNumberOfEntries > 0;
661     }
662 
hasAsmInstructions()663     boolean hasAsmInstructions() {
664         return hasAsmInstructions;
665     }
666 
667     // -----------------------------------------------------------------------------------------------
668     // Implementation of the MethodVisitor abstract class
669     // -----------------------------------------------------------------------------------------------
670 
671     @Override
visitParameter(final String name, final int access)672     public void visitParameter(final String name, final int access) {
673         if (parameters == null) {
674             parameters = new ByteVector();
675         }
676         ++parametersCount;
677         parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access);
678     }
679 
680     @Override
visitAnnotationDefault()681     public AnnotationVisitor visitAnnotationDefault() {
682         defaultValue = new ByteVector();
683         return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null);
684     }
685 
686     @Override
visitAnnotation(final String descriptor, final boolean visible)687     public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
688         if (visible) {
689             return lastRuntimeVisibleAnnotation =
690                     AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
691         } else {
692             return lastRuntimeInvisibleAnnotation =
693                     AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
694         }
695     }
696 
697     @Override
visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)698     public AnnotationVisitor visitTypeAnnotation(
699             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
700         if (visible) {
701             return lastRuntimeVisibleTypeAnnotation =
702                     AnnotationWriter.create(
703                             symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
704         } else {
705             return lastRuntimeInvisibleTypeAnnotation =
706                     AnnotationWriter.create(
707                             symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
708         }
709     }
710 
711     @Override
visitAnnotableParameterCount(final int parameterCount, final boolean visible)712     public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
713         if (visible) {
714             visibleAnnotableParameterCount = parameterCount;
715         } else {
716             invisibleAnnotableParameterCount = parameterCount;
717         }
718     }
719 
720     @Override
visitParameterAnnotation( final int parameter, final String annotationDescriptor, final boolean visible)721     public AnnotationVisitor visitParameterAnnotation(
722             final int parameter, final String annotationDescriptor, final boolean visible) {
723         if (visible) {
724             if (lastRuntimeVisibleParameterAnnotations == null) {
725                 lastRuntimeVisibleParameterAnnotations =
726                         new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
727             }
728             return lastRuntimeVisibleParameterAnnotations[parameter] =
729                     AnnotationWriter.create(
730                             symbolTable, annotationDescriptor, lastRuntimeVisibleParameterAnnotations[parameter]);
731         } else {
732             if (lastRuntimeInvisibleParameterAnnotations == null) {
733                 lastRuntimeInvisibleParameterAnnotations =
734                         new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
735             }
736             return lastRuntimeInvisibleParameterAnnotations[parameter] =
737                     AnnotationWriter.create(
738                             symbolTable,
739                             annotationDescriptor,
740                             lastRuntimeInvisibleParameterAnnotations[parameter]);
741         }
742     }
743 
744     @Override
visitAttribute(final Attribute attribute)745     public void visitAttribute(final Attribute attribute) {
746         // Store the attributes in the <i>reverse</i> order of their visit by this method.
747         if (attribute.isCodeAttribute()) {
748             attribute.nextAttribute = firstCodeAttribute;
749             firstCodeAttribute = attribute;
750         } else {
751             attribute.nextAttribute = firstAttribute;
752             firstAttribute = attribute;
753         }
754     }
755 
756     @Override
visitCode()757     public void visitCode() {
758         // Nothing to do.
759     }
760 
761     @Override
visitFrame( final int type, final int numLocal, final Object[] local, final int numStack, final Object[] stack)762     public void visitFrame(
763             final int type,
764             final int numLocal,
765             final Object[] local,
766             final int numStack,
767             final Object[] stack) {
768         if (compute == COMPUTE_ALL_FRAMES) {
769             return;
770         }
771 
772         if (compute == COMPUTE_INSERTED_FRAMES) {
773             if (currentBasicBlock.frame == null) {
774                 // This should happen only once, for the implicit first frame (which is explicitly visited
775                 // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES
776                 // can't be set if EXPAND_ASM_INSNS is not used).
777                 currentBasicBlock.frame = new CurrentFrame(currentBasicBlock);
778                 currentBasicBlock.frame.setInputFrameFromDescriptor(
779                         symbolTable, accessFlags, descriptor, numLocal);
780                 currentBasicBlock.frame.accept(this);
781             } else {
782                 if (type == Opcodes.F_NEW) {
783                     currentBasicBlock.frame.setInputFrameFromApiFormat(
784                             symbolTable, numLocal, local, numStack, stack);
785                 }
786                 // If type is not F_NEW then it is F_INSERT by hypothesis, and currentBlock.frame contains
787                 // the stack map frame at the current instruction, computed from the last F_NEW frame and
788                 // the bytecode instructions in between (via calls to CurrentFrame#execute).
789                 currentBasicBlock.frame.accept(this);
790             }
791         } else if (type == Opcodes.F_NEW) {
792             if (previousFrame == null) {
793                 int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
794                 Frame implicitFirstFrame = new Frame(new Label());
795                 implicitFirstFrame.setInputFrameFromDescriptor(
796                         symbolTable, accessFlags, descriptor, argumentsSize);
797                 implicitFirstFrame.accept(this);
798             }
799             currentLocals = numLocal;
800             int frameIndex = visitFrameStart(code.length, numLocal, numStack);
801             for (int i = 0; i < numLocal; ++i) {
802                 currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]);
803             }
804             for (int i = 0; i < numStack; ++i) {
805                 currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]);
806             }
807             visitFrameEnd();
808         } else {
809             if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
810                 throw new IllegalArgumentException("Class versions V1_5 or less must use F_NEW frames.");
811             }
812             int offsetDelta;
813             if (stackMapTableEntries == null) {
814                 stackMapTableEntries = new ByteVector();
815                 offsetDelta = code.length;
816             } else {
817                 offsetDelta = code.length - previousFrameOffset - 1;
818                 if (offsetDelta < 0) {
819                     if (type == Opcodes.F_SAME) {
820                         return;
821                     } else {
822                         throw new IllegalStateException();
823                     }
824                 }
825             }
826 
827             switch (type) {
828                 case Opcodes.F_FULL:
829                     currentLocals = numLocal;
830                     stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
831                     for (int i = 0; i < numLocal; ++i) {
832                         putFrameType(local[i]);
833                     }
834                     stackMapTableEntries.putShort(numStack);
835                     for (int i = 0; i < numStack; ++i) {
836                         putFrameType(stack[i]);
837                     }
838                     break;
839                 case Opcodes.F_APPEND:
840                     currentLocals += numLocal;
841                     stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + numLocal).putShort(offsetDelta);
842                     for (int i = 0; i < numLocal; ++i) {
843                         putFrameType(local[i]);
844                     }
845                     break;
846                 case Opcodes.F_CHOP:
847                     currentLocals -= numLocal;
848                     stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - numLocal).putShort(offsetDelta);
849                     break;
850                 case Opcodes.F_SAME:
851                     if (offsetDelta < 64) {
852                         stackMapTableEntries.putByte(offsetDelta);
853                     } else {
854                         stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
855                     }
856                     break;
857                 case Opcodes.F_SAME1:
858                     if (offsetDelta < 64) {
859                         stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
860                     } else {
861                         stackMapTableEntries
862                                 .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
863                                 .putShort(offsetDelta);
864                     }
865                     putFrameType(stack[0]);
866                     break;
867                 default:
868                     throw new IllegalArgumentException();
869             }
870 
871             previousFrameOffset = code.length;
872             ++stackMapTableNumberOfEntries;
873         }
874 
875         if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
876             relativeStackSize = numStack;
877             for (int i = 0; i < numStack; ++i) {
878                 if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
879                     relativeStackSize++;
880                 }
881             }
882             if (relativeStackSize > maxRelativeStackSize) {
883                 maxRelativeStackSize = relativeStackSize;
884             }
885         }
886 
887         maxStack = Math.max(maxStack, numStack);
888         maxLocals = Math.max(maxLocals, currentLocals);
889     }
890 
891     @Override
visitInsn(final int opcode)892     public void visitInsn(final int opcode) {
893         lastBytecodeOffset = code.length;
894         // Add the instruction to the bytecode of the method.
895         code.putByte(opcode);
896         // If needed, update the maximum stack size and number of locals, and stack map frames.
897         if (currentBasicBlock != null) {
898             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
899                 currentBasicBlock.frame.execute(opcode, 0, null, null);
900             } else {
901                 int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
902                 if (size > maxRelativeStackSize) {
903                     maxRelativeStackSize = size;
904                 }
905                 relativeStackSize = size;
906             }
907             if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
908                 endCurrentBasicBlockWithNoSuccessor();
909             }
910         }
911     }
912 
913     @Override
visitIntInsn(final int opcode, final int operand)914     public void visitIntInsn(final int opcode, final int operand) {
915         lastBytecodeOffset = code.length;
916         // Add the instruction to the bytecode of the method.
917         if (opcode == Opcodes.SIPUSH) {
918             code.put12(opcode, operand);
919         } else { // BIPUSH or NEWARRAY
920             code.put11(opcode, operand);
921         }
922         // If needed, update the maximum stack size and number of locals, and stack map frames.
923         if (currentBasicBlock != null) {
924             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
925                 currentBasicBlock.frame.execute(opcode, operand, null, null);
926             } else if (opcode != Opcodes.NEWARRAY) {
927                 // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY.
928                 int size = relativeStackSize + 1;
929                 if (size > maxRelativeStackSize) {
930                     maxRelativeStackSize = size;
931                 }
932                 relativeStackSize = size;
933             }
934         }
935     }
936 
937     @Override
visitVarInsn(final int opcode, final int var)938     public void visitVarInsn(final int opcode, final int var) {
939         lastBytecodeOffset = code.length;
940         // Add the instruction to the bytecode of the method.
941         if (var < 4 && opcode != Opcodes.RET) {
942             int optimizedOpcode;
943             if (opcode < Opcodes.ISTORE) {
944                 optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + var;
945             } else {
946                 optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + var;
947             }
948             code.putByte(optimizedOpcode);
949         } else if (var >= 256) {
950             code.putByte(Constants.WIDE).put12(opcode, var);
951         } else {
952             code.put11(opcode, var);
953         }
954         // If needed, update the maximum stack size and number of locals, and stack map frames.
955         if (currentBasicBlock != null) {
956             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
957                 currentBasicBlock.frame.execute(opcode, var, null, null);
958             } else {
959                 if (opcode == Opcodes.RET) {
960                     // No stack size delta.
961                     currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END;
962                     currentBasicBlock.outputStackSize = (short) relativeStackSize;
963                     endCurrentBasicBlockWithNoSuccessor();
964                 } else { // xLOAD or xSTORE
965                     int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
966                     if (size > maxRelativeStackSize) {
967                         maxRelativeStackSize = size;
968                     }
969                     relativeStackSize = size;
970                 }
971             }
972         }
973         if (compute != COMPUTE_NOTHING) {
974             int currentMaxLocals;
975             if (opcode == Opcodes.LLOAD
976                     || opcode == Opcodes.DLOAD
977                     || opcode == Opcodes.LSTORE
978                     || opcode == Opcodes.DSTORE) {
979                 currentMaxLocals = var + 2;
980             } else {
981                 currentMaxLocals = var + 1;
982             }
983             if (currentMaxLocals > maxLocals) {
984                 maxLocals = currentMaxLocals;
985             }
986         }
987         if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) {
988             // If there are exception handler blocks, each instruction within a handler range is, in
989             // theory, a basic block (since execution can jump from this instruction to the exception
990             // handler). As a consequence, the local variable types at the beginning of the handler
991             // block should be the merge of the local variable types at all the instructions within the
992             // handler range. However, instead of creating a basic block for each instruction, we can
993             // get the same result in a more efficient way. Namely, by starting a new basic block after
994             // each xSTORE instruction, which is what we do here.
995             visitLabel(new Label());
996         }
997     }
998 
999     @Override
visitTypeInsn(final int opcode, final String type)1000     public void visitTypeInsn(final int opcode, final String type) {
1001         lastBytecodeOffset = code.length;
1002         // Add the instruction to the bytecode of the method.
1003         Symbol typeSymbol = symbolTable.addConstantClass(type);
1004         code.put12(opcode, typeSymbol.index);
1005         // If needed, update the maximum stack size and number of locals, and stack map frames.
1006         if (currentBasicBlock != null) {
1007             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1008                 currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable);
1009             } else if (opcode == Opcodes.NEW) {
1010                 // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF.
1011                 int size = relativeStackSize + 1;
1012                 if (size > maxRelativeStackSize) {
1013                     maxRelativeStackSize = size;
1014                 }
1015                 relativeStackSize = size;
1016             }
1017         }
1018     }
1019 
1020     @Override
visitFieldInsn( final int opcode, final String owner, final String name, final String descriptor)1021     public void visitFieldInsn(
1022             final int opcode, final String owner, final String name, final String descriptor) {
1023         lastBytecodeOffset = code.length;
1024         // Add the instruction to the bytecode of the method.
1025         Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor);
1026         code.put12(opcode, fieldrefSymbol.index);
1027         // If needed, update the maximum stack size and number of locals, and stack map frames.
1028         if (currentBasicBlock != null) {
1029             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1030                 currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable);
1031             } else {
1032                 int size;
1033                 char firstDescChar = descriptor.charAt(0);
1034                 switch (opcode) {
1035                     case Opcodes.GETSTATIC:
1036                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1);
1037                         break;
1038                     case Opcodes.PUTSTATIC:
1039                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1);
1040                         break;
1041                     case Opcodes.GETFIELD:
1042                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0);
1043                         break;
1044                     case Opcodes.PUTFIELD:
1045                     default:
1046                         size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2);
1047                         break;
1048                 }
1049                 if (size > maxRelativeStackSize) {
1050                     maxRelativeStackSize = size;
1051                 }
1052                 relativeStackSize = size;
1053             }
1054         }
1055     }
1056 
1057     @Override
visitMethodInsn( final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface)1058     public void visitMethodInsn(
1059             final int opcode,
1060             final String owner,
1061             final String name,
1062             final String descriptor,
1063             final boolean isInterface) {
1064         lastBytecodeOffset = code.length;
1065         // Add the instruction to the bytecode of the method.
1066         Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface);
1067         if (opcode == Opcodes.INVOKEINTERFACE) {
1068             code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index)
1069                     .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0);
1070         } else {
1071             code.put12(opcode, methodrefSymbol.index);
1072         }
1073         // If needed, update the maximum stack size and number of locals, and stack map frames.
1074         if (currentBasicBlock != null) {
1075             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1076                 currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable);
1077             } else {
1078                 int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes();
1079                 int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2);
1080                 int size;
1081                 if (opcode == Opcodes.INVOKESTATIC) {
1082                     size = relativeStackSize + stackSizeDelta + 1;
1083                 } else {
1084                     size = relativeStackSize + stackSizeDelta;
1085                 }
1086                 if (size > maxRelativeStackSize) {
1087                     maxRelativeStackSize = size;
1088                 }
1089                 relativeStackSize = size;
1090             }
1091         }
1092     }
1093 
1094     @Override
visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)1095     public void visitInvokeDynamicInsn(
1096             final String name,
1097             final String descriptor,
1098             final Handle bootstrapMethodHandle,
1099             final Object... bootstrapMethodArguments) {
1100         lastBytecodeOffset = code.length;
1101         // Add the instruction to the bytecode of the method.
1102         Symbol invokeDynamicSymbol =
1103                 symbolTable.addConstantInvokeDynamic(
1104                         name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
1105         code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index);
1106         code.putShort(0);
1107         // If needed, update the maximum stack size and number of locals, and stack map frames.
1108         if (currentBasicBlock != null) {
1109             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1110                 currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable);
1111             } else {
1112                 int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes();
1113                 int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1;
1114                 int size = relativeStackSize + stackSizeDelta;
1115                 if (size > maxRelativeStackSize) {
1116                     maxRelativeStackSize = size;
1117                 }
1118                 relativeStackSize = size;
1119             }
1120         }
1121     }
1122 
1123     @Override
visitJumpInsn(final int opcode, final Label label)1124     public void visitJumpInsn(final int opcode, final Label label) {
1125         lastBytecodeOffset = code.length;
1126         // Add the instruction to the bytecode of the method.
1127         // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode.
1128         int baseOpcode =
1129                 opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode;
1130         boolean nextInsnIsJumpTarget = false;
1131         if ((label.flags & Label.FLAG_RESOLVED) != 0
1132                 && label.bytecodeOffset - code.length < Short.MIN_VALUE) {
1133             // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO
1134             // with GOTO_W, JSR with JSR_W and IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., where
1135             // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where <L> designates
1136             // the instruction just after the GOTO_W.
1137             if (baseOpcode == Opcodes.GOTO) {
1138                 code.putByte(Constants.GOTO_W);
1139             } else if (baseOpcode == Opcodes.JSR) {
1140                 code.putByte(Constants.JSR_W);
1141             } else {
1142                 // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least
1143                 // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a
1144                 // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W).
1145                 code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1);
1146                 code.putShort(8);
1147                 // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this
1148                 // method or another one, and if the class has frames, we will need to insert a frame after
1149                 // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM
1150                 // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W
1151                 // here, which has the unfortunate effect of forcing this additional round trip (which in
1152                 // some case would not have been really necessary, but we can't know this at this point).
1153                 code.putByte(Constants.ASM_GOTO_W);
1154                 hasAsmInstructions = true;
1155                 // The instruction after the GOTO_W becomes the target of the IFNOT instruction.
1156                 nextInsnIsJumpTarget = true;
1157             }
1158             label.put(code, code.length - 1, true);
1159         } else if (baseOpcode != opcode) {
1160             // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove
1161             // ASM specific instructions). In this case we keep the original instruction.
1162             code.putByte(opcode);
1163             label.put(code, code.length - 1, true);
1164         } else {
1165             // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these
1166             // cases we store the offset in 2 bytes (which will be increased via a ClassReader ->
1167             // ClassWriter round trip if it turns out that 2 bytes are not sufficient).
1168             code.putByte(baseOpcode);
1169             label.put(code, code.length - 1, false);
1170         }
1171 
1172         // If needed, update the maximum stack size and number of locals, and stack map frames.
1173         if (currentBasicBlock != null) {
1174             Label nextBasicBlock = null;
1175             if (compute == COMPUTE_ALL_FRAMES) {
1176                 currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
1177                 // Record the fact that 'label' is the target of a jump instruction.
1178                 label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1179                 // Add 'label' as a successor of the current basic block.
1180                 addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1181                 if (baseOpcode != Opcodes.GOTO) {
1182                     // The next instruction starts a new basic block (except for GOTO: by default the code
1183                     // following a goto is unreachable - unless there is an explicit label for it - and we
1184                     // should not compute stack frame types for its instructions).
1185                     nextBasicBlock = new Label();
1186                 }
1187             } else if (compute == COMPUTE_INSERTED_FRAMES) {
1188                 currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
1189             } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
1190                 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1191                 relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
1192             } else {
1193                 if (baseOpcode == Opcodes.JSR) {
1194                     // Record the fact that 'label' designates a subroutine, if not already done.
1195                     if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) {
1196                         label.flags |= Label.FLAG_SUBROUTINE_START;
1197                         hasSubroutines = true;
1198                     }
1199                     currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER;
1200                     // Note that, by construction in this method, a block which calls a subroutine has at
1201                     // least two successors in the control flow graph: the first one (added below) leads to
1202                     // the instruction after the JSR, while the second one (added here) leads to the JSR
1203                     // target. Note that the first successor is virtual (it does not correspond to a possible
1204                     // execution path): it is only used to compute the successors of the basic blocks ending
1205                     // with a ret, in {@link Label#addSubroutineRetSuccessors}.
1206                     addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label);
1207                     // The instruction after the JSR starts a new basic block.
1208                     nextBasicBlock = new Label();
1209                 } else {
1210                     // No need to update maxRelativeStackSize (the stack size delta is always negative).
1211                     relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
1212                     addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1213                 }
1214             }
1215             // If the next instruction starts a new basic block, call visitLabel to add the label of this
1216             // instruction as a successor of the current block, and to start a new basic block.
1217             if (nextBasicBlock != null) {
1218                 if (nextInsnIsJumpTarget) {
1219                     nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET;
1220                 }
1221                 visitLabel(nextBasicBlock);
1222             }
1223             if (baseOpcode == Opcodes.GOTO) {
1224                 endCurrentBasicBlockWithNoSuccessor();
1225             }
1226         }
1227     }
1228 
1229     @Override
visitLabel(final Label label)1230     public void visitLabel(final Label label) {
1231         // Resolve the forward references to this label, if any.
1232         hasAsmInstructions |= label.resolve(code.data, code.length);
1233         // visitLabel starts a new basic block (except for debug only labels), so we need to update the
1234         // previous and current block references and list of successors.
1235         if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) {
1236             return;
1237         }
1238         if (compute == COMPUTE_ALL_FRAMES) {
1239             if (currentBasicBlock != null) {
1240                 if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) {
1241                     // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only
1242                     // one place, but this does not work for labels which have not been visited yet.
1243                     // Therefore, when we detect here two labels having the same bytecode offset, we need to
1244                     // - consolidate the state scattered in these two instances into the canonical instance:
1245                     currentBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET);
1246                     // - make sure the two instances share the same Frame instance (the implementation of
1247                     // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be
1248                     // null):
1249                     label.frame = currentBasicBlock.frame;
1250                     // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so
1251                     // that they still refer to the canonical instance for this bytecode offset.
1252                     return;
1253                 }
1254                 // End the current basic block (with one new successor).
1255                 addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1256             }
1257             // Append 'label' at the end of the basic block list.
1258             if (lastBasicBlock != null) {
1259                 if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) {
1260                     // Same comment as above.
1261                     lastBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET);
1262                     // Here label.frame should be null.
1263                     label.frame = lastBasicBlock.frame;
1264                     currentBasicBlock = lastBasicBlock;
1265                     return;
1266                 }
1267                 lastBasicBlock.nextBasicBlock = label;
1268             }
1269             lastBasicBlock = label;
1270             // Make it the new current basic block.
1271             currentBasicBlock = label;
1272             // Here label.frame should be null.
1273             label.frame = new Frame(label);
1274         } else if (compute == COMPUTE_INSERTED_FRAMES) {
1275             if (currentBasicBlock == null) {
1276                 // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
1277                 // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged.
1278                 currentBasicBlock = label;
1279             } else {
1280                 // Update the frame owner so that a correct frame offset is computed in Frame.accept().
1281                 currentBasicBlock.frame.owner = label;
1282             }
1283         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1284             if (currentBasicBlock != null) {
1285                 // End the current basic block (with one new successor).
1286                 currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
1287                 addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1288             }
1289             // Start a new current basic block, and reset the current and maximum relative stack sizes.
1290             currentBasicBlock = label;
1291             relativeStackSize = 0;
1292             maxRelativeStackSize = 0;
1293             // Append the new basic block at the end of the basic block list.
1294             if (lastBasicBlock != null) {
1295                 lastBasicBlock.nextBasicBlock = label;
1296             }
1297             lastBasicBlock = label;
1298         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES && currentBasicBlock == null) {
1299             // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
1300             // compute is equal to COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES, currentBasicBlock stays
1301             // unchanged.
1302             currentBasicBlock = label;
1303         }
1304     }
1305 
1306     @Override
visitLdcInsn(final Object value)1307     public void visitLdcInsn(final Object value) {
1308         lastBytecodeOffset = code.length;
1309         // Add the instruction to the bytecode of the method.
1310         Symbol constantSymbol = symbolTable.addConstant(value);
1311         int constantIndex = constantSymbol.index;
1312         char firstDescriptorChar;
1313         boolean isLongOrDouble =
1314                 constantSymbol.tag == Symbol.CONSTANT_LONG_TAG
1315                         || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG
1316                         || (constantSymbol.tag == Symbol.CONSTANT_DYNAMIC_TAG
1317                                 && ((firstDescriptorChar = constantSymbol.value.charAt(0)) == 'J'
1318                                         || firstDescriptorChar == 'D'));
1319         if (isLongOrDouble) {
1320             code.put12(Constants.LDC2_W, constantIndex);
1321         } else if (constantIndex >= 256) {
1322             code.put12(Constants.LDC_W, constantIndex);
1323         } else {
1324             code.put11(Opcodes.LDC, constantIndex);
1325         }
1326         // If needed, update the maximum stack size and number of locals, and stack map frames.
1327         if (currentBasicBlock != null) {
1328             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1329                 currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable);
1330             } else {
1331                 int size = relativeStackSize + (isLongOrDouble ? 2 : 1);
1332                 if (size > maxRelativeStackSize) {
1333                     maxRelativeStackSize = size;
1334                 }
1335                 relativeStackSize = size;
1336             }
1337         }
1338     }
1339 
1340     @Override
visitIincInsn(final int var, final int increment)1341     public void visitIincInsn(final int var, final int increment) {
1342         lastBytecodeOffset = code.length;
1343         // Add the instruction to the bytecode of the method.
1344         if ((var > 255) || (increment > 127) || (increment < -128)) {
1345             code.putByte(Constants.WIDE).put12(Opcodes.IINC, var).putShort(increment);
1346         } else {
1347             code.putByte(Opcodes.IINC).put11(var, increment);
1348         }
1349         // If needed, update the maximum stack size and number of locals, and stack map frames.
1350         if (currentBasicBlock != null
1351                 && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) {
1352             currentBasicBlock.frame.execute(Opcodes.IINC, var, null, null);
1353         }
1354         if (compute != COMPUTE_NOTHING) {
1355             int currentMaxLocals = var + 1;
1356             if (currentMaxLocals > maxLocals) {
1357                 maxLocals = currentMaxLocals;
1358             }
1359         }
1360     }
1361 
1362     @Override
visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label... labels)1363     public void visitTableSwitchInsn(
1364             final int min, final int max, final Label dflt, final Label... labels) {
1365         lastBytecodeOffset = code.length;
1366         // Add the instruction to the bytecode of the method.
1367         code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
1368         dflt.put(code, lastBytecodeOffset, true);
1369         code.putInt(min).putInt(max);
1370         for (Label label : labels) {
1371             label.put(code, lastBytecodeOffset, true);
1372         }
1373         // If needed, update the maximum stack size and number of locals, and stack map frames.
1374         visitSwitchInsn(dflt, labels);
1375     }
1376 
1377     @Override
visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)1378     public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
1379         lastBytecodeOffset = code.length;
1380         // Add the instruction to the bytecode of the method.
1381         code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
1382         dflt.put(code, lastBytecodeOffset, true);
1383         code.putInt(labels.length);
1384         for (int i = 0; i < labels.length; ++i) {
1385             code.putInt(keys[i]);
1386             labels[i].put(code, lastBytecodeOffset, true);
1387         }
1388         // If needed, update the maximum stack size and number of locals, and stack map frames.
1389         visitSwitchInsn(dflt, labels);
1390     }
1391 
visitSwitchInsn(final Label dflt, final Label[] labels)1392     private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1393         if (currentBasicBlock != null) {
1394             if (compute == COMPUTE_ALL_FRAMES) {
1395                 currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1396                 // Add all the labels as successors of the current basic block.
1397                 addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt);
1398                 dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1399                 for (Label label : labels) {
1400                     addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1401                     label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1402                 }
1403             } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1404                 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1405                 --relativeStackSize;
1406                 // Add all the labels as successors of the current basic block.
1407                 addSuccessorToCurrentBasicBlock(relativeStackSize, dflt);
1408                 for (Label label : labels) {
1409                     addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1410                 }
1411             }
1412             // End the current basic block.
1413             endCurrentBasicBlockWithNoSuccessor();
1414         }
1415     }
1416 
1417     @Override
visitMultiANewArrayInsn(final String descriptor, final int numDimensions)1418     public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
1419         lastBytecodeOffset = code.length;
1420         // Add the instruction to the bytecode of the method.
1421         Symbol descSymbol = symbolTable.addConstantClass(descriptor);
1422         code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions);
1423         // If needed, update the maximum stack size and number of locals, and stack map frames.
1424         if (currentBasicBlock != null) {
1425             if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1426                 currentBasicBlock.frame.execute(
1427                         Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable);
1428             } else {
1429                 // No need to update maxRelativeStackSize (the stack size delta is always negative).
1430                 relativeStackSize += 1 - numDimensions;
1431             }
1432         }
1433     }
1434 
1435     @Override
visitInsnAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1436     public AnnotationVisitor visitInsnAnnotation(
1437             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1438         if (visible) {
1439             return lastCodeRuntimeVisibleTypeAnnotation =
1440                     AnnotationWriter.create(
1441                             symbolTable,
1442                             (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
1443                             typePath,
1444                             descriptor,
1445                             lastCodeRuntimeVisibleTypeAnnotation);
1446         } else {
1447             return lastCodeRuntimeInvisibleTypeAnnotation =
1448                     AnnotationWriter.create(
1449                             symbolTable,
1450                             (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
1451                             typePath,
1452                             descriptor,
1453                             lastCodeRuntimeInvisibleTypeAnnotation);
1454         }
1455     }
1456 
1457     @Override
visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type)1458     public void visitTryCatchBlock(
1459             final Label start, final Label end, final Label handler, final String type) {
1460         Handler newHandler =
1461                 new Handler(
1462                         start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type);
1463         if (firstHandler == null) {
1464             firstHandler = newHandler;
1465         } else {
1466             lastHandler.nextHandler = newHandler;
1467         }
1468         lastHandler = newHandler;
1469     }
1470 
1471     @Override
visitTryCatchAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1472     public AnnotationVisitor visitTryCatchAnnotation(
1473             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1474         if (visible) {
1475             return lastCodeRuntimeVisibleTypeAnnotation =
1476                     AnnotationWriter.create(
1477                             symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeVisibleTypeAnnotation);
1478         } else {
1479             return lastCodeRuntimeInvisibleTypeAnnotation =
1480                     AnnotationWriter.create(
1481                             symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeInvisibleTypeAnnotation);
1482         }
1483     }
1484 
1485     @Override
visitLocalVariable( final String name, final String descriptor, final String signature, final Label start, final Label end, final int index)1486     public void visitLocalVariable(
1487             final String name,
1488             final String descriptor,
1489             final String signature,
1490             final Label start,
1491             final Label end,
1492             final int index) {
1493         if (signature != null) {
1494             if (localVariableTypeTable == null) {
1495                 localVariableTypeTable = new ByteVector();
1496             }
1497             ++localVariableTypeTableLength;
1498             localVariableTypeTable
1499                     .putShort(start.bytecodeOffset)
1500                     .putShort(end.bytecodeOffset - start.bytecodeOffset)
1501                     .putShort(symbolTable.addConstantUtf8(name))
1502                     .putShort(symbolTable.addConstantUtf8(signature))
1503                     .putShort(index);
1504         }
1505         if (localVariableTable == null) {
1506             localVariableTable = new ByteVector();
1507         }
1508         ++localVariableTableLength;
1509         localVariableTable
1510                 .putShort(start.bytecodeOffset)
1511                 .putShort(end.bytecodeOffset - start.bytecodeOffset)
1512                 .putShort(symbolTable.addConstantUtf8(name))
1513                 .putShort(symbolTable.addConstantUtf8(descriptor))
1514                 .putShort(index);
1515         if (compute != COMPUTE_NOTHING) {
1516             char firstDescChar = descriptor.charAt(0);
1517             int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1);
1518             if (currentMaxLocals > maxLocals) {
1519                 maxLocals = currentMaxLocals;
1520             }
1521         }
1522     }
1523 
1524     @Override
visitLocalVariableAnnotation( final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, final int[] index, final String descriptor, final boolean visible)1525     public AnnotationVisitor visitLocalVariableAnnotation(
1526             final int typeRef,
1527             final TypePath typePath,
1528             final Label[] start,
1529             final Label[] end,
1530             final int[] index,
1531             final String descriptor,
1532             final boolean visible) {
1533         // Create a ByteVector to hold a 'type_annotation' JVMS structure.
1534         // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
1535         ByteVector typeAnnotation = new ByteVector();
1536         // Write target_type, target_info, and target_path.
1537         typeAnnotation.putByte(typeRef >>> 24).putShort(start.length);
1538         for (int i = 0; i < start.length; ++i) {
1539             typeAnnotation
1540                     .putShort(start[i].bytecodeOffset)
1541                     .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset)
1542                     .putShort(index[i]);
1543         }
1544         TypePath.put(typePath, typeAnnotation);
1545         // Write type_index and reserve space for num_element_value_pairs.
1546         typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
1547         if (visible) {
1548             return lastCodeRuntimeVisibleTypeAnnotation =
1549                     new AnnotationWriter(
1550                             symbolTable,
1551                             /* useNamedValues = */ true,
1552                             typeAnnotation,
1553                             lastCodeRuntimeVisibleTypeAnnotation);
1554         } else {
1555             return lastCodeRuntimeInvisibleTypeAnnotation =
1556                     new AnnotationWriter(
1557                             symbolTable,
1558                             /* useNamedValues = */ true,
1559                             typeAnnotation,
1560                             lastCodeRuntimeInvisibleTypeAnnotation);
1561         }
1562     }
1563 
1564     @Override
visitLineNumber(final int line, final Label start)1565     public void visitLineNumber(final int line, final Label start) {
1566         if (lineNumberTable == null) {
1567             lineNumberTable = new ByteVector();
1568         }
1569         ++lineNumberTableLength;
1570         lineNumberTable.putShort(start.bytecodeOffset);
1571         lineNumberTable.putShort(line);
1572     }
1573 
1574     @Override
visitMaxs(final int maxStack, final int maxLocals)1575     public void visitMaxs(final int maxStack, final int maxLocals) {
1576         if (compute == COMPUTE_ALL_FRAMES) {
1577             computeAllFrames();
1578         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1579             computeMaxStackAndLocal();
1580         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
1581             this.maxStack = maxRelativeStackSize;
1582         } else {
1583             this.maxStack = maxStack;
1584             this.maxLocals = maxLocals;
1585         }
1586     }
1587 
1588     /** Computes all the stack map frames of the method, from scratch. */
computeAllFrames()1589     private void computeAllFrames() {
1590         // Complete the control flow graph with exception handler blocks.
1591         Handler handler = firstHandler;
1592         while (handler != null) {
1593             String catchTypeDescriptor =
1594                     handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor;
1595             int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor);
1596             // Mark handlerBlock as an exception handler.
1597             Label handlerBlock = handler.handlerPc.getCanonicalInstance();
1598             handlerBlock.flags |= Label.FLAG_JUMP_TARGET;
1599             // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
1600             Label handlerRangeBlock = handler.startPc.getCanonicalInstance();
1601             Label handlerRangeEnd = handler.endPc.getCanonicalInstance();
1602             while (handlerRangeBlock != handlerRangeEnd) {
1603                 handlerRangeBlock.outgoingEdges =
1604                         new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges);
1605                 handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
1606             }
1607             handler = handler.nextHandler;
1608         }
1609 
1610         // Create and visit the first (implicit) frame.
1611         Frame firstFrame = firstBasicBlock.frame;
1612         firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals);
1613         firstFrame.accept(this);
1614 
1615         // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks
1616         // whose stack map frame has changed) and, while there are blocks to process, remove one from
1617         // the list and update the stack map frames of its successor blocks in the control flow graph
1618         // (which might change them, in which case these blocks must be processed too, and are thus
1619         // added to the list of blocks to process). Also compute the maximum stack size of the method,
1620         // as a by-product.
1621         Label listOfBlocksToProcess = firstBasicBlock;
1622         listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
1623         int maxStackSize = 0;
1624         while (listOfBlocksToProcess != Label.EMPTY_LIST) {
1625             // Remove a basic block from the list of blocks to process.
1626             Label basicBlock = listOfBlocksToProcess;
1627             listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
1628             basicBlock.nextListElement = null;
1629             // By definition, basicBlock is reachable.
1630             basicBlock.flags |= Label.FLAG_REACHABLE;
1631             // Update the (absolute) maximum stack size.
1632             int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax;
1633             if (maxBlockStackSize > maxStackSize) {
1634                 maxStackSize = maxBlockStackSize;
1635             }
1636             // Update the successor blocks of basicBlock in the control flow graph.
1637             Edge outgoingEdge = basicBlock.outgoingEdges;
1638             while (outgoingEdge != null) {
1639                 Label successorBlock = outgoingEdge.successor.getCanonicalInstance();
1640                 boolean successorBlockChanged =
1641                         basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info);
1642                 if (successorBlockChanged && successorBlock.nextListElement == null) {
1643                     // If successorBlock has changed it must be processed. Thus, if it is not already in the
1644                     // list of blocks to process, add it to this list.
1645                     successorBlock.nextListElement = listOfBlocksToProcess;
1646                     listOfBlocksToProcess = successorBlock;
1647                 }
1648                 outgoingEdge = outgoingEdge.nextEdge;
1649             }
1650         }
1651 
1652         // Loop over all the basic blocks and visit the stack map frames that must be stored in the
1653         // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from
1654         // exception handler ranges.
1655         Label basicBlock = firstBasicBlock;
1656         while (basicBlock != null) {
1657             if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE))
1658                     == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) {
1659                 basicBlock.frame.accept(this);
1660             }
1661             if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) {
1662                 // Find the start and end bytecode offsets of this unreachable block.
1663                 Label nextBasicBlock = basicBlock.nextBasicBlock;
1664                 int startOffset = basicBlock.bytecodeOffset;
1665                 int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1;
1666                 if (endOffset >= startOffset) {
1667                     // Replace its instructions with NOP ... NOP ATHROW.
1668                     for (int i = startOffset; i < endOffset; ++i) {
1669                         code.data[i] = Opcodes.NOP;
1670                     }
1671                     code.data[endOffset] = (byte) Opcodes.ATHROW;
1672                     // Emit a frame for this unreachable block, with no local and a Throwable on the stack
1673                     // (so that the ATHROW could consume this Throwable if it were reachable).
1674                     int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
1675                     currentFrame[frameIndex] =
1676                             Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
1677                     visitFrameEnd();
1678                     // Remove this unreachable basic block from the exception handler ranges.
1679                     firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock);
1680                     // The maximum stack size is now at least one, because of the Throwable declared above.
1681                     maxStackSize = Math.max(maxStackSize, 1);
1682                 }
1683             }
1684             basicBlock = basicBlock.nextBasicBlock;
1685         }
1686 
1687         this.maxStack = maxStackSize;
1688     }
1689 
1690     /** Computes the maximum stack size of the method. */
computeMaxStackAndLocal()1691     private void computeMaxStackAndLocal() {
1692         // Complete the control flow graph with exception handler blocks.
1693         Handler handler = firstHandler;
1694         while (handler != null) {
1695             Label handlerBlock = handler.handlerPc;
1696             Label handlerRangeBlock = handler.startPc;
1697             Label handlerRangeEnd = handler.endPc;
1698             // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
1699             while (handlerRangeBlock != handlerRangeEnd) {
1700                 if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) {
1701                     handlerRangeBlock.outgoingEdges =
1702                             new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges);
1703                 } else {
1704                     // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing
1705                     // edges to preserve the hypothesis about JSR block successors order (see
1706                     // {@link #visitJumpInsn}).
1707                     handlerRangeBlock.outgoingEdges.nextEdge.nextEdge =
1708                             new Edge(
1709                                     Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge);
1710                 }
1711                 handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
1712             }
1713             handler = handler.nextHandler;
1714         }
1715 
1716         // Complete the control flow graph with the successor blocks of subroutines, if needed.
1717         if (hasSubroutines) {
1718             // First step: find the subroutines. This step determines, for each basic block, to which
1719             // subroutine(s) it belongs. Start with the main "subroutine":
1720             short numSubroutines = 1;
1721             firstBasicBlock.markSubroutine(numSubroutines);
1722             // Then, mark the subroutines called by the main subroutine, then the subroutines called by
1723             // those called by the main subroutine, etc.
1724             for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) {
1725                 Label basicBlock = firstBasicBlock;
1726                 while (basicBlock != null) {
1727                     if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0
1728                             && basicBlock.subroutineId == currentSubroutine) {
1729                         Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor;
1730                         if (jsrTarget.subroutineId == 0) {
1731                             // If this subroutine has not been marked yet, find its basic blocks.
1732                             jsrTarget.markSubroutine(++numSubroutines);
1733                         }
1734                     }
1735                     basicBlock = basicBlock.nextBasicBlock;
1736                 }
1737             }
1738             // Second step: find the successors in the control flow graph of each subroutine basic block
1739             // 'r' ending with a RET instruction. These successors are the virtual successors of the basic
1740             // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'.
1741             Label basicBlock = firstBasicBlock;
1742             while (basicBlock != null) {
1743                 if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
1744                     // By construction, jsr targets are stored in the second outgoing edge of basic blocks
1745                     // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}).
1746                     Label subroutine = basicBlock.outgoingEdges.nextEdge.successor;
1747                     subroutine.addSubroutineRetSuccessors(basicBlock);
1748                 }
1749                 basicBlock = basicBlock.nextBasicBlock;
1750             }
1751         }
1752 
1753         // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks
1754         // whose input stack size has changed) and, while there are blocks to process, remove one
1755         // from the list, update the input stack size of its successor blocks in the control flow
1756         // graph, and add these blocks to the list of blocks to process (if not already done).
1757         Label listOfBlocksToProcess = firstBasicBlock;
1758         listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
1759         int maxStackSize = maxStack;
1760         while (listOfBlocksToProcess != Label.EMPTY_LIST) {
1761             // Remove a basic block from the list of blocks to process. Note that we don't reset
1762             // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already
1763             // processed basic blocks.
1764             Label basicBlock = listOfBlocksToProcess;
1765             listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
1766             // Compute the (absolute) input stack size and maximum stack size of this block.
1767             int inputStackTop = basicBlock.inputStackSize;
1768             int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax;
1769             // Update the absolute maximum stack size of the method.
1770             if (maxBlockStackSize > maxStackSize) {
1771                 maxStackSize = maxBlockStackSize;
1772             }
1773             // Update the input stack size of the successor blocks of basicBlock in the control flow
1774             // graph, and add these blocks to the list of blocks to process, if not already done.
1775             Edge outgoingEdge = basicBlock.outgoingEdges;
1776             if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
1777                 // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual
1778                 // edges which lead to the instruction just after the jsr, and do not correspond to a
1779                 // possible execution path (see {@link #visitJumpInsn} and
1780                 // {@link Label#FLAG_SUBROUTINE_CALLER}).
1781                 outgoingEdge = outgoingEdge.nextEdge;
1782             }
1783             while (outgoingEdge != null) {
1784                 Label successorBlock = outgoingEdge.successor;
1785                 if (successorBlock.nextListElement == null) {
1786                     successorBlock.inputStackSize =
1787                             (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info);
1788                     successorBlock.nextListElement = listOfBlocksToProcess;
1789                     listOfBlocksToProcess = successorBlock;
1790                 }
1791                 outgoingEdge = outgoingEdge.nextEdge;
1792             }
1793         }
1794         this.maxStack = maxStackSize;
1795     }
1796 
1797     @Override
visitEnd()1798     public void visitEnd() {
1799         // Nothing to do.
1800     }
1801 
1802     // -----------------------------------------------------------------------------------------------
1803     // Utility methods: control flow analysis algorithm
1804     // -----------------------------------------------------------------------------------------------
1805 
1806     /**
1807       * Adds a successor to {@link #currentBasicBlock} in the control flow graph.
1808       *
1809       * @param info information about the control flow edge to be added.
1810       * @param successor the successor block to be added to the current basic block.
1811       */
addSuccessorToCurrentBasicBlock(final int info, final Label successor)1812     private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) {
1813         currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges);
1814     }
1815 
1816     /**
1817       * Ends the current basic block. This method must be used in the case where the current basic
1818       * block does not have any successor.
1819       *
1820       * <p>WARNING: this method must be called after the currently visited instruction has been put in
1821       * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic
1822       * block after the current instruction).
1823       */
endCurrentBasicBlockWithNoSuccessor()1824     private void endCurrentBasicBlockWithNoSuccessor() {
1825         if (compute == COMPUTE_ALL_FRAMES) {
1826             Label nextBasicBlock = new Label();
1827             nextBasicBlock.frame = new Frame(nextBasicBlock);
1828             nextBasicBlock.resolve(code.data, code.length);
1829             lastBasicBlock.nextBasicBlock = nextBasicBlock;
1830             lastBasicBlock = nextBasicBlock;
1831             currentBasicBlock = null;
1832         } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1833             currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
1834             currentBasicBlock = null;
1835         }
1836     }
1837 
1838     // -----------------------------------------------------------------------------------------------
1839     // Utility methods: stack map frames
1840     // -----------------------------------------------------------------------------------------------
1841 
1842     /**
1843       * Starts the visit of a new stack map frame, stored in {@link #currentFrame}.
1844       *
1845       * @param offset the bytecode offset of the instruction to which the frame corresponds.
1846       * @param numLocal the number of local variables in the frame.
1847       * @param numStack the number of stack elements in the frame.
1848       * @return the index of the next element to be written in this frame.
1849       */
visitFrameStart(final int offset, final int numLocal, final int numStack)1850     int visitFrameStart(final int offset, final int numLocal, final int numStack) {
1851         int frameLength = 3 + numLocal + numStack;
1852         if (currentFrame == null || currentFrame.length < frameLength) {
1853             currentFrame = new int[frameLength];
1854         }
1855         currentFrame[0] = offset;
1856         currentFrame[1] = numLocal;
1857         currentFrame[2] = numStack;
1858         return 3;
1859     }
1860 
1861     /**
1862       * Sets an abstract type in {@link #currentFrame}.
1863       *
1864       * @param frameIndex the index of the element to be set in {@link #currentFrame}.
1865       * @param abstractType an abstract type.
1866       */
visitAbstractType(final int frameIndex, final int abstractType)1867     void visitAbstractType(final int frameIndex, final int abstractType) {
1868         currentFrame[frameIndex] = abstractType;
1869     }
1870 
1871     /**
1872       * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by
1873       * updating the StackMapTable number_of_entries (except if the current frame is the first one,
1874       * which is implicit in StackMapTable). Then resets {@link #currentFrame} to {@literal null}.
1875       */
visitFrameEnd()1876     void visitFrameEnd() {
1877         if (previousFrame != null) {
1878             if (stackMapTableEntries == null) {
1879                 stackMapTableEntries = new ByteVector();
1880             }
1881             putFrame();
1882             ++stackMapTableNumberOfEntries;
1883         }
1884         previousFrame = currentFrame;
1885         currentFrame = null;
1886     }
1887 
1888     /** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */
putFrame()1889     private void putFrame() {
1890         final int numLocal = currentFrame[1];
1891         final int numStack = currentFrame[2];
1892         if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
1893             // Generate a StackMap attribute entry, which are always uncompressed.
1894             stackMapTableEntries.putShort(currentFrame[0]).putShort(numLocal);
1895             putAbstractTypes(3, 3 + numLocal);
1896             stackMapTableEntries.putShort(numStack);
1897             putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
1898             return;
1899         }
1900         final int offsetDelta =
1901                 stackMapTableNumberOfEntries == 0
1902                         ? currentFrame[0]
1903                         : currentFrame[0] - previousFrame[0] - 1;
1904         final int previousNumlocal = previousFrame[1];
1905         final int numLocalDelta = numLocal - previousNumlocal;
1906         int type = Frame.FULL_FRAME;
1907         if (numStack == 0) {
1908             switch (numLocalDelta) {
1909                 case -3:
1910                 case -2:
1911                 case -1:
1912                     type = Frame.CHOP_FRAME;
1913                     break;
1914                 case 0:
1915                     type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED;
1916                     break;
1917                 case 1:
1918                 case 2:
1919                 case 3:
1920                     type = Frame.APPEND_FRAME;
1921                     break;
1922                 default:
1923                     // Keep the FULL_FRAME type.
1924                     break;
1925             }
1926         } else if (numLocalDelta == 0 && numStack == 1) {
1927             type =
1928                     offsetDelta < 63
1929                             ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME
1930                             : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1931         }
1932         if (type != Frame.FULL_FRAME) {
1933             // Verify if locals are the same as in the previous frame.
1934             int frameIndex = 3;
1935             for (int i = 0; i < previousNumlocal && i < numLocal; i++) {
1936                 if (currentFrame[frameIndex] != previousFrame[frameIndex]) {
1937                     type = Frame.FULL_FRAME;
1938                     break;
1939                 }
1940                 frameIndex++;
1941             }
1942         }
1943         switch (type) {
1944             case Frame.SAME_FRAME:
1945                 stackMapTableEntries.putByte(offsetDelta);
1946                 break;
1947             case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME:
1948                 stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
1949                 putAbstractTypes(3 + numLocal, 4 + numLocal);
1950                 break;
1951             case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1952                 stackMapTableEntries
1953                         .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
1954                         .putShort(offsetDelta);
1955                 putAbstractTypes(3 + numLocal, 4 + numLocal);
1956                 break;
1957             case Frame.SAME_FRAME_EXTENDED:
1958                 stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
1959                 break;
1960             case Frame.CHOP_FRAME:
1961                 stackMapTableEntries
1962                         .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
1963                         .putShort(offsetDelta);
1964                 break;
1965             case Frame.APPEND_FRAME:
1966                 stackMapTableEntries
1967                         .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
1968                         .putShort(offsetDelta);
1969                 putAbstractTypes(3 + previousNumlocal, 3 + numLocal);
1970                 break;
1971             case Frame.FULL_FRAME:
1972             default:
1973                 stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
1974                 putAbstractTypes(3, 3 + numLocal);
1975                 stackMapTableEntries.putShort(numStack);
1976                 putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
1977                 break;
1978         }
1979     }
1980 
1981     /**
1982       * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the
1983       * JVMS verification_type_info format used in StackMapTable attributes.
1984       *
1985       * @param start index of the first type in {@link #currentFrame} to write.
1986       * @param end index of last type in {@link #currentFrame} to write (exclusive).
1987       */
1988     private void putAbstractTypes(final int start, final int end) {
1989         for (int i = start; i < end; ++i) {
1990             Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries);
1991         }
1992     }
1993 
1994     /**
1995       * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS
1996       * verification_type_info format used in StackMapTable attributes.
1997       *
1998       * @param type a frame element type described using the same format as in {@link
1999       *     MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
2000       *     Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or
2001       *     {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating
2002       *     a NEW instruction (for uninitialized types).
2003       */
2004     private void putFrameType(final Object type) {
2005         if (type instanceof Integer) {
2006             stackMapTableEntries.putByte(((Integer) type).intValue());
2007         } else if (type instanceof String) {
2008             stackMapTableEntries
2009                     .putByte(Frame.ITEM_OBJECT)
2010                     .putShort(symbolTable.addConstantClass((String) type).index);
2011         } else {
2012             stackMapTableEntries
2013                     .putByte(Frame.ITEM_UNINITIALIZED)
2014                     .putShort(((Label) type).bytecodeOffset);
2015         }
2016     }
2017 
2018     // -----------------------------------------------------------------------------------------------
2019     // Utility methods
2020     // -----------------------------------------------------------------------------------------------
2021 
2022     /**
2023       * Returns whether the attributes of this method can be copied from the attributes of the given
2024       * method (assuming there is no method visitor between the given ClassReader and this
2025       * MethodWriter). This method should only be called just after this MethodWriter has been created,
2026       * and before any content is visited. It returns true if the attributes corresponding to the
2027       * constructor arguments (at most a Signature, an Exception, a Deprecated and a Synthetic
2028       * attribute) are the same as the corresponding attributes in the given method.
2029       *
2030       * @param source the source ClassReader from which the attributes of this method might be copied.
2031       * @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes
2032       *     of this method might be copied contains a Synthetic attribute.
2033       * @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes
2034       *     of this method might be copied contains a Deprecated attribute.
2035       * @param descriptorIndex the descriptor_index field of the method_info JVMS structure from which
2036       *     the attributes of this method might be copied.
2037       * @param signatureIndex the constant pool index contained in the Signature attribute of the
2038       *     method_info JVMS structure from which the attributes of this method might be copied, or 0.
2039       * @param exceptionsOffset the offset in 'source.b' of the Exceptions attribute of the method_info
2040       *     JVMS structure from which the attributes of this method might be copied, or 0.
2041       * @return whether the attributes of this method can be copied from the attributes of the
2042       *     method_info JVMS structure in 'source.b', between 'methodInfoOffset' and 'methodInfoOffset'
2043       *     + 'methodInfoLength'.
2044       */
2045     boolean canCopyMethodAttributes(
2046             final ClassReader source,
2047             final boolean hasSyntheticAttribute,
2048             final boolean hasDeprecatedAttribute,
2049             final int descriptorIndex,
2050             final int signatureIndex,
2051             final int exceptionsOffset) {
2052         // If the method descriptor has changed, with more locals than the max_locals field of the
2053         // original Code attribute, if any, then the original method attributes can't be copied. A
2054         // conservative check on the descriptor changes alone ensures this (being more precise is not
2055         // worth the additional complexity, because these cases should be rare -- if a transform changes
2056         // a method descriptor, most of the time it needs to change the method's code too).
2057         if (source != symbolTable.getSource()
2058                 || descriptorIndex != this.descriptorIndex
2059                 || signatureIndex != this.signatureIndex
2060                 || hasDeprecatedAttribute != ((accessFlags & Opcodes.ACC_DEPRECATED) != 0)) {
2061             return false;
2062         }
2063         boolean needSyntheticAttribute =
2064                 symbolTable.getMajorVersion() < Opcodes.V1_5 && (accessFlags & Opcodes.ACC_SYNTHETIC) != 0;
2065         if (hasSyntheticAttribute != needSyntheticAttribute) {
2066             return false;
2067         }
2068         if (exceptionsOffset == 0) {
2069             if (numberOfExceptions != 0) {
2070                 return false;
2071             }
2072         } else if (source.readUnsignedShort(exceptionsOffset) == numberOfExceptions) {
2073             int currentExceptionOffset = exceptionsOffset + 2;
2074             for (int i = 0; i < numberOfExceptions; ++i) {
2075                 if (source.readUnsignedShort(currentExceptionOffset) != exceptionIndexTable[i]) {
2076                     return false;
2077                 }
2078                 currentExceptionOffset += 2;
2079             }
2080         }
2081         return true;
2082     }
2083 
2084     /**
2085       * Sets the source from which the attributes of this method will be copied.
2086       *
2087       * @param methodInfoOffset the offset in 'symbolTable.getSource()' of the method_info JVMS
2088       *     structure from which the attributes of this method will be copied.
2089       * @param methodInfoLength the length in 'symbolTable.getSource()' of the method_info JVMS
2090       *     structure from which the attributes of this method will be copied.
2091       */
2092     void setMethodAttributesSource(final int methodInfoOffset, final int methodInfoLength) {
2093         // Don't copy the attributes yet, instead store their location in the source class reader so
2094         // they can be copied later, in {@link #putMethodInfo}. Note that we skip the 6 header bytes
2095         // of the method_info JVMS structure.
2096         this.sourceOffset = methodInfoOffset + 6;
2097         this.sourceLength = methodInfoLength - 6;
2098     }
2099 
2100     /**
2101       * Returns the size of the method_info JVMS structure generated by this MethodWriter. Also add the
2102       * names of the attributes of this method in the constant pool.
2103       *
2104       * @return the size in bytes of the method_info JVMS structure.
2105       */
2106     int computeMethodInfoSize() {
2107         // If this method_info must be copied from an existing one, the size computation is trivial.
2108         if (sourceOffset != 0) {
2109             // sourceLength excludes the first 6 bytes for access_flags, name_index and descriptor_index.
2110             return 6 + sourceLength;
2111         }
2112         // 2 bytes each for access_flags, name_index, descriptor_index and attributes_count.
2113         int size = 8;
2114         // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2115         if (code.length > 0) {
2116             if (code.length > 65535) {
2117                 throw new MethodTooLargeException(
2118                         symbolTable.getClassName(), name, descriptor, code.length);
2119             }
2120             symbolTable.addConstantUtf8(Constants.CODE);
2121             // The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack,
2122             // max_locals, code_length and attributes_count, plus the bytecode and the exception table.
2123             size += 16 + code.length + Handler.getExceptionTableSize(firstHandler);
2124             if (stackMapTableEntries != null) {
2125                 boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;
2126                 symbolTable.addConstantUtf8(useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap");
2127                 // 6 header bytes and 2 bytes for number_of_entries.
2128                 size += 8 + stackMapTableEntries.length;
2129             }
2130             if (lineNumberTable != null) {
2131                 symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE);
2132                 // 6 header bytes and 2 bytes for line_number_table_length.
2133                 size += 8 + lineNumberTable.length;
2134             }
2135             if (localVariableTable != null) {
2136                 symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE);
2137                 // 6 header bytes and 2 bytes for local_variable_table_length.
2138                 size += 8 + localVariableTable.length;
2139             }
2140             if (localVariableTypeTable != null) {
2141                 symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE);
2142                 // 6 header bytes and 2 bytes for local_variable_type_table_length.
2143                 size += 8 + localVariableTypeTable.length;
2144             }
2145             if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2146                 size +=
2147                         lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
2148                                 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
2149             }
2150             if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2151                 size +=
2152                         lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
2153                                 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
2154             }
2155             if (firstCodeAttribute != null) {
2156                 size +=
2157                         firstCodeAttribute.computeAttributesSize(
2158                                 symbolTable, code.data, code.length, maxStack, maxLocals);
2159             }
2160         }
2161         if (numberOfExceptions > 0) {
2162             symbolTable.addConstantUtf8(Constants.EXCEPTIONS);
2163             size += 8 + 2 * numberOfExceptions;
2164         }
2165         size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex);
2166         size +=
2167                 AnnotationWriter.computeAnnotationsSize(
2168                         lastRuntimeVisibleAnnotation,
2169                         lastRuntimeInvisibleAnnotation,
2170                         lastRuntimeVisibleTypeAnnotation,
2171                         lastRuntimeInvisibleTypeAnnotation);
2172         if (lastRuntimeVisibleParameterAnnotations != null) {
2173             size +=
2174                     AnnotationWriter.computeParameterAnnotationsSize(
2175                             Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
2176                             lastRuntimeVisibleParameterAnnotations,
2177                             visibleAnnotableParameterCount == 0
2178                                     ? lastRuntimeVisibleParameterAnnotations.length
2179                                     : visibleAnnotableParameterCount);
2180         }
2181         if (lastRuntimeInvisibleParameterAnnotations != null) {
2182             size +=
2183                     AnnotationWriter.computeParameterAnnotationsSize(
2184                             Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,
2185                             lastRuntimeInvisibleParameterAnnotations,
2186                             invisibleAnnotableParameterCount == 0
2187                                     ? lastRuntimeInvisibleParameterAnnotations.length
2188                                     : invisibleAnnotableParameterCount);
2189         }
2190         if (defaultValue != null) {
2191             symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT);
2192             size += 6 + defaultValue.length;
2193         }
2194         if (parameters != null) {
2195             symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS);
2196             // 6 header bytes and 1 byte for parameters_count.
2197             size += 7 + parameters.length;
2198         }
2199         if (firstAttribute != null) {
2200             size += firstAttribute.computeAttributesSize(symbolTable);
2201         }
2202         return size;
2203     }
2204 
2205     /**
2206       * Puts the content of the method_info JVMS structure generated by this MethodWriter into the
2207       * given ByteVector.
2208       *
2209       * @param output where the method_info structure must be put.
2210       */
2211     void putMethodInfo(final ByteVector output) {
2212         boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
2213         int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
2214         output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
2215         // If this method_info must be copied from an existing one, copy it now and return early.
2216         if (sourceOffset != 0) {
2217             output.putByteArray(symbolTable.getSource().classFileBuffer, sourceOffset, sourceLength);
2218             return;
2219         }
2220         // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2221         int attributeCount = 0;
2222         if (code.length > 0) {
2223             ++attributeCount;
2224         }
2225         if (numberOfExceptions > 0) {
2226             ++attributeCount;
2227         }
2228         if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
2229             ++attributeCount;
2230         }
2231         if (signatureIndex != 0) {
2232             ++attributeCount;
2233         }
2234         if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
2235             ++attributeCount;
2236         }
2237         if (lastRuntimeVisibleAnnotation != null) {
2238             ++attributeCount;
2239         }
2240         if (lastRuntimeInvisibleAnnotation != null) {
2241             ++attributeCount;
2242         }
2243         if (lastRuntimeVisibleParameterAnnotations != null) {
2244             ++attributeCount;
2245         }
2246         if (lastRuntimeInvisibleParameterAnnotations != null) {
2247             ++attributeCount;
2248         }
2249         if (lastRuntimeVisibleTypeAnnotation != null) {
2250             ++attributeCount;
2251         }
2252         if (lastRuntimeInvisibleTypeAnnotation != null) {
2253             ++attributeCount;
2254         }
2255         if (defaultValue != null) {
2256             ++attributeCount;
2257         }
2258         if (parameters != null) {
2259             ++attributeCount;
2260         }
2261         if (firstAttribute != null) {
2262             attributeCount += firstAttribute.getAttributeCount();
2263         }
2264         // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
2265         output.putShort(attributeCount);
2266         if (code.length > 0) {
2267             // 2, 2, 4 and 2 bytes respectively for max_stack, max_locals, code_length and
2268             // attributes_count, plus the bytecode and the exception table.
2269             int size = 10 + code.length + Handler.getExceptionTableSize(firstHandler);
2270             int codeAttributeCount = 0;
2271             if (stackMapTableEntries != null) {
2272                 // 6 header bytes and 2 bytes for number_of_entries.
2273                 size += 8 + stackMapTableEntries.length;
2274                 ++codeAttributeCount;
2275             }
2276             if (lineNumberTable != null) {
2277                 // 6 header bytes and 2 bytes for line_number_table_length.
2278                 size += 8 + lineNumberTable.length;
2279                 ++codeAttributeCount;
2280             }
2281             if (localVariableTable != null) {
2282                 // 6 header bytes and 2 bytes for local_variable_table_length.
2283                 size += 8 + localVariableTable.length;
2284                 ++codeAttributeCount;
2285             }
2286             if (localVariableTypeTable != null) {
2287                 // 6 header bytes and 2 bytes for local_variable_type_table_length.
2288                 size += 8 + localVariableTypeTable.length;
2289                 ++codeAttributeCount;
2290             }
2291             if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2292                 size +=
2293                         lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
2294                                 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
2295                 ++codeAttributeCount;
2296             }
2297             if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2298                 size +=
2299                         lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
2300                                 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
2301                 ++codeAttributeCount;
2302             }
2303             if (firstCodeAttribute != null) {
2304                 size +=
2305                         firstCodeAttribute.computeAttributesSize(
2306                                 symbolTable, code.data, code.length, maxStack, maxLocals);
2307                 codeAttributeCount += firstCodeAttribute.getAttributeCount();
2308             }
2309             output
2310                     .putShort(symbolTable.addConstantUtf8(Constants.CODE))
2311                     .putInt(size)
2312                     .putShort(maxStack)
2313                     .putShort(maxLocals)
2314                     .putInt(code.length)
2315                     .putByteArray(code.data, 0, code.length);
2316             Handler.putExceptionTable(firstHandler, output);
2317             output.putShort(codeAttributeCount);
2318             if (stackMapTableEntries != null) {
2319                 boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;
2320                 output
2321                         .putShort(
2322                                 symbolTable.addConstantUtf8(
2323                                         useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap"))
2324                         .putInt(2 + stackMapTableEntries.length)
2325                         .putShort(stackMapTableNumberOfEntries)
2326                         .putByteArray(stackMapTableEntries.data, 0, stackMapTableEntries.length);
2327             }
2328             if (lineNumberTable != null) {
2329                 output
2330                         .putShort(symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE))
2331                         .putInt(2 + lineNumberTable.length)
2332                         .putShort(lineNumberTableLength)
2333                         .putByteArray(lineNumberTable.data, 0, lineNumberTable.length);
2334             }
2335             if (localVariableTable != null) {
2336                 output
2337                         .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE))
2338                         .putInt(2 + localVariableTable.length)
2339                         .putShort(localVariableTableLength)
2340                         .putByteArray(localVariableTable.data, 0, localVariableTable.length);
2341             }
2342             if (localVariableTypeTable != null) {
2343                 output
2344                         .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE))
2345                         .putInt(2 + localVariableTypeTable.length)
2346                         .putShort(localVariableTypeTableLength)
2347                         .putByteArray(localVariableTypeTable.data, 0, localVariableTypeTable.length);
2348             }
2349             if (lastCodeRuntimeVisibleTypeAnnotation != null) {
2350                 lastCodeRuntimeVisibleTypeAnnotation.putAnnotations(
2351                         symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
2352             }
2353             if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
2354                 lastCodeRuntimeInvisibleTypeAnnotation.putAnnotations(
2355                         symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
2356             }
2357             if (firstCodeAttribute != null) {
2358                 firstCodeAttribute.putAttributes(
2359                         symbolTable, code.data, code.length, maxStack, maxLocals, output);
2360             }
2361         }
2362         if (numberOfExceptions > 0) {
2363             output
2364                     .putShort(symbolTable.addConstantUtf8(Constants.EXCEPTIONS))
2365                     .putInt(2 + 2 * numberOfExceptions)
2366                     .putShort(numberOfExceptions);
2367             for (int exceptionIndex : exceptionIndexTable) {
2368                 output.putShort(exceptionIndex);
2369             }
2370         }
2371         Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
2372         AnnotationWriter.putAnnotations(
2373                 symbolTable,
2374                 lastRuntimeVisibleAnnotation,
2375                 lastRuntimeInvisibleAnnotation,
2376                 lastRuntimeVisibleTypeAnnotation,
2377                 lastRuntimeInvisibleTypeAnnotation,
2378                 output);
2379         if (lastRuntimeVisibleParameterAnnotations != null) {
2380             AnnotationWriter.putParameterAnnotations(
2381                     symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS),
2382                     lastRuntimeVisibleParameterAnnotations,
2383                     visibleAnnotableParameterCount == 0
2384                             ? lastRuntimeVisibleParameterAnnotations.length
2385                             : visibleAnnotableParameterCount,
2386                     output);
2387         }
2388         if (lastRuntimeInvisibleParameterAnnotations != null) {
2389             AnnotationWriter.putParameterAnnotations(
2390                     symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS),
2391                     lastRuntimeInvisibleParameterAnnotations,
2392                     invisibleAnnotableParameterCount == 0
2393                             ? lastRuntimeInvisibleParameterAnnotations.length
2394                             : invisibleAnnotableParameterCount,
2395                     output);
2396         }
2397         if (defaultValue != null) {
2398             output
2399                     .putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT))
2400                     .putInt(defaultValue.length)
2401                     .putByteArray(defaultValue.data, 0, defaultValue.length);
2402         }
2403         if (parameters != null) {
2404             output
2405                     .putShort(symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS))
2406                     .putInt(1 + parameters.length)
2407                     .putByte(parametersCount)
2408                     .putByteArray(parameters.data, 0, parameters.length);
2409         }
2410         if (firstAttribute != null) {
2411             firstAttribute.putAttributes(symbolTable, output);
2412         }
2413     }
2414 
2415     /**
2416       * Collects the attributes of this method into the given set of attribute prototypes.
2417       *
2418       * @param attributePrototypes a set of attribute prototypes.
2419       */
collectAttributePrototypes(final Attribute.Set attributePrototypes)2420     final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
2421         attributePrototypes.addAttributes(firstAttribute);
2422         attributePrototypes.addAttributes(firstCodeAttribute);
2423     }
2424 }
2425