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