001// ASM: a very small and fast Java bytecode manipulation framework
002// Copyright (c) 2000-2011 INRIA, France Telecom
003// All rights reserved.
004//
005// Redistribution and use in source and binary forms, with or without
006// modification, are permitted provided that the following conditions
007// are met:
008// 1. Redistributions of source code must retain the above copyright
009//    notice, this list of conditions and the following disclaimer.
010// 2. Redistributions in binary form must reproduce the above copyright
011//    notice, this list of conditions and the following disclaimer in the
012//    documentation and/or other materials provided with the distribution.
013// 3. Neither the name of the copyright holders nor the names of its
014//    contributors may be used to endorse or promote products derived from
015//    this software without specific prior written permission.
016//
017// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
020// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
021// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
022// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
023// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
024// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
025// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
026// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
027// THE POSSIBILITY OF SUCH DAMAGE.
028package io.ebean.enhance.asm;
029
030/**
031 * A {@link ClassVisitor} that generates a corresponding ClassFile structure, as defined in the Java
032 * Virtual Machine Specification (JVMS). It can be used alone, to generate a Java class "from
033 * scratch", or with one or more {@link ClassReader} and adapter {@link ClassVisitor} to generate a
034 * modified class from one or more existing Java classes.
035 *
036 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a>
037 * @author Eric Bruneton
038 */
039public class ClassWriter extends ClassVisitor {
040
041  /**
042   * A flag to automatically compute the maximum stack size and the maximum number of local
043   * variables of methods. If this flag is set, then the arguments of the {@link
044   * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link
045   * #visitMethod} method will be ignored, and computed automatically from the signature and the
046   * bytecode of each method.
047   *
048   * <p><b>Note:</b> for classes whose version is {@link Opcodes#V1_7} of more, this option requires
049   * valid stack map frames. The maximum stack size is then computed from these frames, and from the
050   * bytecode instructions in between. If stack map frames are not present or must be recomputed,
051   * used {@link #COMPUTE_FRAMES} instead.
052   *
053   * @see #ClassWriter(int)
054   */
055  public static final int COMPUTE_MAXS = 1;
056
057  /**
058   * A flag to automatically compute the stack map frames of methods from scratch. If this flag is
059   * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack
060   * map frames are recomputed from the methods bytecode. The arguments of the {@link
061   * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other
062   * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}.
063   *
064   * @see #ClassWriter(int)
065   */
066  public static final int COMPUTE_FRAMES = 2;
067
068  // Note: fields are ordered as in the ClassFile structure, and those related to attributes are
069  // ordered as in Section 4.7 of the JVMS.
070
071  /**
072   * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is
073   * stored in the 16 most significant bits, and major_version in the 16 least significant bits.
074   */
075  private int version;
076
077  /** The symbol table for this class (contains the constant_pool and the BootstrapMethods). */
078  private final SymbolTable symbolTable;
079
080  /**
081   * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific
082   * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
083   * ClassFile structure.
084   */
085  private int accessFlags;
086
087  /** The this_class field of the JVMS ClassFile structure. */
088  private int thisClass;
089
090  /** The super_class field of the JVMS ClassFile structure. */
091  private int superClass;
092
093  /** The interface_count field of the JVMS ClassFile structure. */
094  private int interfaceCount;
095
096  /** The 'interfaces' array of the JVMS ClassFile structure. */
097  private int[] interfaces;
098
099  /**
100   * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their
101   * {@link FieldWriter#fv} field. This field stores the first element of this list.
102   */
103  private FieldWriter firstField;
104
105  /**
106   * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their
107   * {@link FieldWriter#fv} field. This field stores the last element of this list.
108   */
109  private FieldWriter lastField;
110
111  /**
112   * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their
113   * {@link MethodWriter#mv} field. This field stores the first element of this list.
114   */
115  private MethodWriter firstMethod;
116
117  /**
118   * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their
119   * {@link MethodWriter#mv} field. This field stores the last element of this list.
120   */
121  private MethodWriter lastMethod;
122
123  /** The number_of_classes field of the InnerClasses attribute, or 0. */
124  private int numberOfInnerClasses;
125
126  /** The 'classes' array of the InnerClasses attribute, or {@literal null}. */
127  private ByteVector innerClasses;
128
129  /** The class_index field of the EnclosingMethod attribute, or 0. */
130  private int enclosingClassIndex;
131
132  /** The method_index field of the EnclosingMethod attribute. */
133  private int enclosingMethodIndex;
134
135  /** The signature_index field of the Signature attribute, or 0. */
136  private int signatureIndex;
137
138  /** The source_file_index field of the SourceFile attribute, or 0. */
139  private int sourceFileIndex;
140
141  /** The debug_extension field of the SourceDebugExtension attribute, or {@literal null}. */
142  private ByteVector debugExtension;
143
144  /**
145   * The last runtime visible annotation of this class. The previous ones can be accessed with the
146   * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
147   */
148  private AnnotationWriter lastRuntimeVisibleAnnotation;
149
150  /**
151   * The last runtime invisible annotation of this class. The previous ones can be accessed with the
152   * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
153   */
154  private AnnotationWriter lastRuntimeInvisibleAnnotation;
155
156  /**
157   * The last runtime visible type annotation of this class. The previous ones can be accessed with
158   * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
159   */
160  private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
161
162  /**
163   * The last runtime invisible type annotation of this class. The previous ones can be accessed
164   * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
165   */
166  private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
167
168  /** The Module attribute of this class, or {@literal null}. */
169  private ModuleWriter moduleWriter;
170
171  /** The host_class_index field of the NestHost attribute, or 0. */
172  private int nestHostClassIndex;
173
174  /** The number_of_classes field of the NestMembers attribute, or 0. */
175  private int numberOfNestMemberClasses;
176
177  /** The 'classes' array of the NestMembers attribute, or {@literal null}. */
178  private ByteVector nestMemberClasses;
179
180  /**
181   * The first non standard attribute of this class. The next ones can be accessed with the {@link
182   * Attribute#nextAttribute} field. May be {@literal null}.
183   *
184   * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
185   * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
186   * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the
187   * reverse order specified by the user.
188   */
189  private Attribute firstAttribute;
190
191  /**
192   * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link
193   * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link
194   * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}.
195   */
196  private int compute;
197
198  // -----------------------------------------------------------------------------------------------
199  // Constructor
200  // -----------------------------------------------------------------------------------------------
201
202  /**
203   * Constructs a new {@link ClassWriter} object.
204   *
205   * @param flags option flags that can be used to modify the default behavior of this class. Must
206   *     be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}.
207   */
208  public ClassWriter(final int flags) {
209    this(null, flags);
210  }
211
212  /**
213   * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode
214   * transformations. These optimizations are the following:
215   *
216   * <ul>
217   *   <li>The constant pool and bootstrap methods from the original class are copied as is in the
218   *       new class, which saves time. New constant pool entries and new bootstrap methods will be
219   *       added at the end if necessary, but unused constant pool entries or bootstrap methods
220   *       <i>won't be removed</i>.
221   *   <li>Methods that are not transformed are copied as is in the new class, directly from the
222   *       original class bytecode (i.e. without emitting visit events for all the method
223   *       instructions), which saves a <i>lot</i> of time. Untransformed methods are detected by
224   *       the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come
225   *       from a {@link ClassWriter} (and not from any other {@link ClassVisitor} instance).
226   * </ul>
227   *
228   * @param classReader the {@link ClassReader} used to read the original class. It will be used to
229   *     copy the entire constant pool and bootstrap methods from the original class and also to
230   *     copy other fragments of original bytecode where applicable.
231   * @param flags option flags that can be used to modify the default behavior of this class.Must be
232   *     zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. <i>These option flags do
233   *     not affect methods that are copied as is in the new class. This means that neither the
234   *     maximum stack size nor the stack frames will be computed for these methods</i>.
235   */
236  public ClassWriter(final ClassReader classReader, final int flags) {
237    super(Opcodes.ASM7);
238    symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
239    if ((flags & COMPUTE_FRAMES) != 0) {
240      this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
241    } else if ((flags & COMPUTE_MAXS) != 0) {
242      this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
243    } else {
244      this.compute = MethodWriter.COMPUTE_NOTHING;
245    }
246  }
247
248  // -----------------------------------------------------------------------------------------------
249  // Implementation of the ClassVisitor abstract class
250  // -----------------------------------------------------------------------------------------------
251
252  @Override
253  public final void visit(
254      final int version,
255      final int access,
256      final String name,
257      final String signature,
258      final String superName,
259      final String[] interfaces) {
260    this.version = version;
261    this.accessFlags = access;
262    this.thisClass = symbolTable.setMajorVersionAndClassName(version & 0xFFFF, name);
263    if (signature != null) {
264      this.signatureIndex = symbolTable.addConstantUtf8(signature);
265    }
266    this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index;
267    if (interfaces != null && interfaces.length > 0) {
268      interfaceCount = interfaces.length;
269      this.interfaces = new int[interfaceCount];
270      for (int i = 0; i < interfaceCount; ++i) {
271        this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index;
272      }
273    }
274    if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL && (version & 0xFFFF) >= Opcodes.V1_7) {
275      compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES;
276    }
277  }
278
279  @Override
280  public final void visitSource(final String file, final String debug) {
281    if (file != null) {
282      sourceFileIndex = symbolTable.addConstantUtf8(file);
283    }
284    if (debug != null) {
285      debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE);
286    }
287  }
288
289  @Override
290  public final ModuleVisitor visitModule(
291      final String name, final int access, final String version) {
292    return moduleWriter =
293        new ModuleWriter(
294            symbolTable,
295            symbolTable.addConstantModule(name).index,
296            access,
297            version == null ? 0 : symbolTable.addConstantUtf8(version));
298  }
299
300  @Override
301  public void visitNestHost(final String nestHost) {
302    nestHostClassIndex = symbolTable.addConstantClass(nestHost).index;
303  }
304
305  @Override
306  public final void visitOuterClass(
307      final String owner, final String name, final String descriptor) {
308    enclosingClassIndex = symbolTable.addConstantClass(owner).index;
309    if (name != null && descriptor != null) {
310      enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor);
311    }
312  }
313
314  @Override
315  public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
316    if (visible) {
317      return lastRuntimeVisibleAnnotation =
318          AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
319    } else {
320      return lastRuntimeInvisibleAnnotation =
321          AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
322    }
323  }
324
325  @Override
326  public final AnnotationVisitor visitTypeAnnotation(
327    final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
328    if (visible) {
329      return lastRuntimeVisibleTypeAnnotation =
330          AnnotationWriter.create(
331              symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
332    } else {
333      return lastRuntimeInvisibleTypeAnnotation =
334          AnnotationWriter.create(
335              symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
336    }
337  }
338
339  @Override
340  public final void visitAttribute(final Attribute attribute) {
341    // Store the attributes in the <i>reverse</i> order of their visit by this method.
342    attribute.nextAttribute = firstAttribute;
343    firstAttribute = attribute;
344  }
345
346  @Override
347  public void visitNestMember(final String nestMember) {
348    if (nestMemberClasses == null) {
349      nestMemberClasses = new ByteVector();
350    }
351    ++numberOfNestMemberClasses;
352    nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index);
353  }
354
355  @Override
356  public final void visitInnerClass(
357      final String name, final String outerName, final String innerName, final int access) {
358    if (innerClasses == null) {
359      innerClasses = new ByteVector();
360    }
361    // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table
362    // which represents a class or interface C that is not a package member must have exactly one
363    // corresponding entry in the classes array". To avoid duplicates we keep track in the info
364    // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has
365    // already been added for C. If so, we store the index of this inner class entry (plus one) in
366    // the info field. This trick allows duplicate detection in O(1) time.
367    Symbol nameSymbol = symbolTable.addConstantClass(name);
368    if (nameSymbol.info == 0) {
369      ++numberOfInnerClasses;
370      innerClasses.putShort(nameSymbol.index);
371      innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index);
372      innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName));
373      innerClasses.putShort(access);
374      nameSymbol.info = numberOfInnerClasses;
375    }
376    // Else, compare the inner classes entry nameSymbol.info - 1 with the arguments of this method
377    // and throw an exception if there is a difference?
378  }
379
380  @Override
381  public final FieldVisitor visitField(
382      final int access,
383      final String name,
384      final String descriptor,
385      final String signature,
386      final Object value) {
387    FieldWriter fieldWriter =
388        new FieldWriter(symbolTable, access, name, descriptor, signature, value);
389    if (firstField == null) {
390      firstField = fieldWriter;
391    } else {
392      lastField.fv = fieldWriter;
393    }
394    return lastField = fieldWriter;
395  }
396
397  @Override
398  public final MethodVisitor visitMethod(
399      final int access,
400      final String name,
401      final String descriptor,
402      final String signature,
403      final String[] exceptions) {
404    MethodWriter methodWriter =
405        new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute);
406    if (firstMethod == null) {
407      firstMethod = methodWriter;
408    } else {
409      lastMethod.mv = methodWriter;
410    }
411    return lastMethod = methodWriter;
412  }
413
414  @Override
415  public final void visitEnd() {
416    // Nothing to do.
417  }
418
419  // -----------------------------------------------------------------------------------------------
420  // Other public methods
421  // -----------------------------------------------------------------------------------------------
422
423  /**
424   * Returns the content of the class file that was built by this ClassWriter.
425   *
426   * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter.
427   * @throws ClassTooLargeException if the constant pool of the class is too large.
428   * @throws MethodTooLargeException if the Code attribute of a method is too large.
429   */
430  public byte[] toByteArray() {
431    // First step: compute the size in bytes of the ClassFile structure.
432    // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version,
433    // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count,
434    // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too.
435    int size = 24 + 2 * interfaceCount;
436    int fieldsCount = 0;
437    FieldWriter fieldWriter = firstField;
438    while (fieldWriter != null) {
439      ++fieldsCount;
440      size += fieldWriter.computeFieldInfoSize();
441      fieldWriter = (FieldWriter) fieldWriter.fv;
442    }
443    int methodsCount = 0;
444    MethodWriter methodWriter = firstMethod;
445    while (methodWriter != null) {
446      ++methodsCount;
447      size += methodWriter.computeMethodInfoSize();
448      methodWriter = (MethodWriter) methodWriter.mv;
449    }
450    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
451    int attributesCount = 0;
452    if (innerClasses != null) {
453      ++attributesCount;
454      size += 8 + innerClasses.length;
455      symbolTable.addConstantUtf8(Constants.INNER_CLASSES);
456    }
457    if (enclosingClassIndex != 0) {
458      ++attributesCount;
459      size += 10;
460      symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD);
461    }
462    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
463      ++attributesCount;
464      size += 6;
465      symbolTable.addConstantUtf8(Constants.SYNTHETIC);
466    }
467    if (signatureIndex != 0) {
468      ++attributesCount;
469      size += 8;
470      symbolTable.addConstantUtf8(Constants.SIGNATURE);
471    }
472    if (sourceFileIndex != 0) {
473      ++attributesCount;
474      size += 8;
475      symbolTable.addConstantUtf8(Constants.SOURCE_FILE);
476    }
477    if (debugExtension != null) {
478      ++attributesCount;
479      size += 6 + debugExtension.length;
480      symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION);
481    }
482    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
483      ++attributesCount;
484      size += 6;
485      symbolTable.addConstantUtf8(Constants.DEPRECATED);
486    }
487    if (lastRuntimeVisibleAnnotation != null) {
488      ++attributesCount;
489      size +=
490          lastRuntimeVisibleAnnotation.computeAnnotationsSize(
491              Constants.RUNTIME_VISIBLE_ANNOTATIONS);
492    }
493    if (lastRuntimeInvisibleAnnotation != null) {
494      ++attributesCount;
495      size +=
496          lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
497              Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
498    }
499    if (lastRuntimeVisibleTypeAnnotation != null) {
500      ++attributesCount;
501      size +=
502          lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
503              Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
504    }
505    if (lastRuntimeInvisibleTypeAnnotation != null) {
506      ++attributesCount;
507      size +=
508          lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
509              Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
510    }
511    if (symbolTable.computeBootstrapMethodsSize() > 0) {
512      ++attributesCount;
513      size += symbolTable.computeBootstrapMethodsSize();
514    }
515    if (moduleWriter != null) {
516      attributesCount += moduleWriter.getAttributeCount();
517      size += moduleWriter.computeAttributesSize();
518    }
519    if (nestHostClassIndex != 0) {
520      ++attributesCount;
521      size += 8;
522      symbolTable.addConstantUtf8(Constants.NEST_HOST);
523    }
524    if (nestMemberClasses != null) {
525      ++attributesCount;
526      size += 8 + nestMemberClasses.length;
527      symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
528    }
529    if (firstAttribute != null) {
530      attributesCount += firstAttribute.getAttributeCount();
531      size += firstAttribute.computeAttributesSize(symbolTable);
532    }
533    // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous
534    // statements can add attribute names to the constant pool, thereby changing its size!
535    size += symbolTable.getConstantPoolLength();
536    int constantPoolCount = symbolTable.getConstantPoolCount();
537    if (constantPoolCount > 0xFFFF) {
538      throw new ClassTooLargeException(symbolTable.getClassName(), constantPoolCount);
539    }
540
541    // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in
542    // dynamic resizes) and fill it with the ClassFile content.
543    ByteVector result = new ByteVector(size);
544    result.putInt(0xCAFEBABE).putInt(version);
545    symbolTable.putConstantPool(result);
546    int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0;
547    result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass);
548    result.putShort(interfaceCount);
549    for (int i = 0; i < interfaceCount; ++i) {
550      result.putShort(interfaces[i]);
551    }
552    result.putShort(fieldsCount);
553    fieldWriter = firstField;
554    while (fieldWriter != null) {
555      fieldWriter.putFieldInfo(result);
556      fieldWriter = (FieldWriter) fieldWriter.fv;
557    }
558    result.putShort(methodsCount);
559    boolean hasFrames = false;
560    boolean hasAsmInstructions = false;
561    methodWriter = firstMethod;
562    while (methodWriter != null) {
563      hasFrames |= methodWriter.hasFrames();
564      hasAsmInstructions |= methodWriter.hasAsmInstructions();
565      methodWriter.putMethodInfo(result);
566      methodWriter = (MethodWriter) methodWriter.mv;
567    }
568    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
569    result.putShort(attributesCount);
570    if (innerClasses != null) {
571      result
572          .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES))
573          .putInt(innerClasses.length + 2)
574          .putShort(numberOfInnerClasses)
575          .putByteArray(innerClasses.data, 0, innerClasses.length);
576    }
577    if (enclosingClassIndex != 0) {
578      result
579          .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD))
580          .putInt(4)
581          .putShort(enclosingClassIndex)
582          .putShort(enclosingMethodIndex);
583    }
584    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
585      result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
586    }
587    if (signatureIndex != 0) {
588      result
589          .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
590          .putInt(2)
591          .putShort(signatureIndex);
592    }
593    if (sourceFileIndex != 0) {
594      result
595          .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE))
596          .putInt(2)
597          .putShort(sourceFileIndex);
598    }
599    if (debugExtension != null) {
600      int length = debugExtension.length;
601      result
602          .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION))
603          .putInt(length)
604          .putByteArray(debugExtension.data, 0, length);
605    }
606    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
607      result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
608    }
609    AnnotationWriter.putAnnotations(
610        symbolTable,
611        lastRuntimeVisibleAnnotation,
612        lastRuntimeInvisibleAnnotation,
613        lastRuntimeVisibleTypeAnnotation,
614        lastRuntimeInvisibleTypeAnnotation,
615        result);
616    symbolTable.putBootstrapMethods(result);
617    if (moduleWriter != null) {
618      moduleWriter.putAttributes(result);
619    }
620    if (nestHostClassIndex != 0) {
621      result
622          .putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST))
623          .putInt(2)
624          .putShort(nestHostClassIndex);
625    }
626    if (nestMemberClasses != null) {
627      result
628          .putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS))
629          .putInt(nestMemberClasses.length + 2)
630          .putShort(numberOfNestMemberClasses)
631          .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
632    }
633    if (firstAttribute != null) {
634      firstAttribute.putAttributes(symbolTable, result);
635    }
636
637    // Third step: replace the ASM specific instructions, if any.
638    if (hasAsmInstructions) {
639      return replaceAsmInstructions(result.data, hasFrames);
640    } else {
641      return result.data;
642    }
643  }
644
645  /**
646   * Returns the equivalent of the given class file, with the ASM specific instructions replaced
647   * with standard ones. This is done with a ClassReader -&gt; ClassWriter round trip.
648   *
649   * @param classFile a class file containing ASM specific instructions, generated by this
650   *     ClassWriter.
651   * @param hasFrames whether there is at least one stack map frames in 'classFile'.
652   * @return an equivalent of 'classFile', with the ASM specific instructions replaced with standard
653   *     ones.
654   */
655  private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) {
656    final Attribute[] attributes = getAttributePrototypes();
657    firstField = null;
658    lastField = null;
659    firstMethod = null;
660    lastMethod = null;
661    lastRuntimeVisibleAnnotation = null;
662    lastRuntimeInvisibleAnnotation = null;
663    lastRuntimeVisibleTypeAnnotation = null;
664    lastRuntimeInvisibleTypeAnnotation = null;
665    moduleWriter = null;
666    nestHostClassIndex = 0;
667    numberOfNestMemberClasses = 0;
668    nestMemberClasses = null;
669    firstAttribute = null;
670    compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
671    new ClassReader(classFile, 0, /* checkClassVersion = */ false)
672        .accept(
673            this,
674            attributes,
675            (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS);
676    return toByteArray();
677  }
678
679  /**
680   * Returns the prototypes of the attributes used by this class, its fields and its methods.
681   *
682   * @return the prototypes of the attributes used by this class, its fields and its methods.
683   */
684  private Attribute[] getAttributePrototypes() {
685    Attribute.Set attributePrototypes = new Attribute.Set();
686    attributePrototypes.addAttributes(firstAttribute);
687    FieldWriter fieldWriter = firstField;
688    while (fieldWriter != null) {
689      fieldWriter.collectAttributePrototypes(attributePrototypes);
690      fieldWriter = (FieldWriter) fieldWriter.fv;
691    }
692    MethodWriter methodWriter = firstMethod;
693    while (methodWriter != null) {
694      methodWriter.collectAttributePrototypes(attributePrototypes);
695      methodWriter = (MethodWriter) methodWriter.mv;
696    }
697    return attributePrototypes.toArray();
698  }
699
700  // -----------------------------------------------------------------------------------------------
701  // Utility methods: constant pool management for Attribute sub classes
702  // -----------------------------------------------------------------------------------------------
703
704  /**
705   * Adds a number or string constant to the constant pool of the class being build. Does nothing if
706   * the constant pool already contains a similar item. <i>This method is intended for {@link
707   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
708   *
709   * @param value the value of the constant to be added to the constant pool. This parameter must be
710   *     an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
711   * @return the index of a new or already existing constant item with the given value.
712   */
713  public int newConst(final Object value) {
714    return symbolTable.addConstant(value).index;
715  }
716
717  /**
718   * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant
719   * pool already contains a similar item. <i>This method is intended for {@link Attribute} sub
720   * classes, and is normally not needed by class generators or adapters.</i>
721   *
722   * @param value the String value.
723   * @return the index of a new or already existing UTF8 item.
724   */
725  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
726  public int newUTF8(final String value) {
727    return symbolTable.addConstantUtf8(value);
728  }
729
730  /**
731   * Adds a class reference to the constant pool of the class being build. Does nothing if the
732   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
733   * sub classes, and is normally not needed by class generators or adapters.</i>
734   *
735   * @param value the internal name of the class.
736   * @return the index of a new or already existing class reference item.
737   */
738  public int newClass(final String value) {
739    return symbolTable.addConstantClass(value).index;
740  }
741
742  /**
743   * Adds a method type reference to the constant pool of the class being build. Does nothing if the
744   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
745   * sub classes, and is normally not needed by class generators or adapters.</i>
746   *
747   * @param methodDescriptor method descriptor of the method type.
748   * @return the index of a new or already existing method type reference item.
749   */
750  public int newMethodType(final String methodDescriptor) {
751    return symbolTable.addConstantMethodType(methodDescriptor).index;
752  }
753
754  /**
755   * Adds a module reference to the constant pool of the class being build. Does nothing if the
756   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
757   * sub classes, and is normally not needed by class generators or adapters.</i>
758   *
759   * @param moduleName name of the module.
760   * @return the index of a new or already existing module reference item.
761   */
762  public int newModule(final String moduleName) {
763    return symbolTable.addConstantModule(moduleName).index;
764  }
765
766  /**
767   * Adds a package reference to the constant pool of the class being build. Does nothing if the
768   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
769   * sub classes, and is normally not needed by class generators or adapters.</i>
770   *
771   * @param packageName name of the package in its internal form.
772   * @return the index of a new or already existing module reference item.
773   */
774  public int newPackage(final String packageName) {
775    return symbolTable.addConstantPackage(packageName).index;
776  }
777
778  /**
779   * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool
780   * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes,
781   * and is normally not needed by class generators or adapters.</i>
782   *
783   * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link
784   *     Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
785   *     Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
786   *     {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
787   * @param owner the internal name of the field or method owner class.
788   * @param name the name of the field or method.
789   * @param descriptor the descriptor of the field or method.
790   * @return the index of a new or already existing method type reference item.
791   * @deprecated this method is superseded by {@link #newHandle(int, String, String, String,
792   *     boolean)}.
793   */
794  @Deprecated
795  public int newHandle(
796      final int tag, final String owner, final String name, final String descriptor) {
797    return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
798  }
799
800  /**
801   * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool
802   * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes,
803   * and is normally not needed by class generators or adapters.</i>
804   *
805   * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link
806   *     Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
807   *     Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
808   *     {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
809   * @param owner the internal name of the field or method owner class.
810   * @param name the name of the field or method.
811   * @param descriptor the descriptor of the field or method.
812   * @param isInterface true if the owner is an interface.
813   * @return the index of a new or already existing method type reference item.
814   */
815  public int newHandle(
816      final int tag,
817      final String owner,
818      final String name,
819      final String descriptor,
820      final boolean isInterface) {
821    return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index;
822  }
823
824  /**
825   * Adds a dynamic constant reference to the constant pool of the class being build. Does nothing
826   * if the constant pool already contains a similar item. <i>This method is intended for {@link
827   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
828   *
829   * @param name name of the invoked method.
830   * @param descriptor field descriptor of the constant type.
831   * @param bootstrapMethodHandle the bootstrap method.
832   * @param bootstrapMethodArguments the bootstrap method constant arguments.
833   * @return the index of a new or already existing dynamic constant reference item.
834   */
835  public int newConstantDynamic(
836      final String name,
837      final String descriptor,
838      final Handle bootstrapMethodHandle,
839      final Object... bootstrapMethodArguments) {
840    return symbolTable.addConstantDynamic(
841            name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
842        .index;
843  }
844
845  /**
846   * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if
847   * the constant pool already contains a similar item. <i>This method is intended for {@link
848   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
849   *
850   * @param name name of the invoked method.
851   * @param descriptor descriptor of the invoke method.
852   * @param bootstrapMethodHandle the bootstrap method.
853   * @param bootstrapMethodArguments the bootstrap method constant arguments.
854   * @return the index of a new or already existing invokedynamic reference item.
855   */
856  public int newInvokeDynamic(
857      final String name,
858      final String descriptor,
859      final Handle bootstrapMethodHandle,
860      final Object... bootstrapMethodArguments) {
861    return symbolTable.addConstantInvokeDynamic(
862            name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
863        .index;
864  }
865
866  /**
867   * Adds a field reference to the constant pool of the class being build. Does nothing if the
868   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
869   * sub classes, and is normally not needed by class generators or adapters.</i>
870   *
871   * @param owner the internal name of the field's owner class.
872   * @param name the field's name.
873   * @param descriptor the field's descriptor.
874   * @return the index of a new or already existing field reference item.
875   */
876  public int newField(final String owner, final String name, final String descriptor) {
877    return symbolTable.addConstantFieldref(owner, name, descriptor).index;
878  }
879
880  /**
881   * Adds a method reference to the constant pool of the class being build. Does nothing if the
882   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
883   * sub classes, and is normally not needed by class generators or adapters.</i>
884   *
885   * @param owner the internal name of the method's owner class.
886   * @param name the method's name.
887   * @param descriptor the method's descriptor.
888   * @param isInterface {@literal true} if {@code owner} is an interface.
889   * @return the index of a new or already existing method reference item.
890   */
891  public int newMethod(
892      final String owner, final String name, final String descriptor, final boolean isInterface) {
893    return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index;
894  }
895
896  /**
897   * Adds a name and type to the constant pool of the class being build. Does nothing if the
898   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
899   * sub classes, and is normally not needed by class generators or adapters.</i>
900   *
901   * @param name a name.
902   * @param descriptor a type descriptor.
903   * @return the index of a new or already existing name and type item.
904   */
905  public int newNameType(final String name, final String descriptor) {
906    return symbolTable.addConstantNameAndType(name, descriptor);
907  }
908
909  // -----------------------------------------------------------------------------------------------
910  // Default method to compute common super classes when computing stack map frames
911  // -----------------------------------------------------------------------------------------------
912
913  /**
914   * Returns the common super type of the two given types. The default implementation of this method
915   * <i>loads</i> the two given classes and uses the java.lang.Class methods to find the common
916   * super class. It can be overridden to compute this common super type in other ways, in
917   * particular without actually loading any class, or to take into account the class that is
918   * currently being generated by this ClassWriter, which can of course not be loaded since it is
919   * under construction.
920   *
921   * @param type1 the internal name of a class.
922   * @param type2 the internal name of another class.
923   * @return the internal name of the common super class of the two given classes.
924   */
925  protected String getCommonSuperClass(final String type1, final String type2) {
926    ClassLoader classLoader = getClassLoader();
927    Class<?> class1;
928    try {
929      class1 = Class.forName(type1.replace('/', '.'), false, classLoader);
930    } catch (ClassNotFoundException e) {
931      throw new TypeNotPresentException(type1, e);
932    }
933    Class<?> class2;
934    try {
935      class2 = Class.forName(type2.replace('/', '.'), false, classLoader);
936    } catch (ClassNotFoundException e) {
937      throw new TypeNotPresentException(type2, e);
938    }
939    if (class1.isAssignableFrom(class2)) {
940      return type1;
941    }
942    if (class2.isAssignableFrom(class1)) {
943      return type2;
944    }
945    if (class1.isInterface() || class2.isInterface()) {
946      return "java/lang/Object";
947    } else {
948      do {
949        class1 = class1.getSuperclass();
950      } while (!class1.isAssignableFrom(class2));
951      return class1.getName().replace('.', '/');
952    }
953  }
954
955  /**
956   * Returns the {@link ClassLoader} to be used by the default implementation of {@link
957   * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
958   * default.
959   *
960   * @return ClassLoader
961   */
962  protected ClassLoader getClassLoader() {
963    return getClass().getClassLoader();
964  }
965}