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