• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ASM: a very small and fast Java bytecode manipulation framework
2 // Copyright (c) 2000-2011 INRIA, France Telecom
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holders nor the names of its
14 //    contributors may be used to endorse or promote products derived from
15 //    this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 // THE POSSIBILITY OF SUCH DAMAGE.
28 package org.objectweb.asm;
29 
30 final class RecordComponentWriter extends RecordComponentVisitor {
31   /** Where the constants used in this RecordComponentWriter must be stored. */
32   private final SymbolTable symbolTable;
33 
34   // Note: fields are ordered as in the record_component_info structure, and those related to
35   // attributes are ordered as in Section 4.7 of the JVMS.
36 
37   /** The name_index field of the Record attribute. */
38   private final int nameIndex;
39 
40   /** The descriptor_index field of the Record attribute. */
41   private final int descriptorIndex;
42 
43   /**
44    * The signature_index field of the Signature attribute of this record component, or 0 if there is
45    * no Signature attribute.
46    */
47   private int signatureIndex;
48 
49   /**
50    * The last runtime visible annotation of this record component. The previous ones can be accessed
51    * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
52    */
53   private AnnotationWriter lastRuntimeVisibleAnnotation;
54 
55   /**
56    * The last runtime invisible annotation of this record component. The previous ones can be
57    * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
58    */
59   private AnnotationWriter lastRuntimeInvisibleAnnotation;
60 
61   /**
62    * The last runtime visible type annotation of this record component. The previous ones can be
63    * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
64    */
65   private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
66 
67   /**
68    * The last runtime invisible type annotation of this record component. The previous ones can be
69    * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
70    */
71   private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
72 
73   /**
74    * The first non standard attribute of this record component. The next ones can be accessed with
75    * the {@link Attribute#nextAttribute} field. May be {@literal null}.
76    *
77    * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
78    * firstAttribute is actually the last attribute visited in {@link #visitAttribute(Attribute)}.
79    * The {@link #putRecordComponentInfo(ByteVector)} method writes the attributes in the order
80    * defined by this list, i.e. in the reverse order specified by the user.
81    */
82   private Attribute firstAttribute;
83 
84   /**
85    * Constructs a new {@link RecordComponentWriter}.
86    *
87    * @param symbolTable where the constants used in this RecordComponentWriter must be stored.
88    * @param name the record component name.
89    * @param descriptor the record component descriptor (see {@link Type}).
90    * @param signature the record component signature. May be {@literal null}.
91    */
RecordComponentWriter( final SymbolTable symbolTable, final String name, final String descriptor, final String signature)92   RecordComponentWriter(
93       final SymbolTable symbolTable,
94       final String name,
95       final String descriptor,
96       final String signature) {
97     super(/* latest api = */ Opcodes.ASM9);
98     this.symbolTable = symbolTable;
99     this.nameIndex = symbolTable.addConstantUtf8(name);
100     this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
101     if (signature != null) {
102       this.signatureIndex = symbolTable.addConstantUtf8(signature);
103     }
104   }
105 
106   // -----------------------------------------------------------------------------------------------
107   // Implementation of the FieldVisitor abstract class
108   // -----------------------------------------------------------------------------------------------
109 
110   @Override
visitAnnotation(final String descriptor, final boolean visible)111   public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
112     if (visible) {
113       return lastRuntimeVisibleAnnotation =
114           AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
115     } else {
116       return lastRuntimeInvisibleAnnotation =
117           AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
118     }
119   }
120 
121   @Override
visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)122   public AnnotationVisitor visitTypeAnnotation(
123       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
124     if (visible) {
125       return lastRuntimeVisibleTypeAnnotation =
126           AnnotationWriter.create(
127               symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
128     } else {
129       return lastRuntimeInvisibleTypeAnnotation =
130           AnnotationWriter.create(
131               symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
132     }
133   }
134 
135   @Override
visitAttribute(final Attribute attribute)136   public void visitAttribute(final Attribute attribute) {
137     // Store the attributes in the <i>reverse</i> order of their visit by this method.
138     attribute.nextAttribute = firstAttribute;
139     firstAttribute = attribute;
140   }
141 
142   @Override
visitEnd()143   public void visitEnd() {
144     // Nothing to do.
145   }
146 
147   // -----------------------------------------------------------------------------------------------
148   // Utility methods
149   // -----------------------------------------------------------------------------------------------
150 
151   /**
152    * Returns the size of the record component JVMS structure generated by this
153    * RecordComponentWriter. Also adds the names of the attributes of this record component in the
154    * constant pool.
155    *
156    * @return the size in bytes of the record_component_info of the Record attribute.
157    */
computeRecordComponentInfoSize()158   int computeRecordComponentInfoSize() {
159     // name_index, descriptor_index and attributes_count fields use 6 bytes.
160     int size = 6;
161     size += Attribute.computeAttributesSize(symbolTable, 0, signatureIndex);
162     size +=
163         AnnotationWriter.computeAnnotationsSize(
164             lastRuntimeVisibleAnnotation,
165             lastRuntimeInvisibleAnnotation,
166             lastRuntimeVisibleTypeAnnotation,
167             lastRuntimeInvisibleTypeAnnotation);
168     if (firstAttribute != null) {
169       size += firstAttribute.computeAttributesSize(symbolTable);
170     }
171     return size;
172   }
173 
174   /**
175    * Puts the content of the record component generated by this RecordComponentWriter into the given
176    * ByteVector.
177    *
178    * @param output where the record_component_info structure must be put.
179    */
putRecordComponentInfo(final ByteVector output)180   void putRecordComponentInfo(final ByteVector output) {
181     output.putShort(nameIndex).putShort(descriptorIndex);
182     // Compute and put the attributes_count field.
183     // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
184     int attributesCount = 0;
185     if (signatureIndex != 0) {
186       ++attributesCount;
187     }
188     if (lastRuntimeVisibleAnnotation != null) {
189       ++attributesCount;
190     }
191     if (lastRuntimeInvisibleAnnotation != null) {
192       ++attributesCount;
193     }
194     if (lastRuntimeVisibleTypeAnnotation != null) {
195       ++attributesCount;
196     }
197     if (lastRuntimeInvisibleTypeAnnotation != null) {
198       ++attributesCount;
199     }
200     if (firstAttribute != null) {
201       attributesCount += firstAttribute.getAttributeCount();
202     }
203     output.putShort(attributesCount);
204     Attribute.putAttributes(symbolTable, 0, signatureIndex, output);
205     AnnotationWriter.putAnnotations(
206         symbolTable,
207         lastRuntimeVisibleAnnotation,
208         lastRuntimeInvisibleAnnotation,
209         lastRuntimeVisibleTypeAnnotation,
210         lastRuntimeInvisibleTypeAnnotation,
211         output);
212     if (firstAttribute != null) {
213       firstAttribute.putAttributes(symbolTable, output);
214     }
215   }
216 
217   /**
218    * Collects the attributes of this record component into the given set of attribute prototypes.
219    *
220    * @param attributePrototypes a set of attribute prototypes.
221    */
collectAttributePrototypes(final Attribute.Set attributePrototypes)222   final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
223     attributePrototypes.addAttributes(firstAttribute);
224   }
225 }
226