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 non standard class, field, method or Code attribute, as defined in the Java Virtual Machine 032 * Specification (JVMS). 033 * 034 * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS 035 * 4.7</a> 036 * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS 037 * 4.7.3</a> 038 * @author Eric Bruneton 039 * @author Eugene Kuleshov 040 */ 041public class Attribute { 042 043 /** The type of this attribute, also called its name in the JVMS. */ 044 public final String type; 045 046 /** 047 * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}). 048 * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i> 049 * included. 050 */ 051 private byte[] content; 052 053 /** 054 * The next attribute in this attribute list (Attribute instances can be linked via this field to 055 * store a list of class, field, method or Code attributes). May be {@literal null}. 056 */ 057 Attribute nextAttribute; 058 059 /** 060 * Constructs a new empty attribute. 061 * 062 * @param type the type of the attribute. 063 */ 064 protected Attribute(final String type) { 065 this.type = type; 066 } 067 068 /** 069 * Returns {@literal true} if this type of attribute is unknown. This means that the attribute 070 * content can't be parsed to extract constant pool references, labels, etc. Instead, the 071 * attribute content is read as an opaque byte array, and written back as is. This can lead to 072 * invalid attributes, if the content actually contains constant pool references, labels, or other 073 * symbolic references that need to be updated when there are changes to the constant pool, the 074 * method bytecode, etc. The default implementation of this method always returns {@literal true}. 075 * 076 * @return {@literal true} if this type of attribute is unknown. 077 */ 078 public boolean isUnknown() { 079 return true; 080 } 081 082 /** 083 * Returns {@literal true} if this type of attribute is a Code attribute. 084 * 085 * @return {@literal true} if this type of attribute is a Code attribute. 086 */ 087 public boolean isCodeAttribute() { 088 return false; 089 } 090 091 /** 092 * Returns the labels corresponding to this attribute. 093 * 094 * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not 095 * a Code attribute that contains labels. 096 */ 097 protected Label[] getLabels() { 098 return new Label[0]; 099 } 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 368 Attribute[] toArray() { 369 Attribute[] result = new Attribute[size]; 370 System.arraycopy(data, 0, result, 0, size); 371 return result; 372 } 373 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 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}