• 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}, {@link
538    * Frame#UNINITIALIZED_KIND} or {@link Frame#FORWARD_UNINITIALIZED_KIND} abstract types. Long and
539    * double types use only one array entry.
540    */
541   private int[] currentFrame;
542 
543   /** Whether this method contains subroutines. */
544   private boolean hasSubroutines;
545 
546   // -----------------------------------------------------------------------------------------------
547   // Other miscellaneous status fields
548   // -----------------------------------------------------------------------------------------------
549 
550   /** Whether the bytecode of this method contains ASM specific instructions. */
551   private boolean hasAsmInstructions;
552 
553   /**
554    * The start offset of the last visited instruction. Used to set the offset field of type
555    * annotations of type 'offset_target' (see <a
556    * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS
557    * 4.7.20.1</a>).
558    */
559   private int lastBytecodeOffset;
560 
561   /**
562    * The offset in bytes in {@link SymbolTable#getSource} from which the method_info for this method
563    * (excluding its first 6 bytes) must be copied, or 0.
564    */
565   private int sourceOffset;
566 
567   /**
568    * The length in bytes in {@link SymbolTable#getSource} which must be copied to get the
569    * method_info for this method (excluding its first 6 bytes for access_flags, name_index and
570    * descriptor_index).
571    */
572   private int sourceLength;
573 
574   // -----------------------------------------------------------------------------------------------
575   // Constructor and accessors
576   // -----------------------------------------------------------------------------------------------
577 
578   /**
579    * Constructs a new {@link MethodWriter}.
580    *
581    * @param symbolTable where the constants used in this AnnotationWriter must be stored.
582    * @param access the method's access flags (see {@link Opcodes}).
583    * @param name the method's name.
584    * @param descriptor the method's descriptor (see {@link Type}).
585    * @param signature the method's signature. May be {@literal null}.
586    * @param exceptions the internal names of the method's exceptions. May be {@literal null}.
587    * @param compute indicates what must be computed (see #compute).
588    */
MethodWriter( final SymbolTable symbolTable, final int access, final String name, final String descriptor, final String signature, final String[] exceptions, final int compute)589   MethodWriter(
590       final SymbolTable symbolTable,
591       final int access,
592       final String name,
593       final String descriptor,
594       final String signature,
595       final String[] exceptions,
596       final int compute) {
597     super(/* latest api = */ Opcodes.ASM9);
598     this.symbolTable = symbolTable;
599     this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
600     this.nameIndex = symbolTable.addConstantUtf8(name);
601     this.name = name;
602     this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
603     this.descriptor = descriptor;
604     this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature);
605     if (exceptions != null && exceptions.length > 0) {
606       numberOfExceptions = exceptions.length;
607       this.exceptionIndexTable = new int[numberOfExceptions];
608       for (int i = 0; i < numberOfExceptions; ++i) {
609         this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index;
610       }
611     } else {
612       numberOfExceptions = 0;
613       this.exceptionIndexTable = null;
614     }
615     this.compute = compute;
616     if (compute != COMPUTE_NOTHING) {
617       // Update maxLocals and currentLocals.
618       int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
619       if ((access & Opcodes.ACC_STATIC) != 0) {
620         --argumentsSize;
621       }
622       maxLocals = argumentsSize;
623       currentLocals = argumentsSize;
624       // Create and visit the label for the first basic block.
625       firstBasicBlock = new Label();
626       visitLabel(firstBasicBlock);
627     }
628   }
629 
hasFrames()630   boolean hasFrames() {
631     return stackMapTableNumberOfEntries > 0;
632   }
633 
hasAsmInstructions()634   boolean hasAsmInstructions() {
635     return hasAsmInstructions;
636   }
637 
638   // -----------------------------------------------------------------------------------------------
639   // Implementation of the MethodVisitor abstract class
640   // -----------------------------------------------------------------------------------------------
641 
642   @Override
visitParameter(final String name, final int access)643   public void visitParameter(final String name, final int access) {
644     if (parameters == null) {
645       parameters = new ByteVector();
646     }
647     ++parametersCount;
648     parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access);
649   }
650 
651   @Override
visitAnnotationDefault()652   public AnnotationVisitor visitAnnotationDefault() {
653     defaultValue = new ByteVector();
654     return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null);
655   }
656 
657   @Override
visitAnnotation(final String descriptor, final boolean visible)658   public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
659     if (visible) {
660       return lastRuntimeVisibleAnnotation =
661           AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
662     } else {
663       return lastRuntimeInvisibleAnnotation =
664           AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
665     }
666   }
667 
668   @Override
visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)669   public AnnotationVisitor visitTypeAnnotation(
670       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
671     if (visible) {
672       return lastRuntimeVisibleTypeAnnotation =
673           AnnotationWriter.create(
674               symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
675     } else {
676       return lastRuntimeInvisibleTypeAnnotation =
677           AnnotationWriter.create(
678               symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
679     }
680   }
681 
682   @Override
visitAnnotableParameterCount(final int parameterCount, final boolean visible)683   public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
684     if (visible) {
685       visibleAnnotableParameterCount = parameterCount;
686     } else {
687       invisibleAnnotableParameterCount = parameterCount;
688     }
689   }
690 
691   @Override
visitParameterAnnotation( final int parameter, final String annotationDescriptor, final boolean visible)692   public AnnotationVisitor visitParameterAnnotation(
693       final int parameter, final String annotationDescriptor, final boolean visible) {
694     if (visible) {
695       if (lastRuntimeVisibleParameterAnnotations == null) {
696         lastRuntimeVisibleParameterAnnotations =
697             new AnnotationWriter[Type.getArgumentCount(descriptor)];
698       }
699       return lastRuntimeVisibleParameterAnnotations[parameter] =
700           AnnotationWriter.create(
701               symbolTable, annotationDescriptor, lastRuntimeVisibleParameterAnnotations[parameter]);
702     } else {
703       if (lastRuntimeInvisibleParameterAnnotations == null) {
704         lastRuntimeInvisibleParameterAnnotations =
705             new AnnotationWriter[Type.getArgumentCount(descriptor)];
706       }
707       return lastRuntimeInvisibleParameterAnnotations[parameter] =
708           AnnotationWriter.create(
709               symbolTable,
710               annotationDescriptor,
711               lastRuntimeInvisibleParameterAnnotations[parameter]);
712     }
713   }
714 
715   @Override
visitAttribute(final Attribute attribute)716   public void visitAttribute(final Attribute attribute) {
717     // Store the attributes in the <i>reverse</i> order of their visit by this method.
718     if (attribute.isCodeAttribute()) {
719       attribute.nextAttribute = firstCodeAttribute;
720       firstCodeAttribute = attribute;
721     } else {
722       attribute.nextAttribute = firstAttribute;
723       firstAttribute = attribute;
724     }
725   }
726 
727   @Override
visitCode()728   public void visitCode() {
729     // Nothing to do.
730   }
731 
732   @Override
visitFrame( final int type, final int numLocal, final Object[] local, final int numStack, final Object[] stack)733   public void visitFrame(
734       final int type,
735       final int numLocal,
736       final Object[] local,
737       final int numStack,
738       final Object[] stack) {
739     if (compute == COMPUTE_ALL_FRAMES) {
740       return;
741     }
742 
743     if (compute == COMPUTE_INSERTED_FRAMES) {
744       if (currentBasicBlock.frame == null) {
745         // This should happen only once, for the implicit first frame (which is explicitly visited
746         // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES
747         // can't be set if EXPAND_ASM_INSNS is not used).
748         currentBasicBlock.frame = new CurrentFrame(currentBasicBlock);
749         currentBasicBlock.frame.setInputFrameFromDescriptor(
750             symbolTable, accessFlags, descriptor, numLocal);
751         currentBasicBlock.frame.accept(this);
752       } else {
753         if (type == Opcodes.F_NEW) {
754           currentBasicBlock.frame.setInputFrameFromApiFormat(
755               symbolTable, numLocal, local, numStack, stack);
756         }
757         // If type is not F_NEW then it is F_INSERT by hypothesis, and currentBlock.frame contains
758         // the stack map frame at the current instruction, computed from the last F_NEW frame and
759         // the bytecode instructions in between (via calls to CurrentFrame#execute).
760         currentBasicBlock.frame.accept(this);
761       }
762     } else if (type == Opcodes.F_NEW) {
763       if (previousFrame == null) {
764         int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
765         Frame implicitFirstFrame = new Frame(new Label());
766         implicitFirstFrame.setInputFrameFromDescriptor(
767             symbolTable, accessFlags, descriptor, argumentsSize);
768         implicitFirstFrame.accept(this);
769       }
770       currentLocals = numLocal;
771       int frameIndex = visitFrameStart(code.length, numLocal, numStack);
772       for (int i = 0; i < numLocal; ++i) {
773         currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]);
774       }
775       for (int i = 0; i < numStack; ++i) {
776         currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]);
777       }
778       visitFrameEnd();
779     } else {
780       if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
781         throw new IllegalArgumentException("Class versions V1_5 or less must use F_NEW frames.");
782       }
783       int offsetDelta;
784       if (stackMapTableEntries == null) {
785         stackMapTableEntries = new ByteVector();
786         offsetDelta = code.length;
787       } else {
788         offsetDelta = code.length - previousFrameOffset - 1;
789         if (offsetDelta < 0) {
790           if (type == Opcodes.F_SAME) {
791             return;
792           } else {
793             throw new IllegalStateException();
794           }
795         }
796       }
797 
798       switch (type) {
799         case Opcodes.F_FULL:
800           currentLocals = numLocal;
801           stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
802           for (int i = 0; i < numLocal; ++i) {
803             putFrameType(local[i]);
804           }
805           stackMapTableEntries.putShort(numStack);
806           for (int i = 0; i < numStack; ++i) {
807             putFrameType(stack[i]);
808           }
809           break;
810         case Opcodes.F_APPEND:
811           currentLocals += numLocal;
812           stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + numLocal).putShort(offsetDelta);
813           for (int i = 0; i < numLocal; ++i) {
814             putFrameType(local[i]);
815           }
816           break;
817         case Opcodes.F_CHOP:
818           currentLocals -= numLocal;
819           stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - numLocal).putShort(offsetDelta);
820           break;
821         case Opcodes.F_SAME:
822           if (offsetDelta < 64) {
823             stackMapTableEntries.putByte(offsetDelta);
824           } else {
825             stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
826           }
827           break;
828         case Opcodes.F_SAME1:
829           if (offsetDelta < 64) {
830             stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
831           } else {
832             stackMapTableEntries
833                 .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
834                 .putShort(offsetDelta);
835           }
836           putFrameType(stack[0]);
837           break;
838         default:
839           throw new IllegalArgumentException();
840       }
841 
842       previousFrameOffset = code.length;
843       ++stackMapTableNumberOfEntries;
844     }
845 
846     if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
847       relativeStackSize = numStack;
848       for (int i = 0; i < numStack; ++i) {
849         if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
850           relativeStackSize++;
851         }
852       }
853       if (relativeStackSize > maxRelativeStackSize) {
854         maxRelativeStackSize = relativeStackSize;
855       }
856     }
857 
858     maxStack = Math.max(maxStack, numStack);
859     maxLocals = Math.max(maxLocals, currentLocals);
860   }
861 
862   @Override
visitInsn(final int opcode)863   public void visitInsn(final int opcode) {
864     lastBytecodeOffset = code.length;
865     // Add the instruction to the bytecode of the method.
866     code.putByte(opcode);
867     // If needed, update the maximum stack size and number of locals, and stack map frames.
868     if (currentBasicBlock != null) {
869       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
870         currentBasicBlock.frame.execute(opcode, 0, null, null);
871       } else {
872         int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
873         if (size > maxRelativeStackSize) {
874           maxRelativeStackSize = size;
875         }
876         relativeStackSize = size;
877       }
878       if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
879         endCurrentBasicBlockWithNoSuccessor();
880       }
881     }
882   }
883 
884   @Override
visitIntInsn(final int opcode, final int operand)885   public void visitIntInsn(final int opcode, final int operand) {
886     lastBytecodeOffset = code.length;
887     // Add the instruction to the bytecode of the method.
888     if (opcode == Opcodes.SIPUSH) {
889       code.put12(opcode, operand);
890     } else { // BIPUSH or NEWARRAY
891       code.put11(opcode, operand);
892     }
893     // If needed, update the maximum stack size and number of locals, and stack map frames.
894     if (currentBasicBlock != null) {
895       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
896         currentBasicBlock.frame.execute(opcode, operand, null, null);
897       } else if (opcode != Opcodes.NEWARRAY) {
898         // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY.
899         int size = relativeStackSize + 1;
900         if (size > maxRelativeStackSize) {
901           maxRelativeStackSize = size;
902         }
903         relativeStackSize = size;
904       }
905     }
906   }
907 
908   @Override
visitVarInsn(final int opcode, final int varIndex)909   public void visitVarInsn(final int opcode, final int varIndex) {
910     lastBytecodeOffset = code.length;
911     // Add the instruction to the bytecode of the method.
912     if (varIndex < 4 && opcode != Opcodes.RET) {
913       int optimizedOpcode;
914       if (opcode < Opcodes.ISTORE) {
915         optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + varIndex;
916       } else {
917         optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + varIndex;
918       }
919       code.putByte(optimizedOpcode);
920     } else if (varIndex >= 256) {
921       code.putByte(Constants.WIDE).put12(opcode, varIndex);
922     } else {
923       code.put11(opcode, varIndex);
924     }
925     // If needed, update the maximum stack size and number of locals, and stack map frames.
926     if (currentBasicBlock != null) {
927       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
928         currentBasicBlock.frame.execute(opcode, varIndex, null, null);
929       } else {
930         if (opcode == Opcodes.RET) {
931           // No stack size delta.
932           currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END;
933           currentBasicBlock.outputStackSize = (short) relativeStackSize;
934           endCurrentBasicBlockWithNoSuccessor();
935         } else { // xLOAD or xSTORE
936           int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
937           if (size > maxRelativeStackSize) {
938             maxRelativeStackSize = size;
939           }
940           relativeStackSize = size;
941         }
942       }
943     }
944     if (compute != COMPUTE_NOTHING) {
945       int currentMaxLocals;
946       if (opcode == Opcodes.LLOAD
947           || opcode == Opcodes.DLOAD
948           || opcode == Opcodes.LSTORE
949           || opcode == Opcodes.DSTORE) {
950         currentMaxLocals = varIndex + 2;
951       } else {
952         currentMaxLocals = varIndex + 1;
953       }
954       if (currentMaxLocals > maxLocals) {
955         maxLocals = currentMaxLocals;
956       }
957     }
958     if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) {
959       // If there are exception handler blocks, each instruction within a handler range is, in
960       // theory, a basic block (since execution can jump from this instruction to the exception
961       // handler). As a consequence, the local variable types at the beginning of the handler
962       // block should be the merge of the local variable types at all the instructions within the
963       // handler range. However, instead of creating a basic block for each instruction, we can
964       // get the same result in a more efficient way. Namely, by starting a new basic block after
965       // each xSTORE instruction, which is what we do here.
966       visitLabel(new Label());
967     }
968   }
969 
970   @Override
visitTypeInsn(final int opcode, final String type)971   public void visitTypeInsn(final int opcode, final String type) {
972     lastBytecodeOffset = code.length;
973     // Add the instruction to the bytecode of the method.
974     Symbol typeSymbol = symbolTable.addConstantClass(type);
975     code.put12(opcode, typeSymbol.index);
976     // If needed, update the maximum stack size and number of locals, and stack map frames.
977     if (currentBasicBlock != null) {
978       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
979         currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable);
980       } else if (opcode == Opcodes.NEW) {
981         // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF.
982         int size = relativeStackSize + 1;
983         if (size > maxRelativeStackSize) {
984           maxRelativeStackSize = size;
985         }
986         relativeStackSize = size;
987       }
988     }
989   }
990 
991   @Override
visitFieldInsn( final int opcode, final String owner, final String name, final String descriptor)992   public void visitFieldInsn(
993       final int opcode, final String owner, final String name, final String descriptor) {
994     lastBytecodeOffset = code.length;
995     // Add the instruction to the bytecode of the method.
996     Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor);
997     code.put12(opcode, fieldrefSymbol.index);
998     // If needed, update the maximum stack size and number of locals, and stack map frames.
999     if (currentBasicBlock != null) {
1000       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1001         currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable);
1002       } else {
1003         int size;
1004         char firstDescChar = descriptor.charAt(0);
1005         switch (opcode) {
1006           case Opcodes.GETSTATIC:
1007             size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1);
1008             break;
1009           case Opcodes.PUTSTATIC:
1010             size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1);
1011             break;
1012           case Opcodes.GETFIELD:
1013             size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0);
1014             break;
1015           case Opcodes.PUTFIELD:
1016           default:
1017             size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2);
1018             break;
1019         }
1020         if (size > maxRelativeStackSize) {
1021           maxRelativeStackSize = size;
1022         }
1023         relativeStackSize = size;
1024       }
1025     }
1026   }
1027 
1028   @Override
visitMethodInsn( final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface)1029   public void visitMethodInsn(
1030       final int opcode,
1031       final String owner,
1032       final String name,
1033       final String descriptor,
1034       final boolean isInterface) {
1035     lastBytecodeOffset = code.length;
1036     // Add the instruction to the bytecode of the method.
1037     Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface);
1038     if (opcode == Opcodes.INVOKEINTERFACE) {
1039       code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index)
1040           .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0);
1041     } else {
1042       code.put12(opcode, methodrefSymbol.index);
1043     }
1044     // If needed, update the maximum stack size and number of locals, and stack map frames.
1045     if (currentBasicBlock != null) {
1046       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1047         currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable);
1048       } else {
1049         int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes();
1050         int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2);
1051         int size;
1052         if (opcode == Opcodes.INVOKESTATIC) {
1053           size = relativeStackSize + stackSizeDelta + 1;
1054         } else {
1055           size = relativeStackSize + stackSizeDelta;
1056         }
1057         if (size > maxRelativeStackSize) {
1058           maxRelativeStackSize = size;
1059         }
1060         relativeStackSize = size;
1061       }
1062     }
1063   }
1064 
1065   @Override
visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)1066   public void visitInvokeDynamicInsn(
1067       final String name,
1068       final String descriptor,
1069       final Handle bootstrapMethodHandle,
1070       final Object... bootstrapMethodArguments) {
1071     lastBytecodeOffset = code.length;
1072     // Add the instruction to the bytecode of the method.
1073     Symbol invokeDynamicSymbol =
1074         symbolTable.addConstantInvokeDynamic(
1075             name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
1076     code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index);
1077     code.putShort(0);
1078     // If needed, update the maximum stack size and number of locals, and stack map frames.
1079     if (currentBasicBlock != null) {
1080       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1081         currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable);
1082       } else {
1083         int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes();
1084         int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1;
1085         int size = relativeStackSize + stackSizeDelta;
1086         if (size > maxRelativeStackSize) {
1087           maxRelativeStackSize = size;
1088         }
1089         relativeStackSize = size;
1090       }
1091     }
1092   }
1093 
1094   @Override
visitJumpInsn(final int opcode, final Label label)1095   public void visitJumpInsn(final int opcode, final Label label) {
1096     lastBytecodeOffset = code.length;
1097     // Add the instruction to the bytecode of the method.
1098     // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode.
1099     int baseOpcode =
1100         opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode;
1101     boolean nextInsnIsJumpTarget = false;
1102     if ((label.flags & Label.FLAG_RESOLVED) != 0
1103         && label.bytecodeOffset - code.length < Short.MIN_VALUE) {
1104       // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO
1105       // with GOTO_W, JSR with JSR_W and IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., where
1106       // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where <L> designates
1107       // the instruction just after the GOTO_W.
1108       if (baseOpcode == Opcodes.GOTO) {
1109         code.putByte(Constants.GOTO_W);
1110       } else if (baseOpcode == Opcodes.JSR) {
1111         code.putByte(Constants.JSR_W);
1112       } else {
1113         // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least
1114         // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a
1115         // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W).
1116         code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1);
1117         code.putShort(8);
1118         // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this
1119         // method or another one, and if the class has frames, we will need to insert a frame after
1120         // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM
1121         // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W
1122         // here, which has the unfortunate effect of forcing this additional round trip (which in
1123         // some case would not have been really necessary, but we can't know this at this point).
1124         code.putByte(Constants.ASM_GOTO_W);
1125         hasAsmInstructions = true;
1126         // The instruction after the GOTO_W becomes the target of the IFNOT instruction.
1127         nextInsnIsJumpTarget = true;
1128       }
1129       label.put(code, code.length - 1, true);
1130     } else if (baseOpcode != opcode) {
1131       // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove
1132       // ASM specific instructions). In this case we keep the original instruction.
1133       code.putByte(opcode);
1134       label.put(code, code.length - 1, true);
1135     } else {
1136       // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these
1137       // cases we store the offset in 2 bytes (which will be increased via a ClassReader ->
1138       // ClassWriter round trip if it turns out that 2 bytes are not sufficient).
1139       code.putByte(baseOpcode);
1140       label.put(code, code.length - 1, false);
1141     }
1142 
1143     // If needed, update the maximum stack size and number of locals, and stack map frames.
1144     if (currentBasicBlock != null) {
1145       Label nextBasicBlock = null;
1146       if (compute == COMPUTE_ALL_FRAMES) {
1147         currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
1148         // Record the fact that 'label' is the target of a jump instruction.
1149         label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1150         // Add 'label' as a successor of the current basic block.
1151         addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1152         if (baseOpcode != Opcodes.GOTO) {
1153           // The next instruction starts a new basic block (except for GOTO: by default the code
1154           // following a goto is unreachable - unless there is an explicit label for it - and we
1155           // should not compute stack frame types for its instructions).
1156           nextBasicBlock = new Label();
1157         }
1158       } else if (compute == COMPUTE_INSERTED_FRAMES) {
1159         currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
1160       } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
1161         // No need to update maxRelativeStackSize (the stack size delta is always negative).
1162         relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
1163       } else {
1164         if (baseOpcode == Opcodes.JSR) {
1165           // Record the fact that 'label' designates a subroutine, if not already done.
1166           if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) {
1167             label.flags |= Label.FLAG_SUBROUTINE_START;
1168             hasSubroutines = true;
1169           }
1170           currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER;
1171           // Note that, by construction in this method, a block which calls a subroutine has at
1172           // least two successors in the control flow graph: the first one (added below) leads to
1173           // the instruction after the JSR, while the second one (added here) leads to the JSR
1174           // target. Note that the first successor is virtual (it does not correspond to a possible
1175           // execution path): it is only used to compute the successors of the basic blocks ending
1176           // with a ret, in {@link Label#addSubroutineRetSuccessors}.
1177           addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label);
1178           // The instruction after the JSR starts a new basic block.
1179           nextBasicBlock = new Label();
1180         } else {
1181           // No need to update maxRelativeStackSize (the stack size delta is always negative).
1182           relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
1183           addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1184         }
1185       }
1186       // If the next instruction starts a new basic block, call visitLabel to add the label of this
1187       // instruction as a successor of the current block, and to start a new basic block.
1188       if (nextBasicBlock != null) {
1189         if (nextInsnIsJumpTarget) {
1190           nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET;
1191         }
1192         visitLabel(nextBasicBlock);
1193       }
1194       if (baseOpcode == Opcodes.GOTO) {
1195         endCurrentBasicBlockWithNoSuccessor();
1196       }
1197     }
1198   }
1199 
1200   @Override
visitLabel(final Label label)1201   public void visitLabel(final Label label) {
1202     // Resolve the forward references to this label, if any.
1203     hasAsmInstructions |= label.resolve(code.data, stackMapTableEntries, code.length);
1204     // visitLabel starts a new basic block (except for debug only labels), so we need to update the
1205     // previous and current block references and list of successors.
1206     if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) {
1207       return;
1208     }
1209     if (compute == COMPUTE_ALL_FRAMES) {
1210       if (currentBasicBlock != null) {
1211         if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) {
1212           // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only
1213           // one place, but this does not work for labels which have not been visited yet.
1214           // Therefore, when we detect here two labels having the same bytecode offset, we need to
1215           // - consolidate the state scattered in these two instances into the canonical instance:
1216           currentBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET);
1217           // - make sure the two instances share the same Frame instance (the implementation of
1218           // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be
1219           // null):
1220           label.frame = currentBasicBlock.frame;
1221           // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so
1222           // that they still refer to the canonical instance for this bytecode offset.
1223           return;
1224         }
1225         // End the current basic block (with one new successor).
1226         addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1227       }
1228       // Append 'label' at the end of the basic block list.
1229       if (lastBasicBlock != null) {
1230         if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) {
1231           // Same comment as above.
1232           lastBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET);
1233           // Here label.frame should be null.
1234           label.frame = lastBasicBlock.frame;
1235           currentBasicBlock = lastBasicBlock;
1236           return;
1237         }
1238         lastBasicBlock.nextBasicBlock = label;
1239       }
1240       lastBasicBlock = label;
1241       // Make it the new current basic block.
1242       currentBasicBlock = label;
1243       // Here label.frame should be null.
1244       label.frame = new Frame(label);
1245     } else if (compute == COMPUTE_INSERTED_FRAMES) {
1246       if (currentBasicBlock == null) {
1247         // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
1248         // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged.
1249         currentBasicBlock = label;
1250       } else {
1251         // Update the frame owner so that a correct frame offset is computed in Frame.accept().
1252         currentBasicBlock.frame.owner = label;
1253       }
1254     } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1255       if (currentBasicBlock != null) {
1256         // End the current basic block (with one new successor).
1257         currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
1258         addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1259       }
1260       // Start a new current basic block, and reset the current and maximum relative stack sizes.
1261       currentBasicBlock = label;
1262       relativeStackSize = 0;
1263       maxRelativeStackSize = 0;
1264       // Append the new basic block at the end of the basic block list.
1265       if (lastBasicBlock != null) {
1266         lastBasicBlock.nextBasicBlock = label;
1267       }
1268       lastBasicBlock = label;
1269     } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES && currentBasicBlock == null) {
1270       // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
1271       // compute is equal to COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES, currentBasicBlock stays
1272       // unchanged.
1273       currentBasicBlock = label;
1274     }
1275   }
1276 
1277   @Override
visitLdcInsn(final Object value)1278   public void visitLdcInsn(final Object value) {
1279     lastBytecodeOffset = code.length;
1280     // Add the instruction to the bytecode of the method.
1281     Symbol constantSymbol = symbolTable.addConstant(value);
1282     int constantIndex = constantSymbol.index;
1283     char firstDescriptorChar;
1284     boolean isLongOrDouble =
1285         constantSymbol.tag == Symbol.CONSTANT_LONG_TAG
1286             || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG
1287             || (constantSymbol.tag == Symbol.CONSTANT_DYNAMIC_TAG
1288                 && ((firstDescriptorChar = constantSymbol.value.charAt(0)) == 'J'
1289                     || firstDescriptorChar == 'D'));
1290     if (isLongOrDouble) {
1291       code.put12(Constants.LDC2_W, constantIndex);
1292     } else if (constantIndex >= 256) {
1293       code.put12(Constants.LDC_W, constantIndex);
1294     } else {
1295       code.put11(Opcodes.LDC, constantIndex);
1296     }
1297     // If needed, update the maximum stack size and number of locals, and stack map frames.
1298     if (currentBasicBlock != null) {
1299       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1300         currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable);
1301       } else {
1302         int size = relativeStackSize + (isLongOrDouble ? 2 : 1);
1303         if (size > maxRelativeStackSize) {
1304           maxRelativeStackSize = size;
1305         }
1306         relativeStackSize = size;
1307       }
1308     }
1309   }
1310 
1311   @Override
visitIincInsn(final int varIndex, final int increment)1312   public void visitIincInsn(final int varIndex, final int increment) {
1313     lastBytecodeOffset = code.length;
1314     // Add the instruction to the bytecode of the method.
1315     if ((varIndex > 255) || (increment > 127) || (increment < -128)) {
1316       code.putByte(Constants.WIDE).put12(Opcodes.IINC, varIndex).putShort(increment);
1317     } else {
1318       code.putByte(Opcodes.IINC).put11(varIndex, increment);
1319     }
1320     // If needed, update the maximum stack size and number of locals, and stack map frames.
1321     if (currentBasicBlock != null
1322         && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) {
1323       currentBasicBlock.frame.execute(Opcodes.IINC, varIndex, null, null);
1324     }
1325     if (compute != COMPUTE_NOTHING) {
1326       int currentMaxLocals = varIndex + 1;
1327       if (currentMaxLocals > maxLocals) {
1328         maxLocals = currentMaxLocals;
1329       }
1330     }
1331   }
1332 
1333   @Override
visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label... labels)1334   public void visitTableSwitchInsn(
1335       final int min, final int max, final Label dflt, final Label... labels) {
1336     lastBytecodeOffset = code.length;
1337     // Add the instruction to the bytecode of the method.
1338     code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
1339     dflt.put(code, lastBytecodeOffset, true);
1340     code.putInt(min).putInt(max);
1341     for (Label label : labels) {
1342       label.put(code, lastBytecodeOffset, true);
1343     }
1344     // If needed, update the maximum stack size and number of locals, and stack map frames.
1345     visitSwitchInsn(dflt, labels);
1346   }
1347 
1348   @Override
visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)1349   public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
1350     lastBytecodeOffset = code.length;
1351     // Add the instruction to the bytecode of the method.
1352     code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
1353     dflt.put(code, lastBytecodeOffset, true);
1354     code.putInt(labels.length);
1355     for (int i = 0; i < labels.length; ++i) {
1356       code.putInt(keys[i]);
1357       labels[i].put(code, lastBytecodeOffset, true);
1358     }
1359     // If needed, update the maximum stack size and number of locals, and stack map frames.
1360     visitSwitchInsn(dflt, labels);
1361   }
1362 
visitSwitchInsn(final Label dflt, final Label[] labels)1363   private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1364     if (currentBasicBlock != null) {
1365       if (compute == COMPUTE_ALL_FRAMES) {
1366         currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1367         // Add all the labels as successors of the current basic block.
1368         addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt);
1369         dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1370         for (Label label : labels) {
1371           addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
1372           label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
1373         }
1374       } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1375         // No need to update maxRelativeStackSize (the stack size delta is always negative).
1376         --relativeStackSize;
1377         // Add all the labels as successors of the current basic block.
1378         addSuccessorToCurrentBasicBlock(relativeStackSize, dflt);
1379         for (Label label : labels) {
1380           addSuccessorToCurrentBasicBlock(relativeStackSize, label);
1381         }
1382       }
1383       // End the current basic block.
1384       endCurrentBasicBlockWithNoSuccessor();
1385     }
1386   }
1387 
1388   @Override
visitMultiANewArrayInsn(final String descriptor, final int numDimensions)1389   public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
1390     lastBytecodeOffset = code.length;
1391     // Add the instruction to the bytecode of the method.
1392     Symbol descSymbol = symbolTable.addConstantClass(descriptor);
1393     code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions);
1394     // If needed, update the maximum stack size and number of locals, and stack map frames.
1395     if (currentBasicBlock != null) {
1396       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
1397         currentBasicBlock.frame.execute(
1398             Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable);
1399       } else {
1400         // No need to update maxRelativeStackSize (the stack size delta is always negative).
1401         relativeStackSize += 1 - numDimensions;
1402       }
1403     }
1404   }
1405 
1406   @Override
visitInsnAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1407   public AnnotationVisitor visitInsnAnnotation(
1408       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1409     if (visible) {
1410       return lastCodeRuntimeVisibleTypeAnnotation =
1411           AnnotationWriter.create(
1412               symbolTable,
1413               (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
1414               typePath,
1415               descriptor,
1416               lastCodeRuntimeVisibleTypeAnnotation);
1417     } else {
1418       return lastCodeRuntimeInvisibleTypeAnnotation =
1419           AnnotationWriter.create(
1420               symbolTable,
1421               (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
1422               typePath,
1423               descriptor,
1424               lastCodeRuntimeInvisibleTypeAnnotation);
1425     }
1426   }
1427 
1428   @Override
visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type)1429   public void visitTryCatchBlock(
1430       final Label start, final Label end, final Label handler, final String type) {
1431     Handler newHandler =
1432         new Handler(
1433             start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type);
1434     if (firstHandler == null) {
1435       firstHandler = newHandler;
1436     } else {
1437       lastHandler.nextHandler = newHandler;
1438     }
1439     lastHandler = newHandler;
1440   }
1441 
1442   @Override
visitTryCatchAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1443   public AnnotationVisitor visitTryCatchAnnotation(
1444       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1445     if (visible) {
1446       return lastCodeRuntimeVisibleTypeAnnotation =
1447           AnnotationWriter.create(
1448               symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeVisibleTypeAnnotation);
1449     } else {
1450       return lastCodeRuntimeInvisibleTypeAnnotation =
1451           AnnotationWriter.create(
1452               symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeInvisibleTypeAnnotation);
1453     }
1454   }
1455 
1456   @Override
visitLocalVariable( final String name, final String descriptor, final String signature, final Label start, final Label end, final int index)1457   public void visitLocalVariable(
1458       final String name,
1459       final String descriptor,
1460       final String signature,
1461       final Label start,
1462       final Label end,
1463       final int index) {
1464     if (signature != null) {
1465       if (localVariableTypeTable == null) {
1466         localVariableTypeTable = new ByteVector();
1467       }
1468       ++localVariableTypeTableLength;
1469       localVariableTypeTable
1470           .putShort(start.bytecodeOffset)
1471           .putShort(end.bytecodeOffset - start.bytecodeOffset)
1472           .putShort(symbolTable.addConstantUtf8(name))
1473           .putShort(symbolTable.addConstantUtf8(signature))
1474           .putShort(index);
1475     }
1476     if (localVariableTable == null) {
1477       localVariableTable = new ByteVector();
1478     }
1479     ++localVariableTableLength;
1480     localVariableTable
1481         .putShort(start.bytecodeOffset)
1482         .putShort(end.bytecodeOffset - start.bytecodeOffset)
1483         .putShort(symbolTable.addConstantUtf8(name))
1484         .putShort(symbolTable.addConstantUtf8(descriptor))
1485         .putShort(index);
1486     if (compute != COMPUTE_NOTHING) {
1487       char firstDescChar = descriptor.charAt(0);
1488       int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1);
1489       if (currentMaxLocals > maxLocals) {
1490         maxLocals = currentMaxLocals;
1491       }
1492     }
1493   }
1494 
1495   @Override
visitLocalVariableAnnotation( final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, final int[] index, final String descriptor, final boolean visible)1496   public AnnotationVisitor visitLocalVariableAnnotation(
1497       final int typeRef,
1498       final TypePath typePath,
1499       final Label[] start,
1500       final Label[] end,
1501       final int[] index,
1502       final String descriptor,
1503       final boolean visible) {
1504     // Create a ByteVector to hold a 'type_annotation' JVMS structure.
1505     // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
1506     ByteVector typeAnnotation = new ByteVector();
1507     // Write target_type, target_info, and target_path.
1508     typeAnnotation.putByte(typeRef >>> 24).putShort(start.length);
1509     for (int i = 0; i < start.length; ++i) {
1510       typeAnnotation
1511           .putShort(start[i].bytecodeOffset)
1512           .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset)
1513           .putShort(index[i]);
1514     }
1515     TypePath.put(typePath, typeAnnotation);
1516     // Write type_index and reserve space for num_element_value_pairs.
1517     typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
1518     if (visible) {
1519       return lastCodeRuntimeVisibleTypeAnnotation =
1520           new AnnotationWriter(
1521               symbolTable,
1522               /* useNamedValues = */ true,
1523               typeAnnotation,
1524               lastCodeRuntimeVisibleTypeAnnotation);
1525     } else {
1526       return lastCodeRuntimeInvisibleTypeAnnotation =
1527           new AnnotationWriter(
1528               symbolTable,
1529               /* useNamedValues = */ true,
1530               typeAnnotation,
1531               lastCodeRuntimeInvisibleTypeAnnotation);
1532     }
1533   }
1534 
1535   @Override
visitLineNumber(final int line, final Label start)1536   public void visitLineNumber(final int line, final Label start) {
1537     if (lineNumberTable == null) {
1538       lineNumberTable = new ByteVector();
1539     }
1540     ++lineNumberTableLength;
1541     lineNumberTable.putShort(start.bytecodeOffset);
1542     lineNumberTable.putShort(line);
1543   }
1544 
1545   @Override
visitMaxs(final int maxStack, final int maxLocals)1546   public void visitMaxs(final int maxStack, final int maxLocals) {
1547     if (compute == COMPUTE_ALL_FRAMES) {
1548       computeAllFrames();
1549     } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1550       computeMaxStackAndLocal();
1551     } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
1552       this.maxStack = maxRelativeStackSize;
1553     } else {
1554       this.maxStack = maxStack;
1555       this.maxLocals = maxLocals;
1556     }
1557   }
1558 
1559   /** Computes all the stack map frames of the method, from scratch. */
computeAllFrames()1560   private void computeAllFrames() {
1561     // Complete the control flow graph with exception handler blocks.
1562     Handler handler = firstHandler;
1563     while (handler != null) {
1564       String catchTypeDescriptor =
1565           handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor;
1566       int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor);
1567       // Mark handlerBlock as an exception handler.
1568       Label handlerBlock = handler.handlerPc.getCanonicalInstance();
1569       handlerBlock.flags |= Label.FLAG_JUMP_TARGET;
1570       // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
1571       Label handlerRangeBlock = handler.startPc.getCanonicalInstance();
1572       Label handlerRangeEnd = handler.endPc.getCanonicalInstance();
1573       while (handlerRangeBlock != handlerRangeEnd) {
1574         handlerRangeBlock.outgoingEdges =
1575             new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges);
1576         handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
1577       }
1578       handler = handler.nextHandler;
1579     }
1580 
1581     // Create and visit the first (implicit) frame.
1582     Frame firstFrame = firstBasicBlock.frame;
1583     firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals);
1584     firstFrame.accept(this);
1585 
1586     // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks
1587     // whose stack map frame has changed) and, while there are blocks to process, remove one from
1588     // the list and update the stack map frames of its successor blocks in the control flow graph
1589     // (which might change them, in which case these blocks must be processed too, and are thus
1590     // added to the list of blocks to process). Also compute the maximum stack size of the method,
1591     // as a by-product.
1592     Label listOfBlocksToProcess = firstBasicBlock;
1593     listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
1594     int maxStackSize = 0;
1595     while (listOfBlocksToProcess != Label.EMPTY_LIST) {
1596       // Remove a basic block from the list of blocks to process.
1597       Label basicBlock = listOfBlocksToProcess;
1598       listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
1599       basicBlock.nextListElement = null;
1600       // By definition, basicBlock is reachable.
1601       basicBlock.flags |= Label.FLAG_REACHABLE;
1602       // Update the (absolute) maximum stack size.
1603       int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax;
1604       if (maxBlockStackSize > maxStackSize) {
1605         maxStackSize = maxBlockStackSize;
1606       }
1607       // Update the successor blocks of basicBlock in the control flow graph.
1608       Edge outgoingEdge = basicBlock.outgoingEdges;
1609       while (outgoingEdge != null) {
1610         Label successorBlock = outgoingEdge.successor.getCanonicalInstance();
1611         boolean successorBlockChanged =
1612             basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info);
1613         if (successorBlockChanged && successorBlock.nextListElement == null) {
1614           // If successorBlock has changed it must be processed. Thus, if it is not already in the
1615           // list of blocks to process, add it to this list.
1616           successorBlock.nextListElement = listOfBlocksToProcess;
1617           listOfBlocksToProcess = successorBlock;
1618         }
1619         outgoingEdge = outgoingEdge.nextEdge;
1620       }
1621     }
1622 
1623     // Loop over all the basic blocks and visit the stack map frames that must be stored in the
1624     // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from
1625     // exception handler ranges.
1626     Label basicBlock = firstBasicBlock;
1627     while (basicBlock != null) {
1628       if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE))
1629           == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) {
1630         basicBlock.frame.accept(this);
1631       }
1632       if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) {
1633         // Find the start and end bytecode offsets of this unreachable block.
1634         Label nextBasicBlock = basicBlock.nextBasicBlock;
1635         int startOffset = basicBlock.bytecodeOffset;
1636         int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1;
1637         if (endOffset >= startOffset) {
1638           // Replace its instructions with NOP ... NOP ATHROW.
1639           for (int i = startOffset; i < endOffset; ++i) {
1640             code.data[i] = Opcodes.NOP;
1641           }
1642           code.data[endOffset] = (byte) Opcodes.ATHROW;
1643           // Emit a frame for this unreachable block, with no local and a Throwable on the stack
1644           // (so that the ATHROW could consume this Throwable if it were reachable).
1645           int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
1646           currentFrame[frameIndex] =
1647               Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
1648           visitFrameEnd();
1649           // Remove this unreachable basic block from the exception handler ranges.
1650           firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock);
1651           // The maximum stack size is now at least one, because of the Throwable declared above.
1652           maxStackSize = Math.max(maxStackSize, 1);
1653         }
1654       }
1655       basicBlock = basicBlock.nextBasicBlock;
1656     }
1657 
1658     this.maxStack = maxStackSize;
1659   }
1660 
1661   /** Computes the maximum stack size of the method. */
computeMaxStackAndLocal()1662   private void computeMaxStackAndLocal() {
1663     // Complete the control flow graph with exception handler blocks.
1664     Handler handler = firstHandler;
1665     while (handler != null) {
1666       Label handlerBlock = handler.handlerPc;
1667       Label handlerRangeBlock = handler.startPc;
1668       Label handlerRangeEnd = handler.endPc;
1669       // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
1670       while (handlerRangeBlock != handlerRangeEnd) {
1671         if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) {
1672           handlerRangeBlock.outgoingEdges =
1673               new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges);
1674         } else {
1675           // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing
1676           // edges to preserve the hypothesis about JSR block successors order (see
1677           // {@link #visitJumpInsn}).
1678           handlerRangeBlock.outgoingEdges.nextEdge.nextEdge =
1679               new Edge(
1680                   Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge);
1681         }
1682         handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
1683       }
1684       handler = handler.nextHandler;
1685     }
1686 
1687     // Complete the control flow graph with the successor blocks of subroutines, if needed.
1688     if (hasSubroutines) {
1689       // First step: find the subroutines. This step determines, for each basic block, to which
1690       // subroutine(s) it belongs. Start with the main "subroutine":
1691       short numSubroutines = 1;
1692       firstBasicBlock.markSubroutine(numSubroutines);
1693       // Then, mark the subroutines called by the main subroutine, then the subroutines called by
1694       // those called by the main subroutine, etc.
1695       for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) {
1696         Label basicBlock = firstBasicBlock;
1697         while (basicBlock != null) {
1698           if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0
1699               && basicBlock.subroutineId == currentSubroutine) {
1700             Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor;
1701             if (jsrTarget.subroutineId == 0) {
1702               // If this subroutine has not been marked yet, find its basic blocks.
1703               jsrTarget.markSubroutine(++numSubroutines);
1704             }
1705           }
1706           basicBlock = basicBlock.nextBasicBlock;
1707         }
1708       }
1709       // Second step: find the successors in the control flow graph of each subroutine basic block
1710       // 'r' ending with a RET instruction. These successors are the virtual successors of the basic
1711       // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'.
1712       Label basicBlock = firstBasicBlock;
1713       while (basicBlock != null) {
1714         if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
1715           // By construction, jsr targets are stored in the second outgoing edge of basic blocks
1716           // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}).
1717           Label subroutine = basicBlock.outgoingEdges.nextEdge.successor;
1718           subroutine.addSubroutineRetSuccessors(basicBlock);
1719         }
1720         basicBlock = basicBlock.nextBasicBlock;
1721       }
1722     }
1723 
1724     // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks
1725     // whose input stack size has changed) and, while there are blocks to process, remove one
1726     // from the list, update the input stack size of its successor blocks in the control flow
1727     // graph, and add these blocks to the list of blocks to process (if not already done).
1728     Label listOfBlocksToProcess = firstBasicBlock;
1729     listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
1730     int maxStackSize = maxStack;
1731     while (listOfBlocksToProcess != Label.EMPTY_LIST) {
1732       // Remove a basic block from the list of blocks to process. Note that we don't reset
1733       // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already
1734       // processed basic blocks.
1735       Label basicBlock = listOfBlocksToProcess;
1736       listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
1737       // Compute the (absolute) input stack size and maximum stack size of this block.
1738       int inputStackTop = basicBlock.inputStackSize;
1739       int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax;
1740       // Update the absolute maximum stack size of the method.
1741       if (maxBlockStackSize > maxStackSize) {
1742         maxStackSize = maxBlockStackSize;
1743       }
1744       // Update the input stack size of the successor blocks of basicBlock in the control flow
1745       // graph, and add these blocks to the list of blocks to process, if not already done.
1746       Edge outgoingEdge = basicBlock.outgoingEdges;
1747       if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
1748         // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual
1749         // edges which lead to the instruction just after the jsr, and do not correspond to a
1750         // possible execution path (see {@link #visitJumpInsn} and
1751         // {@link Label#FLAG_SUBROUTINE_CALLER}).
1752         outgoingEdge = outgoingEdge.nextEdge;
1753       }
1754       while (outgoingEdge != null) {
1755         Label successorBlock = outgoingEdge.successor;
1756         if (successorBlock.nextListElement == null) {
1757           successorBlock.inputStackSize =
1758               (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info);
1759           successorBlock.nextListElement = listOfBlocksToProcess;
1760           listOfBlocksToProcess = successorBlock;
1761         }
1762         outgoingEdge = outgoingEdge.nextEdge;
1763       }
1764     }
1765     this.maxStack = maxStackSize;
1766   }
1767 
1768   @Override
visitEnd()1769   public void visitEnd() {
1770     // Nothing to do.
1771   }
1772 
1773   // -----------------------------------------------------------------------------------------------
1774   // Utility methods: control flow analysis algorithm
1775   // -----------------------------------------------------------------------------------------------
1776 
1777   /**
1778    * Adds a successor to {@link #currentBasicBlock} in the control flow graph.
1779    *
1780    * @param info information about the control flow edge to be added.
1781    * @param successor the successor block to be added to the current basic block.
1782    */
addSuccessorToCurrentBasicBlock(final int info, final Label successor)1783   private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) {
1784     currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges);
1785   }
1786 
1787   /**
1788    * Ends the current basic block. This method must be used in the case where the current basic
1789    * block does not have any successor.
1790    *
1791    * <p>WARNING: this method must be called after the currently visited instruction has been put in
1792    * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic
1793    * block after the current instruction).
1794    */
endCurrentBasicBlockWithNoSuccessor()1795   private void endCurrentBasicBlockWithNoSuccessor() {
1796     if (compute == COMPUTE_ALL_FRAMES) {
1797       Label nextBasicBlock = new Label();
1798       nextBasicBlock.frame = new Frame(nextBasicBlock);
1799       nextBasicBlock.resolve(code.data, stackMapTableEntries, code.length);
1800       lastBasicBlock.nextBasicBlock = nextBasicBlock;
1801       lastBasicBlock = nextBasicBlock;
1802       currentBasicBlock = null;
1803     } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
1804       currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
1805       currentBasicBlock = null;
1806     }
1807   }
1808 
1809   // -----------------------------------------------------------------------------------------------
1810   // Utility methods: stack map frames
1811   // -----------------------------------------------------------------------------------------------
1812 
1813   /**
1814    * Starts the visit of a new stack map frame, stored in {@link #currentFrame}.
1815    *
1816    * @param offset the bytecode offset of the instruction to which the frame corresponds.
1817    * @param numLocal the number of local variables in the frame.
1818    * @param numStack the number of stack elements in the frame.
1819    * @return the index of the next element to be written in this frame.
1820    */
visitFrameStart(final int offset, final int numLocal, final int numStack)1821   int visitFrameStart(final int offset, final int numLocal, final int numStack) {
1822     int frameLength = 3 + numLocal + numStack;
1823     if (currentFrame == null || currentFrame.length < frameLength) {
1824       currentFrame = new int[frameLength];
1825     }
1826     currentFrame[0] = offset;
1827     currentFrame[1] = numLocal;
1828     currentFrame[2] = numStack;
1829     return 3;
1830   }
1831 
1832   /**
1833    * Sets an abstract type in {@link #currentFrame}.
1834    *
1835    * @param frameIndex the index of the element to be set in {@link #currentFrame}.
1836    * @param abstractType an abstract type.
1837    */
visitAbstractType(final int frameIndex, final int abstractType)1838   void visitAbstractType(final int frameIndex, final int abstractType) {
1839     currentFrame[frameIndex] = abstractType;
1840   }
1841 
1842   /**
1843    * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by
1844    * updating the StackMapTable number_of_entries (except if the current frame is the first one,
1845    * which is implicit in StackMapTable). Then resets {@link #currentFrame} to {@literal null}.
1846    */
visitFrameEnd()1847   void visitFrameEnd() {
1848     if (previousFrame != null) {
1849       if (stackMapTableEntries == null) {
1850         stackMapTableEntries = new ByteVector();
1851       }
1852       putFrame();
1853       ++stackMapTableNumberOfEntries;
1854     }
1855     previousFrame = currentFrame;
1856     currentFrame = null;
1857   }
1858 
1859   /** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */
putFrame()1860   private void putFrame() {
1861     final int numLocal = currentFrame[1];
1862     final int numStack = currentFrame[2];
1863     if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
1864       // Generate a StackMap attribute entry, which are always uncompressed.
1865       stackMapTableEntries.putShort(currentFrame[0]).putShort(numLocal);
1866       putAbstractTypes(3, 3 + numLocal);
1867       stackMapTableEntries.putShort(numStack);
1868       putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
1869       return;
1870     }
1871     final int offsetDelta =
1872         stackMapTableNumberOfEntries == 0
1873             ? currentFrame[0]
1874             : currentFrame[0] - previousFrame[0] - 1;
1875     final int previousNumlocal = previousFrame[1];
1876     final int numLocalDelta = numLocal - previousNumlocal;
1877     int type = Frame.FULL_FRAME;
1878     if (numStack == 0) {
1879       switch (numLocalDelta) {
1880         case -3:
1881         case -2:
1882         case -1:
1883           type = Frame.CHOP_FRAME;
1884           break;
1885         case 0:
1886           type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED;
1887           break;
1888         case 1:
1889         case 2:
1890         case 3:
1891           type = Frame.APPEND_FRAME;
1892           break;
1893         default:
1894           // Keep the FULL_FRAME type.
1895           break;
1896       }
1897     } else if (numLocalDelta == 0 && numStack == 1) {
1898       type =
1899           offsetDelta < 63
1900               ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME
1901               : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1902     }
1903     if (type != Frame.FULL_FRAME) {
1904       // Verify if locals are the same as in the previous frame.
1905       int frameIndex = 3;
1906       for (int i = 0; i < previousNumlocal && i < numLocal; i++) {
1907         if (currentFrame[frameIndex] != previousFrame[frameIndex]) {
1908           type = Frame.FULL_FRAME;
1909           break;
1910         }
1911         frameIndex++;
1912       }
1913     }
1914     switch (type) {
1915       case Frame.SAME_FRAME:
1916         stackMapTableEntries.putByte(offsetDelta);
1917         break;
1918       case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME:
1919         stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
1920         putAbstractTypes(3 + numLocal, 4 + numLocal);
1921         break;
1922       case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1923         stackMapTableEntries
1924             .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
1925             .putShort(offsetDelta);
1926         putAbstractTypes(3 + numLocal, 4 + numLocal);
1927         break;
1928       case Frame.SAME_FRAME_EXTENDED:
1929         stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
1930         break;
1931       case Frame.CHOP_FRAME:
1932         stackMapTableEntries
1933             .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
1934             .putShort(offsetDelta);
1935         break;
1936       case Frame.APPEND_FRAME:
1937         stackMapTableEntries
1938             .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
1939             .putShort(offsetDelta);
1940         putAbstractTypes(3 + previousNumlocal, 3 + numLocal);
1941         break;
1942       case Frame.FULL_FRAME:
1943       default:
1944         stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
1945         putAbstractTypes(3, 3 + numLocal);
1946         stackMapTableEntries.putShort(numStack);
1947         putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
1948         break;
1949     }
1950   }
1951 
1952   /**
1953    * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the
1954    * JVMS verification_type_info format used in StackMapTable attributes.
1955    *
1956    * @param start index of the first type in {@link #currentFrame} to write.
1957    * @param end index of last type in {@link #currentFrame} to write (exclusive).
1958    */
1959   private void putAbstractTypes(final int start, final int end) {
1960     for (int i = start; i < end; ++i) {
1961       Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries);
1962     }
1963   }
1964 
1965   /**
1966    * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS
1967    * verification_type_info format used in StackMapTable attributes.
1968    *
1969    * @param type a frame element type described using the same format as in {@link
1970    *     MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
1971    *     Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or
1972    *     {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating
1973    *     a NEW instruction (for uninitialized types).
1974    */
1975   private void putFrameType(final Object type) {
1976     if (type instanceof Integer) {
1977       stackMapTableEntries.putByte(((Integer) type).intValue());
1978     } else if (type instanceof String) {
1979       stackMapTableEntries
1980           .putByte(Frame.ITEM_OBJECT)
1981           .putShort(symbolTable.addConstantClass((String) type).index);
1982     } else {
1983       stackMapTableEntries.putByte(Frame.ITEM_UNINITIALIZED);
1984       ((Label) type).put(stackMapTableEntries);
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