@@ -44,11 +44,11 @@ public class Attribute {
44
44
public final String type ;
45
45
46
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.
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.
50
50
*/
51
- private byte [] content ;
51
+ private ByteVector cachedContent ;
52
52
53
53
/**
54
54
* The next attribute in this attribute list (Attribute instances can be linked via this field to
@@ -93,7 +93,9 @@ public boolean isCodeAttribute() {
93
93
*
94
94
* @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
95
95
* a Code attribute that contains labels.
96
+ * @deprecated no longer used by ASM.
96
97
*/
98
+ @ Deprecated
97
99
protected Label [] getLabels () {
98
100
return new Label [0 ];
99
101
}
@@ -115,7 +117,9 @@ protected Label[] getLabels() {
115
117
* attribute header bytes (attribute_name_index and attribute_length) are not taken into
116
118
* account here.
117
119
* @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).
119
123
* @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
120
124
*/
121
125
protected Attribute read (
@@ -126,16 +130,99 @@ protected Attribute read(
126
130
final int codeAttributeOffset ,
127
131
final Label [] labels ) {
128
132
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 ));
131
134
return attribute ;
132
135
}
133
136
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
+
134
218
/**
135
219
* Returns the byte array form of the content of this attribute. The 6 header bytes
136
220
* (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
137
221
* ByteVector.
138
222
*
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
+ *
139
226
* @param classWriter the class to which this attribute must be added. This parameter can be used
140
227
* to add the items that corresponds to this attribute to the constant pool of this class.
141
228
* @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
@@ -156,7 +243,39 @@ protected ByteVector write(
156
243
final int codeLength ,
157
244
final int maxStack ,
158
245
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 ;
160
279
}
161
280
162
281
/**
@@ -221,7 +340,7 @@ final int computeAttributesSize(
221
340
Attribute attribute = this ;
222
341
while (attribute != null ) {
223
342
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 ;
225
344
attribute = attribute .nextAttribute ;
226
345
}
227
346
return size ;
@@ -308,7 +427,7 @@ final void putAttributes(
308
427
Attribute attribute = this ;
309
428
while (attribute != null ) {
310
429
ByteVector attributeContent =
311
- attribute .write (classWriter , code , codeLength , maxStack , maxLocals );
430
+ attribute .maybeWrite (classWriter , code , codeLength , maxStack , maxLocals );
312
431
// Put attribute_name_index and attribute_length.
313
432
output .putShort (symbolTable .addConstantUtf8 (attribute .type )).putInt (attributeContent .length );
314
433
output .putByteArray (attributeContent .data , 0 , attributeContent .length );
0 commit comments