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 org.springframework.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  /** The number_of_classes field of the PermittedSubtypes attribute, or 0. */
181  private int numberOfPermittedSubtypeClasses;
182
183  /** The 'classes' array of the PermittedSubtypes attribute, or {@literal null}. */
184  private ByteVector permittedSubtypeClasses;
185
186  /**
187   * The record components of this class, stored in a linked list of {@link RecordComponentWriter}
188   * linked via their {@link RecordComponentWriter#delegate} field. This field stores the first
189   * element of this list.
190   */
191  private RecordComponentWriter firstRecordComponent;
192
193  /**
194   * The record components of this class, stored in a linked list of {@link RecordComponentWriter}
195   * linked via their {@link RecordComponentWriter#delegate} field. This field stores the last
196   * element of this list.
197   */
198  private RecordComponentWriter lastRecordComponent;
199
200  /**
201   * The first non standard attribute of this class. The next ones can be accessed with the {@link
202   * Attribute#nextAttribute} field. May be {@literal null}.
203   *
204   * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
205   * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
206   * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the
207   * reverse order specified by the user.
208   */
209  private Attribute firstAttribute;
210
211  /**
212   * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link
213   * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link
214   * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}.
215   */
216  private int compute;
217
218  // -----------------------------------------------------------------------------------------------
219  // Constructor
220  // -----------------------------------------------------------------------------------------------
221
222  /**
223   * Constructs a new {@link ClassWriter} object.
224   *
225   * @param flags option flags that can be used to modify the default behavior of this class. Must
226   *     be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}.
227   */
228  public ClassWriter(final int flags) {
229    this(null, flags);
230  }
231
232  /**
233   * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode
234   * transformations. These optimizations are the following:
235   *
236   * <ul>
237   *   <li>The constant pool and bootstrap methods from the original class are copied as is in the
238   *       new class, which saves time. New constant pool entries and new bootstrap methods will be
239   *       added at the end if necessary, but unused constant pool entries or bootstrap methods
240   *       <i>won't be removed</i>.
241   *   <li>Methods that are not transformed are copied as is in the new class, directly from the
242   *       original class bytecode (i.e. without emitting visit events for all the method
243   *       instructions), which saves a <i>lot</i> of time. Untransformed methods are detected by
244   *       the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come
245   *       from a {@link ClassWriter} (and not from any other {@link ClassVisitor} instance).
246   * </ul>
247   *
248   * @param classReader the {@link ClassReader} used to read the original class. It will be used to
249   *     copy the entire constant pool and bootstrap methods from the original class and also to
250   *     copy other fragments of original bytecode where applicable.
251   * @param flags option flags that can be used to modify the default behavior of this class.Must be
252   *     zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. <i>These option flags do
253   *     not affect methods that are copied as is in the new class. This means that neither the
254   *     maximum stack size nor the stack frames will be computed for these methods</i>.
255   */
256  public ClassWriter(final ClassReader classReader, final int flags) {
257    super(/* latest api = */ Opcodes.ASM7);
258    symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
259    if ((flags & COMPUTE_FRAMES) != 0) {
260      this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
261    } else if ((flags & COMPUTE_MAXS) != 0) {
262      this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
263    } else {
264      this.compute = MethodWriter.COMPUTE_NOTHING;
265    }
266  }
267
268  // -----------------------------------------------------------------------------------------------
269  // Implementation of the ClassVisitor abstract class
270  // -----------------------------------------------------------------------------------------------
271
272  @Override
273  public final void visit(
274      final int version,
275      final int access,
276      final String name,
277      final String signature,
278      final String superName,
279      final String[] interfaces) {
280    this.version = version;
281    this.accessFlags = access;
282    this.thisClass = symbolTable.setMajorVersionAndClassName(version & 0xFFFF, name);
283    if (signature != null) {
284      this.signatureIndex = symbolTable.addConstantUtf8(signature);
285    }
286    this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index;
287    if (interfaces != null && interfaces.length > 0) {
288      interfaceCount = interfaces.length;
289      this.interfaces = new int[interfaceCount];
290      for (int i = 0; i < interfaceCount; ++i) {
291        this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index;
292      }
293    }
294    if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL && (version & 0xFFFF) >= Opcodes.V1_7) {
295      compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES;
296    }
297  }
298
299  @Override
300  public final void visitSource(final String file, final String debug) {
301    if (file != null) {
302      sourceFileIndex = symbolTable.addConstantUtf8(file);
303    }
304    if (debug != null) {
305      debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE);
306    }
307  }
308
309  @Override
310  public final ModuleVisitor visitModule(
311      final String name, final int access, final String version) {
312    return moduleWriter =
313        new ModuleWriter(
314            symbolTable,
315            symbolTable.addConstantModule(name).index,
316            access,
317            version == null ? 0 : symbolTable.addConstantUtf8(version));
318  }
319
320  @Override
321  public final void visitNestHost(final String nestHost) {
322    nestHostClassIndex = symbolTable.addConstantClass(nestHost).index;
323  }
324
325  @Override
326  public final void visitOuterClass(
327      final String owner, final String name, final String descriptor) {
328    enclosingClassIndex = symbolTable.addConstantClass(owner).index;
329    if (name != null && descriptor != null) {
330      enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor);
331    }
332  }
333
334  @Override
335  public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
336    if (visible) {
337      return lastRuntimeVisibleAnnotation =
338          AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
339    } else {
340      return lastRuntimeInvisibleAnnotation =
341          AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
342    }
343  }
344
345  @Override
346  public final AnnotationVisitor visitTypeAnnotation(
347      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
348    if (visible) {
349      return lastRuntimeVisibleTypeAnnotation =
350          AnnotationWriter.create(
351              symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
352    } else {
353      return lastRuntimeInvisibleTypeAnnotation =
354          AnnotationWriter.create(
355              symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
356    }
357  }
358
359  @Override
360  public final void visitAttribute(final Attribute attribute) {
361    // Store the attributes in the <i>reverse</i> order of their visit by this method.
362    attribute.nextAttribute = firstAttribute;
363    firstAttribute = attribute;
364  }
365
366  @Override
367  public final void visitNestMember(final String nestMember) {
368    if (nestMemberClasses == null) {
369      nestMemberClasses = new ByteVector();
370    }
371    ++numberOfNestMemberClasses;
372    nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index);
373  }
374
375  @Override
376  @SuppressWarnings("deprecation")
377  public final void visitPermittedSubtypeExperimental(final String permittedSubtype) {
378    if (permittedSubtypeClasses == null) {
379      permittedSubtypeClasses = new ByteVector();
380    }
381    ++numberOfPermittedSubtypeClasses;
382    permittedSubtypeClasses.putShort(symbolTable.addConstantClass(permittedSubtype).index);
383  }
384
385  @Override
386  public final void visitInnerClass(
387      final String name, final String outerName, final String innerName, final int access) {
388    if (innerClasses == null) {
389      innerClasses = new ByteVector();
390    }
391    // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table
392    // which represents a class or interface C that is not a package member must have exactly one
393    // corresponding entry in the classes array". To avoid duplicates we keep track in the info
394    // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has
395    // already been added for C. If so, we store the index of this inner class entry (plus one) in
396    // the info field. This trick allows duplicate detection in O(1) time.
397    Symbol nameSymbol = symbolTable.addConstantClass(name);
398    if (nameSymbol.info == 0) {
399      ++numberOfInnerClasses;
400      innerClasses.putShort(nameSymbol.index);
401      innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index);
402      innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName));
403      innerClasses.putShort(access);
404      nameSymbol.info = numberOfInnerClasses;
405    }
406    // Else, compare the inner classes entry nameSymbol.info - 1 with the arguments of this method
407    // and throw an exception if there is a difference?
408  }
409
410  @Override
411  @SuppressWarnings("deprecation")
412  public final RecordComponentVisitor visitRecordComponentExperimental(
413      final int access, final String name, final String descriptor, final String signature) {
414    RecordComponentWriter recordComponentWriter =
415        new RecordComponentWriter(symbolTable, access, name, descriptor, signature);
416    if (firstRecordComponent == null) {
417      firstRecordComponent = recordComponentWriter;
418    } else {
419      lastRecordComponent.delegate = recordComponentWriter;
420    }
421    return lastRecordComponent = recordComponentWriter;
422  }
423
424  @Override
425  public final FieldVisitor visitField(
426      final int access,
427      final String name,
428      final String descriptor,
429      final String signature,
430      final Object value) {
431    FieldWriter fieldWriter =
432        new FieldWriter(symbolTable, access, name, descriptor, signature, value);
433    if (firstField == null) {
434      firstField = fieldWriter;
435    } else {
436      lastField.fv = fieldWriter;
437    }
438    return lastField = fieldWriter;
439  }
440
441  @Override
442  public final MethodVisitor visitMethod(
443      final int access,
444      final String name,
445      final String descriptor,
446      final String signature,
447      final String[] exceptions) {
448    MethodWriter methodWriter =
449        new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute);
450    if (firstMethod == null) {
451      firstMethod = methodWriter;
452    } else {
453      lastMethod.mv = methodWriter;
454    }
455    return lastMethod = methodWriter;
456  }
457
458  @Override
459  public final void visitEnd() {
460    // Nothing to do.
461  }
462
463  // -----------------------------------------------------------------------------------------------
464  // Other public methods
465  // -----------------------------------------------------------------------------------------------
466
467  /**
468   * Returns the content of the class file that was built by this ClassWriter.
469   *
470   * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter.
471   * @throws ClassTooLargeException if the constant pool of the class is too large.
472   * @throws MethodTooLargeException if the Code attribute of a method is too large.
473   */
474  public byte[] toByteArray() {
475    // First step: compute the size in bytes of the ClassFile structure.
476    // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version,
477    // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count,
478    // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too.
479    int size = 24 + 2 * interfaceCount;
480    int fieldsCount = 0;
481    FieldWriter fieldWriter = firstField;
482    while (fieldWriter != null) {
483      ++fieldsCount;
484      size += fieldWriter.computeFieldInfoSize();
485      fieldWriter = (FieldWriter) fieldWriter.fv;
486    }
487    int methodsCount = 0;
488    MethodWriter methodWriter = firstMethod;
489    while (methodWriter != null) {
490      ++methodsCount;
491      size += methodWriter.computeMethodInfoSize();
492      methodWriter = (MethodWriter) methodWriter.mv;
493    }
494
495    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
496    int attributesCount = 0;
497    if (innerClasses != null) {
498      ++attributesCount;
499      size += 8 + innerClasses.length;
500      symbolTable.addConstantUtf8(Constants.INNER_CLASSES);
501    }
502    if (enclosingClassIndex != 0) {
503      ++attributesCount;
504      size += 10;
505      symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD);
506    }
507    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
508      ++attributesCount;
509      size += 6;
510      symbolTable.addConstantUtf8(Constants.SYNTHETIC);
511    }
512    if (signatureIndex != 0) {
513      ++attributesCount;
514      size += 8;
515      symbolTable.addConstantUtf8(Constants.SIGNATURE);
516    }
517    if (sourceFileIndex != 0) {
518      ++attributesCount;
519      size += 8;
520      symbolTable.addConstantUtf8(Constants.SOURCE_FILE);
521    }
522    if (debugExtension != null) {
523      ++attributesCount;
524      size += 6 + debugExtension.length;
525      symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION);
526    }
527    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
528      ++attributesCount;
529      size += 6;
530      symbolTable.addConstantUtf8(Constants.DEPRECATED);
531    }
532    if (lastRuntimeVisibleAnnotation != null) {
533      ++attributesCount;
534      size +=
535          lastRuntimeVisibleAnnotation.computeAnnotationsSize(
536              Constants.RUNTIME_VISIBLE_ANNOTATIONS);
537    }
538    if (lastRuntimeInvisibleAnnotation != null) {
539      ++attributesCount;
540      size +=
541          lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
542              Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
543    }
544    if (lastRuntimeVisibleTypeAnnotation != null) {
545      ++attributesCount;
546      size +=
547          lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
548              Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
549    }
550    if (lastRuntimeInvisibleTypeAnnotation != null) {
551      ++attributesCount;
552      size +=
553          lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
554              Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
555    }
556    if (symbolTable.computeBootstrapMethodsSize() > 0) {
557      ++attributesCount;
558      size += symbolTable.computeBootstrapMethodsSize();
559    }
560    if (moduleWriter != null) {
561      attributesCount += moduleWriter.getAttributeCount();
562      size += moduleWriter.computeAttributesSize();
563    }
564    if (nestHostClassIndex != 0) {
565      ++attributesCount;
566      size += 8;
567      symbolTable.addConstantUtf8(Constants.NEST_HOST);
568    }
569    if (nestMemberClasses != null) {
570      ++attributesCount;
571      size += 8 + nestMemberClasses.length;
572      symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
573    }
574    if (permittedSubtypeClasses != null) {
575      ++attributesCount;
576      size += 8 + permittedSubtypeClasses.length;
577      symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES);
578    }
579    int recordComponentCount = 0;
580    int recordSize = 0;
581    if (firstRecordComponent != null) {
582      RecordComponentWriter recordComponentWriter = firstRecordComponent;
583      while (recordComponentWriter != null) {
584        ++recordComponentCount;
585        recordSize += recordComponentWriter.computeRecordComponentInfoSize();
586        recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
587      }
588      ++attributesCount;
589      size += 8 + recordSize;
590      symbolTable.addConstantUtf8(Constants.RECORD);
591    }
592    if (firstAttribute != null) {
593      attributesCount += firstAttribute.getAttributeCount();
594      size += firstAttribute.computeAttributesSize(symbolTable);
595    }
596    // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous
597    // statements can add attribute names to the constant pool, thereby changing its size!
598    size += symbolTable.getConstantPoolLength();
599    int constantPoolCount = symbolTable.getConstantPoolCount();
600    if (constantPoolCount > 0xFFFF) {
601      throw new ClassTooLargeException(symbolTable.getClassName(), constantPoolCount);
602    }
603
604    // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in
605    // dynamic resizes) and fill it with the ClassFile content.
606    ByteVector result = new ByteVector(size);
607    result.putInt(0xCAFEBABE).putInt(version);
608    symbolTable.putConstantPool(result);
609    int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0;
610    result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass);
611    result.putShort(interfaceCount);
612    for (int i = 0; i < interfaceCount; ++i) {
613      result.putShort(interfaces[i]);
614    }
615    result.putShort(fieldsCount);
616    fieldWriter = firstField;
617    while (fieldWriter != null) {
618      fieldWriter.putFieldInfo(result);
619      fieldWriter = (FieldWriter) fieldWriter.fv;
620    }
621    result.putShort(methodsCount);
622    boolean hasFrames = false;
623    boolean hasAsmInstructions = false;
624    methodWriter = firstMethod;
625    while (methodWriter != null) {
626      hasFrames |= methodWriter.hasFrames();
627      hasAsmInstructions |= methodWriter.hasAsmInstructions();
628      methodWriter.putMethodInfo(result);
629      methodWriter = (MethodWriter) methodWriter.mv;
630    }
631    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
632    result.putShort(attributesCount);
633    if (innerClasses != null) {
634      result
635          .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES))
636          .putInt(innerClasses.length + 2)
637          .putShort(numberOfInnerClasses)
638          .putByteArray(innerClasses.data, 0, innerClasses.length);
639    }
640    if (enclosingClassIndex != 0) {
641      result
642          .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD))
643          .putInt(4)
644          .putShort(enclosingClassIndex)
645          .putShort(enclosingMethodIndex);
646    }
647    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
648      result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
649    }
650    if (signatureIndex != 0) {
651      result
652          .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
653          .putInt(2)
654          .putShort(signatureIndex);
655    }
656    if (sourceFileIndex != 0) {
657      result
658          .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE))
659          .putInt(2)
660          .putShort(sourceFileIndex);
661    }
662    if (debugExtension != null) {
663      int length = debugExtension.length;
664      result
665          .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION))
666          .putInt(length)
667          .putByteArray(debugExtension.data, 0, length);
668    }
669    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
670      result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
671    }
672    AnnotationWriter.putAnnotations(
673        symbolTable,
674        lastRuntimeVisibleAnnotation,
675        lastRuntimeInvisibleAnnotation,
676        lastRuntimeVisibleTypeAnnotation,
677        lastRuntimeInvisibleTypeAnnotation,
678        result);
679    symbolTable.putBootstrapMethods(result);
680    if (moduleWriter != null) {
681      moduleWriter.putAttributes(result);
682    }
683    if (nestHostClassIndex != 0) {
684      result
685          .putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST))
686          .putInt(2)
687          .putShort(nestHostClassIndex);
688    }
689    if (nestMemberClasses != null) {
690      result
691          .putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS))
692          .putInt(nestMemberClasses.length + 2)
693          .putShort(numberOfNestMemberClasses)
694          .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
695    }
696    if (permittedSubtypeClasses != null) {
697      result
698          .putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES))
699          .putInt(permittedSubtypeClasses.length + 2)
700          .putShort(numberOfPermittedSubtypeClasses)
701          .putByteArray(permittedSubtypeClasses.data, 0, permittedSubtypeClasses.length);
702    }
703    if (firstRecordComponent != null) {
704      result
705          .putShort(symbolTable.addConstantUtf8(Constants.RECORD))
706          .putInt(recordSize + 2)
707          .putShort(recordComponentCount);
708      RecordComponentWriter recordComponentWriter = firstRecordComponent;
709      while (recordComponentWriter != null) {
710        recordComponentWriter.putRecordComponentInfo(result);
711        recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
712      }
713    }
714    if (firstAttribute != null) {
715      firstAttribute.putAttributes(symbolTable, result);
716    }
717
718    // Third step: replace the ASM specific instructions, if any.
719    if (hasAsmInstructions) {
720      return replaceAsmInstructions(result.data, hasFrames);
721    } else {
722      return result.data;
723    }
724  }
725
726  /**
727   * Returns the equivalent of the given class file, with the ASM specific instructions replaced
728   * with standard ones. This is done with a ClassReader -&gt; ClassWriter round trip.
729   *
730   * @param classFile a class file containing ASM specific instructions, generated by this
731   *     ClassWriter.
732   * @param hasFrames whether there is at least one stack map frames in 'classFile'.
733   * @return an equivalent of 'classFile', with the ASM specific instructions replaced with standard
734   *     ones.
735   */
736  private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) {
737    final Attribute[] attributes = getAttributePrototypes();
738    firstField = null;
739    lastField = null;
740    firstMethod = null;
741    lastMethod = null;
742    lastRuntimeVisibleAnnotation = null;
743    lastRuntimeInvisibleAnnotation = null;
744    lastRuntimeVisibleTypeAnnotation = null;
745    lastRuntimeInvisibleTypeAnnotation = null;
746    moduleWriter = null;
747    nestHostClassIndex = 0;
748    numberOfNestMemberClasses = 0;
749    nestMemberClasses = null;
750    numberOfPermittedSubtypeClasses = 0;
751    permittedSubtypeClasses = null;
752    firstRecordComponent = null;
753    lastRecordComponent = null;
754    firstAttribute = null;
755    compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
756    new ClassReader(classFile, 0, /* checkClassVersion = */ false)
757        .accept(
758            this,
759            attributes,
760            (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS);
761    return toByteArray();
762  }
763
764  /**
765   * Returns the prototypes of the attributes used by this class, its fields and its methods.
766   *
767   * @return the prototypes of the attributes used by this class, its fields and its methods.
768   */
769  private Attribute[] getAttributePrototypes() {
770    Attribute.Set attributePrototypes = new Attribute.Set();
771    attributePrototypes.addAttributes(firstAttribute);
772    FieldWriter fieldWriter = firstField;
773    while (fieldWriter != null) {
774      fieldWriter.collectAttributePrototypes(attributePrototypes);
775      fieldWriter = (FieldWriter) fieldWriter.fv;
776    }
777    MethodWriter methodWriter = firstMethod;
778    while (methodWriter != null) {
779      methodWriter.collectAttributePrototypes(attributePrototypes);
780      methodWriter = (MethodWriter) methodWriter.mv;
781    }
782    RecordComponentWriter recordComponentWriter = firstRecordComponent;
783    while (recordComponentWriter != null) {
784      recordComponentWriter.collectAttributePrototypes(attributePrototypes);
785      recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
786    }
787    return attributePrototypes.toArray();
788  }
789
790  // -----------------------------------------------------------------------------------------------
791  // Utility methods: constant pool management for Attribute sub classes
792  // -----------------------------------------------------------------------------------------------
793
794  /**
795   * Adds a number or string constant to the constant pool of the class being build. Does nothing if
796   * the constant pool already contains a similar item. <i>This method is intended for {@link
797   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
798   *
799   * @param value the value of the constant to be added to the constant pool. This parameter must be
800   *     an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
801   * @return the index of a new or already existing constant item with the given value.
802   */
803  public int newConst(final Object value) {
804    return symbolTable.addConstant(value).index;
805  }
806
807  /**
808   * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant
809   * pool already contains a similar item. <i>This method is intended for {@link Attribute} sub
810   * classes, and is normally not needed by class generators or adapters.</i>
811   *
812   * @param value the String value.
813   * @return the index of a new or already existing UTF8 item.
814   */
815  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
816  public int newUTF8(final String value) {
817    return symbolTable.addConstantUtf8(value);
818  }
819
820  /**
821   * Adds a class reference to the constant pool of the class being build. Does nothing if the
822   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
823   * sub classes, and is normally not needed by class generators or adapters.</i>
824   *
825   * @param value the internal name of the class.
826   * @return the index of a new or already existing class reference item.
827   */
828  public int newClass(final String value) {
829    return symbolTable.addConstantClass(value).index;
830  }
831
832  /**
833   * Adds a method type reference to the constant pool of the class being build. Does nothing if the
834   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
835   * sub classes, and is normally not needed by class generators or adapters.</i>
836   *
837   * @param methodDescriptor method descriptor of the method type.
838   * @return the index of a new or already existing method type reference item.
839   */
840  public int newMethodType(final String methodDescriptor) {
841    return symbolTable.addConstantMethodType(methodDescriptor).index;
842  }
843
844  /**
845   * Adds a module reference to the constant pool of the class being build. Does nothing if the
846   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
847   * sub classes, and is normally not needed by class generators or adapters.</i>
848   *
849   * @param moduleName name of the module.
850   * @return the index of a new or already existing module reference item.
851   */
852  public int newModule(final String moduleName) {
853    return symbolTable.addConstantModule(moduleName).index;
854  }
855
856  /**
857   * Adds a package reference to the constant pool of the class being build. Does nothing if the
858   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
859   * sub classes, and is normally not needed by class generators or adapters.</i>
860   *
861   * @param packageName name of the package in its internal form.
862   * @return the index of a new or already existing module reference item.
863   */
864  public int newPackage(final String packageName) {
865    return symbolTable.addConstantPackage(packageName).index;
866  }
867
868  /**
869   * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool
870   * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes,
871   * and is normally not needed by class generators or adapters.</i>
872   *
873   * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link
874   *     Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
875   *     Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
876   *     {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
877   * @param owner the internal name of the field or method owner class.
878   * @param name the name of the field or method.
879   * @param descriptor the descriptor of the field or method.
880   * @return the index of a new or already existing method type reference item.
881   * @deprecated this method is superseded by {@link #newHandle(int, String, String, String,
882   *     boolean)}.
883   */
884  @Deprecated
885  public int newHandle(
886      final int tag, final String owner, final String name, final String descriptor) {
887    return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
888  }
889
890  /**
891   * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool
892   * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes,
893   * and is normally not needed by class generators or adapters.</i>
894   *
895   * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link
896   *     Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
897   *     Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
898   *     {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
899   * @param owner the internal name of the field or method owner class.
900   * @param name the name of the field or method.
901   * @param descriptor the descriptor of the field or method.
902   * @param isInterface true if the owner is an interface.
903   * @return the index of a new or already existing method type reference item.
904   */
905  public int newHandle(
906      final int tag,
907      final String owner,
908      final String name,
909      final String descriptor,
910      final boolean isInterface) {
911    return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index;
912  }
913
914  /**
915   * Adds a dynamic constant reference to the constant pool of the class being build. Does nothing
916   * if the constant pool already contains a similar item. <i>This method is intended for {@link
917   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
918   *
919   * @param name the name of the invoked method.
920   * @param descriptor field descriptor of the constant type.
921   * @param bootstrapMethodHandle the bootstrap method.
922   * @param bootstrapMethodArguments the bootstrap method constant arguments.
923   * @return the index of a new or already existing dynamic constant reference item.
924   */
925  public int newConstantDynamic(
926      final String name,
927      final String descriptor,
928      final Handle bootstrapMethodHandle,
929      final Object... bootstrapMethodArguments) {
930    return symbolTable.addConstantDynamic(
931            name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
932        .index;
933  }
934
935  /**
936   * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if
937   * the constant pool already contains a similar item. <i>This method is intended for {@link
938   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
939   *
940   * @param name the name of the invoked method.
941   * @param descriptor descriptor of the invoke method.
942   * @param bootstrapMethodHandle the bootstrap method.
943   * @param bootstrapMethodArguments the bootstrap method constant arguments.
944   * @return the index of a new or already existing invokedynamic reference item.
945   */
946  public int newInvokeDynamic(
947      final String name,
948      final String descriptor,
949      final Handle bootstrapMethodHandle,
950      final Object... bootstrapMethodArguments) {
951    return symbolTable.addConstantInvokeDynamic(
952            name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
953        .index;
954  }
955
956  /**
957   * Adds a field reference to the constant pool of the class being build. Does nothing if the
958   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
959   * sub classes, and is normally not needed by class generators or adapters.</i>
960   *
961   * @param owner the internal name of the field's owner class.
962   * @param name the field's name.
963   * @param descriptor the field's descriptor.
964   * @return the index of a new or already existing field reference item.
965   */
966  public int newField(final String owner, final String name, final String descriptor) {
967    return symbolTable.addConstantFieldref(owner, name, descriptor).index;
968  }
969
970  /**
971   * Adds a method reference to the constant pool of the class being build. Does nothing if the
972   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
973   * sub classes, and is normally not needed by class generators or adapters.</i>
974   *
975   * @param owner the internal name of the method's owner class.
976   * @param name the method's name.
977   * @param descriptor the method's descriptor.
978   * @param isInterface {@literal true} if {@code owner} is an interface.
979   * @return the index of a new or already existing method reference item.
980   */
981  public int newMethod(
982      final String owner, final String name, final String descriptor, final boolean isInterface) {
983    return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index;
984  }
985
986  /**
987   * Adds a name and type to the constant pool of the class being build. Does nothing if the
988   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
989   * sub classes, and is normally not needed by class generators or adapters.</i>
990   *
991   * @param name a name.
992   * @param descriptor a type descriptor.
993   * @return the index of a new or already existing name and type item.
994   */
995  public int newNameType(final String name, final String descriptor) {
996    return symbolTable.addConstantNameAndType(name, descriptor);
997  }
998
999  // -----------------------------------------------------------------------------------------------
1000  // Default method to compute common super classes when computing stack map frames
1001  // -----------------------------------------------------------------------------------------------
1002
1003  /**
1004   * Returns the common super type of the two given types. The default implementation of this method
1005   * <i>loads</i> the two given classes and uses the java.lang.Class methods to find the common
1006   * super class. It can be overridden to compute this common super type in other ways, in
1007   * particular without actually loading any class, or to take into account the class that is
1008   * currently being generated by this ClassWriter, which can of course not be loaded since it is
1009   * under construction.
1010   *
1011   * @param type1 the internal name of a class.
1012   * @param type2 the internal name of another class.
1013   * @return the internal name of the common super class of the two given classes.
1014   */
1015  protected String getCommonSuperClass(final String type1, final String type2) {
1016    ClassLoader classLoader = getClassLoader();
1017    Class<?> class1;
1018    try {
1019      class1 = Class.forName(type1.replace('/', '.'), false, classLoader);
1020    } catch (ClassNotFoundException e) {
1021      throw new TypeNotPresentException(type1, e);
1022    }
1023    Class<?> class2;
1024    try {
1025      class2 = Class.forName(type2.replace('/', '.'), false, classLoader);
1026    } catch (ClassNotFoundException e) {
1027      throw new TypeNotPresentException(type2, e);
1028    }
1029    if (class1.isAssignableFrom(class2)) {
1030      return type1;
1031    }
1032    if (class2.isAssignableFrom(class1)) {
1033      return type2;
1034    }
1035    if (class1.isInterface() || class2.isInterface()) {
1036      return "java/lang/Object";
1037    } else {
1038      do {
1039        class1 = class1.getSuperclass();
1040      } while (!class1.isAssignableFrom(class2));
1041      return class1.getName().replace('.', '/');
1042    }
1043  }
1044
1045  /**
1046   * Returns the {@link ClassLoader} to be used by the default implementation of {@link
1047   * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
1048   * default.
1049   *
1050   * @return ClassLoader
1051   */
1052  protected ClassLoader getClassLoader() {
1053    // SPRING PATCH: prefer thread context ClassLoader for application classes
1054    ClassLoader classLoader = null;
1055    try {
1056      classLoader = Thread.currentThread().getContextClassLoader();
1057    } catch (Throwable ex) {
1058      // Cannot access thread context ClassLoader - falling back...
1059    }
1060    return (classLoader != null ? classLoader : getClass().getClassLoader());
1061  }
1062}