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