• 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 non standard class, field, method or Code attribute, as defined in the Java Virtual Machine
32  * Specification (JVMS).
33  *
34  * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS
35  *     4.7</a>
36  * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
37  *     4.7.3</a>
38  * @author Eric Bruneton
39  * @author Eugene Kuleshov
40  */
41 public class Attribute {
42 
43   /** The type of this attribute, also called its name in the JVMS. */
44   public final String type;
45 
46   /**
47    * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
48    * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
49    * included.
50    */
51   private byte[] content;
52 
53   /**
54    * The next attribute in this attribute list (Attribute instances can be linked via this field to
55    * store a list of class, field, method or Code attributes). May be {@literal null}.
56    */
57   Attribute nextAttribute;
58 
59   /**
60    * Constructs a new empty attribute.
61    *
62    * @param type the type of the attribute.
63    */
Attribute(final String type)64   protected Attribute(final String type) {
65     this.type = type;
66   }
67 
68   /**
69    * Returns {@literal true} if this type of attribute is unknown. This means that the attribute
70    * content can't be parsed to extract constant pool references, labels, etc. Instead, the
71    * attribute content is read as an opaque byte array, and written back as is. This can lead to
72    * invalid attributes, if the content actually contains constant pool references, labels, or other
73    * symbolic references that need to be updated when there are changes to the constant pool, the
74    * method bytecode, etc. The default implementation of this method always returns {@literal true}.
75    *
76    * @return {@literal true} if this type of attribute is unknown.
77    */
isUnknown()78   public boolean isUnknown() {
79     return true;
80   }
81 
82   /**
83    * Returns {@literal true} if this type of attribute is a Code attribute.
84    *
85    * @return {@literal true} if this type of attribute is a Code attribute.
86    */
isCodeAttribute()87   public boolean isCodeAttribute() {
88     return false;
89   }
90 
91   /**
92    * Returns the labels corresponding to this attribute.
93    *
94    * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
95    *     a Code attribute that contains labels.
96    */
getLabels()97   protected Label[] getLabels() {
98     return new Label[0];
99   }
100 
101   /**
102    * Reads a {@link #type} attribute. This method must return a <i>new</i> {@link Attribute} object,
103    * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given
104    * ClassReader.
105    *
106    * @param classReader the class that contains the attribute to be read.
107    * @param offset index of the first byte of the attribute's content in {@link ClassReader}. The 6
108    *     attribute header bytes (attribute_name_index and attribute_length) are not taken into
109    *     account here.
110    * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
111    * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
112    *     'charBuffer' parameter.
113    * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
114    *     in {@link ClassReader}, or -1 if the attribute to be read is not a Code attribute. The 6
115    *     attribute header bytes (attribute_name_index and attribute_length) are not taken into
116    *     account here.
117    * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
118    *     is not a Code attribute.
119    * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
120    */
read( final ClassReader classReader, final int offset, final int length, final char[] charBuffer, final int codeAttributeOffset, final Label[] labels)121   protected Attribute read(
122       final ClassReader classReader,
123       final int offset,
124       final int length,
125       final char[] charBuffer,
126       final int codeAttributeOffset,
127       final Label[] labels) {
128     Attribute attribute = new Attribute(type);
129     attribute.content = new byte[length];
130     System.arraycopy(classReader.classFileBuffer, offset, attribute.content, 0, length);
131     return attribute;
132   }
133 
134   /**
135    * Returns the byte array form of the content of this attribute. The 6 header bytes
136    * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
137    * ByteVector.
138    *
139    * @param classWriter the class to which this attribute must be added. This parameter can be used
140    *     to add the items that corresponds to this attribute to the constant pool of this class.
141    * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
142    *     if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
143    *     attribute.
144    * @param codeLength the length of the bytecode of the method corresponding to this code
145    *     attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length'
146    *     field of the Code attribute.
147    * @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
148    *     -1 if this attribute is not a Code attribute.
149    * @param maxLocals the maximum number of local variables of the method corresponding to this code
150    *     attribute, or -1 if this attribute is not a Code attribute.
151    * @return the byte array form of this attribute.
152    */
write( final ClassWriter classWriter, final byte[] code, final int codeLength, final int maxStack, final int maxLocals)153   protected ByteVector write(
154       final ClassWriter classWriter,
155       final byte[] code,
156       final int codeLength,
157       final int maxStack,
158       final int maxLocals) {
159     return new ByteVector(content);
160   }
161 
162   /**
163    * Returns the number of attributes of the attribute list that begins with this attribute.
164    *
165    * @return the number of attributes of the attribute list that begins with this attribute.
166    */
getAttributeCount()167   final int getAttributeCount() {
168     int count = 0;
169     Attribute attribute = this;
170     while (attribute != null) {
171       count += 1;
172       attribute = attribute.nextAttribute;
173     }
174     return count;
175   }
176 
177   /**
178    * Returns the total size in bytes of all the attributes in the attribute list that begins with
179    * this attribute. This size includes the 6 header bytes (attribute_name_index and
180    * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
181    *
182    * @param symbolTable where the constants used in the attributes must be stored.
183    * @return the size of all the attributes in this attribute list. This size includes the size of
184    *     the attribute headers.
185    */
computeAttributesSize(final SymbolTable symbolTable)186   final int computeAttributesSize(final SymbolTable symbolTable) {
187     final byte[] code = null;
188     final int codeLength = 0;
189     final int maxStack = -1;
190     final int maxLocals = -1;
191     return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals);
192   }
193 
194   /**
195    * Returns the total size in bytes of all the attributes in the attribute list that begins with
196    * this attribute. This size includes the 6 header bytes (attribute_name_index and
197    * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
198    *
199    * @param symbolTable where the constants used in the attributes must be stored.
200    * @param code the bytecode of the method corresponding to these Code attributes, or {@literal
201    *     null} if they are not Code attributes. Corresponds to the 'code' field of the Code
202    *     attribute.
203    * @param codeLength the length of the bytecode of the method corresponding to these code
204    *     attributes, or 0 if they are not Code attributes. Corresponds to the 'code_length' field of
205    *     the Code attribute.
206    * @param maxStack the maximum stack size of the method corresponding to these Code attributes, or
207    *     -1 if they are not Code attributes.
208    * @param maxLocals the maximum number of local variables of the method corresponding to these
209    *     Code attributes, or -1 if they are not Code attribute.
210    * @return the size of all the attributes in this attribute list. This size includes the size of
211    *     the attribute headers.
212    */
computeAttributesSize( final SymbolTable symbolTable, final byte[] code, final int codeLength, final int maxStack, final int maxLocals)213   final int computeAttributesSize(
214       final SymbolTable symbolTable,
215       final byte[] code,
216       final int codeLength,
217       final int maxStack,
218       final int maxLocals) {
219     final ClassWriter classWriter = symbolTable.classWriter;
220     int size = 0;
221     Attribute attribute = this;
222     while (attribute != null) {
223       symbolTable.addConstantUtf8(attribute.type);
224       size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
225       attribute = attribute.nextAttribute;
226     }
227     return size;
228   }
229 
230   /**
231    * Returns the total size in bytes of all the attributes that correspond to the given field,
232    * method or class access flags and signature. This size includes the 6 header bytes
233    * (attribute_name_index and attribute_length) per attribute. Also adds the attribute type names
234    * to the constant pool.
235    *
236    * @param symbolTable where the constants used in the attributes must be stored.
237    * @param accessFlags some field, method or class access flags.
238    * @param signatureIndex the constant pool index of a field, method of class signature.
239    * @return the size of all the attributes in bytes. This size includes the size of the attribute
240    *     headers.
241    */
computeAttributesSize( final SymbolTable symbolTable, final int accessFlags, final int signatureIndex)242   static int computeAttributesSize(
243       final SymbolTable symbolTable, final int accessFlags, final int signatureIndex) {
244     int size = 0;
245     // Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
246     if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
247         && symbolTable.getMajorVersion() < Opcodes.V1_5) {
248       // Synthetic attributes always use 6 bytes.
249       symbolTable.addConstantUtf8(Constants.SYNTHETIC);
250       size += 6;
251     }
252     if (signatureIndex != 0) {
253       // Signature attributes always use 8 bytes.
254       symbolTable.addConstantUtf8(Constants.SIGNATURE);
255       size += 8;
256     }
257     // ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
258     if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
259       // Deprecated attributes always use 6 bytes.
260       symbolTable.addConstantUtf8(Constants.DEPRECATED);
261       size += 6;
262     }
263     return size;
264   }
265 
266   /**
267    * Puts all the attributes of the attribute list that begins with this attribute, in the given
268    * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
269    * attribute.
270    *
271    * @param symbolTable where the constants used in the attributes must be stored.
272    * @param output where the attributes must be written.
273    */
putAttributes(final SymbolTable symbolTable, final ByteVector output)274   final void putAttributes(final SymbolTable symbolTable, final ByteVector output) {
275     final byte[] code = null;
276     final int codeLength = 0;
277     final int maxStack = -1;
278     final int maxLocals = -1;
279     putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output);
280   }
281 
282   /**
283    * Puts all the attributes of the attribute list that begins with this attribute, in the given
284    * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
285    * attribute.
286    *
287    * @param symbolTable where the constants used in the attributes must be stored.
288    * @param code the bytecode of the method corresponding to these Code attributes, or {@literal
289    *     null} if they are not Code attributes. Corresponds to the 'code' field of the Code
290    *     attribute.
291    * @param codeLength the length of the bytecode of the method corresponding to these code
292    *     attributes, or 0 if they are not Code attributes. Corresponds to the 'code_length' field of
293    *     the Code attribute.
294    * @param maxStack the maximum stack size of the method corresponding to these Code attributes, or
295    *     -1 if they are not Code attributes.
296    * @param maxLocals the maximum number of local variables of the method corresponding to these
297    *     Code attributes, or -1 if they are not Code attribute.
298    * @param output where the attributes must be written.
299    */
putAttributes( final SymbolTable symbolTable, final byte[] code, final int codeLength, final int maxStack, final int maxLocals, final ByteVector output)300   final void putAttributes(
301       final SymbolTable symbolTable,
302       final byte[] code,
303       final int codeLength,
304       final int maxStack,
305       final int maxLocals,
306       final ByteVector output) {
307     final ClassWriter classWriter = symbolTable.classWriter;
308     Attribute attribute = this;
309     while (attribute != null) {
310       ByteVector attributeContent =
311           attribute.write(classWriter, code, codeLength, maxStack, maxLocals);
312       // Put attribute_name_index and attribute_length.
313       output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
314       output.putByteArray(attributeContent.data, 0, attributeContent.length);
315       attribute = attribute.nextAttribute;
316     }
317   }
318 
319   /**
320    * Puts all the attributes that correspond to the given field, method or class access flags and
321    * signature, in the given byte vector. This includes the 6 header bytes (attribute_name_index and
322    * attribute_length) per attribute.
323    *
324    * @param symbolTable where the constants used in the attributes must be stored.
325    * @param accessFlags some field, method or class access flags.
326    * @param signatureIndex the constant pool index of a field, method of class signature.
327    * @param output where the attributes must be written.
328    */
putAttributes( final SymbolTable symbolTable, final int accessFlags, final int signatureIndex, final ByteVector output)329   static void putAttributes(
330       final SymbolTable symbolTable,
331       final int accessFlags,
332       final int signatureIndex,
333       final ByteVector output) {
334     // Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
335     if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
336         && symbolTable.getMajorVersion() < Opcodes.V1_5) {
337       output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
338     }
339     if (signatureIndex != 0) {
340       output
341           .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
342           .putInt(2)
343           .putShort(signatureIndex);
344     }
345     if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
346       output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
347     }
348   }
349 
350   /** A set of attribute prototypes (attributes with the same type are considered equal). */
351   static final class Set {
352 
353     private static final int SIZE_INCREMENT = 6;
354 
355     private int size;
356     private Attribute[] data = new Attribute[SIZE_INCREMENT];
357 
addAttributes(final Attribute attributeList)358     void addAttributes(final Attribute attributeList) {
359       Attribute attribute = attributeList;
360       while (attribute != null) {
361         if (!contains(attribute)) {
362           add(attribute);
363         }
364         attribute = attribute.nextAttribute;
365       }
366     }
367 
toArray()368     Attribute[] toArray() {
369       Attribute[] result = new Attribute[size];
370       System.arraycopy(data, 0, result, 0, size);
371       return result;
372     }
373 
contains(final Attribute attribute)374     private boolean contains(final Attribute attribute) {
375       for (int i = 0; i < size; ++i) {
376         if (data[i].type.equals(attribute.type)) {
377           return true;
378         }
379       }
380       return false;
381     }
382 
add(final Attribute attribute)383     private void add(final Attribute attribute) {
384       if (size >= data.length) {
385         Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT];
386         System.arraycopy(data, 0, newData, 0, size);
387         data = newData;
388       }
389       data[size++] = attribute;
390     }
391   }
392 }
393