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