@@ -44,11 +44,11 @@ public class Attribute {
4444 public final String type ;
4545
4646 /**
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.
47+ * The raw content of this attribute, as returned by {@link
48+ * #write(ClassWriter,byte[],int,int,int)}. The 6 header bytes of the attribute
49+ * (attribute_name_index and attribute_length) are <i>not</i> included.
5050 */
51- private byte [] content ;
51+ private ByteVector cachedContent ;
5252
5353 /**
5454 * The next attribute in this attribute list (Attribute instances can be linked via this field to
@@ -93,7 +93,9 @@ public boolean isCodeAttribute() {
9393 *
9494 * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
9595 * a Code attribute that contains labels.
96+ * @deprecated no longer used by ASM.
9697 */
98+ @ Deprecated
9799 protected Label [] getLabels () {
98100 return new Label [0 ];
99101 }
@@ -115,7 +117,9 @@ protected Label[] getLabels() {
115117 * attribute header bytes (attribute_name_index and attribute_length) are not taken into
116118 * account here.
117119 * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
118- * is not a Code attribute.
120+ * is not a Code attribute. Labels defined in the attribute must be created and added to this
121+ * array, if not already present, by calling the {@link #readLabel} method (do not create
122+ * {@link Label} instances directly).
119123 * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
120124 */
121125 protected Attribute read (
@@ -126,16 +130,99 @@ protected Attribute read(
126130 final int codeAttributeOffset ,
127131 final Label [] labels ) {
128132 Attribute attribute = new Attribute (type );
129- attribute .content = new byte [length ];
130- System .arraycopy (classReader .classFileBuffer , offset , attribute .content , 0 , length );
133+ attribute .cachedContent = new ByteVector (classReader .readBytes (offset , length ));
131134 return attribute ;
132135 }
133136
137+ /**
138+ * Reads an attribute with the same {@link #type} as the given attribute. This method returns a
139+ * new {@link Attribute} object, corresponding to the 'length' bytes starting at 'offset', in the
140+ * given ClassReader.
141+ *
142+ * @param attribute The attribute prototype that is used for reading.
143+ * @param classReader the class that contains the attribute to be read.
144+ * @param offset index of the first byte of the attribute's content in {@link ClassReader}. The 6
145+ * attribute header bytes (attribute_name_index and attribute_length) are not taken into
146+ * account here.
147+ * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
148+ * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
149+ * 'charBuffer' parameter.
150+ * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
151+ * in {@link ClassReader}, or -1 if the attribute to be read is not a Code attribute. The 6
152+ * attribute header bytes (attribute_name_index and attribute_length) are not taken into
153+ * account here.
154+ * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
155+ * is not a Code attribute. Labels defined in the attribute are added to this array, if not
156+ * already present.
157+ * @return a new {@link Attribute} object corresponding to the specified bytes.
158+ */
159+ public static Attribute read (
160+ final Attribute attribute ,
161+ final ClassReader classReader ,
162+ final int offset ,
163+ final int length ,
164+ final char [] charBuffer ,
165+ final int codeAttributeOffset ,
166+ final Label [] labels ) {
167+ return attribute .read (classReader , offset , length , charBuffer , codeAttributeOffset , labels );
168+ }
169+
170+ /**
171+ * Returns the label corresponding to the given bytecode offset by calling {@link
172+ * ClassReader#readLabel}. This creates and adds the label to the given array if it is not already
173+ * present. Note that this created label may be a {@link Label} subclass instance, if the given
174+ * ClassReader overrides {@link ClassReader#readLabel}. Hence {@link #read(ClassReader, int, int,
175+ * char[], int, Label[])} must not manually create {@link Label} instances.
176+ *
177+ * @param bytecodeOffset a bytecode offset in a method.
178+ * @param labels the already created labels, indexed by their offset. If a label already exists
179+ * for bytecodeOffset this method does not create a new one. Otherwise it stores the new label
180+ * in this array.
181+ * @return a label for the given bytecode offset.
182+ */
183+ public static Label readLabel (
184+ final ClassReader classReader , final int bytecodeOffset , final Label [] labels ) {
185+ return classReader .readLabel (bytecodeOffset , labels );
186+ }
187+
188+ /**
189+ * Calls {@link #write(ClassWriter,byte[],int,int,int)} if it has not already been called and
190+ * returns its result or its (cached) previous result.
191+ *
192+ * @param classWriter the class to which this attribute must be added. This parameter can be used
193+ * to add the items that corresponds to this attribute to the constant pool of this class.
194+ * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
195+ * if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
196+ * attribute.
197+ * @param codeLength the length of the bytecode of the method corresponding to this code
198+ * attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length'
199+ * field of the Code attribute.
200+ * @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
201+ * -1 if this attribute is not a Code attribute.
202+ * @param maxLocals the maximum number of local variables of the method corresponding to this code
203+ * attribute, or -1 if this attribute is not a Code attribute.
204+ * @return the byte array form of this attribute.
205+ */
206+ private ByteVector maybeWrite (
207+ final ClassWriter classWriter ,
208+ final byte [] code ,
209+ final int codeLength ,
210+ final int maxStack ,
211+ final int maxLocals ) {
212+ if (cachedContent == null ) {
213+ cachedContent = write (classWriter , code , codeLength , maxStack , maxLocals );
214+ }
215+ return cachedContent ;
216+ }
217+
134218 /**
135219 * Returns the byte array form of the content of this attribute. The 6 header bytes
136220 * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
137221 * ByteVector.
138222 *
223+ * <p>This method is only invoked once to compute the binary form of this attribute. Subsequent
224+ * changes to the attribute after it was written for the first time will not be considered.
225+ *
139226 * @param classWriter the class to which this attribute must be added. This parameter can be used
140227 * to add the items that corresponds to this attribute to the constant pool of this class.
141228 * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
@@ -156,7 +243,39 @@ protected ByteVector write(
156243 final int codeLength ,
157244 final int maxStack ,
158245 final int maxLocals ) {
159- return new ByteVector (content );
246+ return cachedContent ;
247+ }
248+
249+ /**
250+ * Returns the byte array form of the content of the given attribute. The 6 header bytes
251+ * (attribute_name_index and attribute_length) are <i>not</i> added in the returned byte array.
252+ *
253+ * @param attribute The attribute that should be written.
254+ * @param classWriter the class to which this attribute must be added. This parameter can be used
255+ * to add the items that corresponds to this attribute to the constant pool of this class.
256+ * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
257+ * if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
258+ * attribute.
259+ * @param codeLength the length of the bytecode of the method corresponding to this code
260+ * attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length'
261+ * field of the Code attribute.
262+ * @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
263+ * -1 if this attribute is not a Code attribute.
264+ * @param maxLocals the maximum number of local variables of the method corresponding to this code
265+ * attribute, or -1 if this attribute is not a Code attribute.
266+ * @return the byte array form of this attribute.
267+ */
268+ public static byte [] write (
269+ final Attribute attribute ,
270+ final ClassWriter classWriter ,
271+ final byte [] code ,
272+ final int codeLength ,
273+ final int maxStack ,
274+ final int maxLocals ) {
275+ ByteVector content = attribute .maybeWrite (classWriter , code , codeLength , maxStack , maxLocals );
276+ byte [] result = new byte [content .length ];
277+ System .arraycopy (content .data , 0 , result , 0 , content .length );
278+ return result ;
160279 }
161280
162281 /**
@@ -221,7 +340,7 @@ final int computeAttributesSize(
221340 Attribute attribute = this ;
222341 while (attribute != null ) {
223342 symbolTable .addConstantUtf8 (attribute .type );
224- size += 6 + attribute .write (classWriter , code , codeLength , maxStack , maxLocals ).length ;
343+ size += 6 + attribute .maybeWrite (classWriter , code , codeLength , maxStack , maxLocals ).length ;
225344 attribute = attribute .nextAttribute ;
226345 }
227346 return size ;
@@ -308,7 +427,7 @@ final void putAttributes(
308427 Attribute attribute = this ;
309428 while (attribute != null ) {
310429 ByteVector attributeContent =
311- attribute .write (classWriter , code , codeLength , maxStack , maxLocals );
430+ attribute .maybeWrite (classWriter , code , codeLength , maxStack , maxLocals );
312431 // Put attribute_name_index and attribute_length.
313432 output .putShort (symbolTable .addConstantUtf8 (attribute .type )).putInt (attributeContent .length );
314433 output .putByteArray (attributeContent .data , 0 , attributeContent .length );
0 commit comments