Skip to content

Commit 864cb25

Browse files
committed
Upgrade to ASM 9.7.1
Closes gh-33821
1 parent e23c8bf commit 864cb25

File tree

7 files changed

+215
-39
lines changed

7 files changed

+215
-39
lines changed

spring-core/src/main/java/org/springframework/asm/Attribute.java

+129-10
Original file line numberDiff line numberDiff line change
@@ -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);

spring-core/src/main/java/org/springframework/asm/ClassReader.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,14 @@ public ClassReader(
188188
* @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
189189
* @param checkClassVersion whether to check the class version or not.
190190
*/
191+
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
191192
ClassReader(
192193
final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) {
193194
this.classFileBuffer = classFileBuffer;
194195
this.b = classFileBuffer;
195196
// Check the class' major_version. This field is after the magic and minor_version fields, which
196197
// use 4 and 2 bytes respectively.
197-
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V23) {
198+
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V24) {
198199
throw new IllegalArgumentException(
199200
"Unsupported class file major version " + readShort(classFileOffset + 6));
200201
}
@@ -340,7 +341,7 @@ private static byte[] readStream(final InputStream inputStream, final boolean cl
340341
private static int computeBufferSize(final InputStream inputStream) throws IOException {
341342
int expectedLength = inputStream.available();
342343
/*
343-
* Some implementations can return 0 while holding available data (for example, new
344+
* Some implementations can return 0 while holding available data (e.g. new
344345
* FileInputStream("/proc/a_file")). Also in some pathological cases a very small number might
345346
* be returned, and in this case we use a default size.
346347
*/
@@ -2311,7 +2312,7 @@ private void readCode(
23112312
{
23122313
// A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO
23132314
// with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:...,
2314-
// where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (for example, IFNE for ASM_IFEQ) and
2315+
// where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and
23152316
// where <L> designates the instruction just after the GOTO_W.
23162317
// First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and
23172318
// ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL.
@@ -3603,6 +3604,20 @@ public int readByte(final int offset) {
36033604
return classFileBuffer[offset] & 0xFF;
36043605
}
36053606

3607+
/**
3608+
* Reads several bytes in this {@link ClassReader}. <i>This method is intended for {@link
3609+
* Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
3610+
*
3611+
* @param offset the start offset of the bytes to be read in this {@link ClassReader}.
3612+
* @param length the number of bytes to read.
3613+
* @return the read bytes.
3614+
*/
3615+
public byte[] readBytes(final int offset, final int length) {
3616+
byte[] result = new byte[length];
3617+
System.arraycopy(classFileBuffer, offset, result, 0, length);
3618+
return result;
3619+
}
3620+
36063621
/**
36073622
* Reads an unsigned short value in this {@link ClassReader}. <i>This method is intended for
36083623
* {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>

spring-core/src/main/java/org/springframework/asm/ClassWriter.java

+23-7
Original file line numberDiff line numberDiff line change
@@ -264,13 +264,7 @@ public ClassWriter(final ClassReader classReader, final int flags) {
264264
super(/* latest api = */ Opcodes.ASM9);
265265
this.flags = flags;
266266
symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
267-
if ((flags & COMPUTE_FRAMES) != 0) {
268-
compute = MethodWriter.COMPUTE_ALL_FRAMES;
269-
} else if ((flags & COMPUTE_MAXS) != 0) {
270-
compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
271-
} else {
272-
compute = MethodWriter.COMPUTE_NOTHING;
273-
}
267+
setFlags(flags);
274268
}
275269

276270
// -----------------------------------------------------------------------------------------------
@@ -1020,6 +1014,28 @@ public int newNameType(final String name, final String descriptor) {
10201014
return symbolTable.addConstantNameAndType(name, descriptor);
10211015
}
10221016

1017+
/**
1018+
* Changes the computation strategy of method properties like max stack size, max number of local
1019+
* variables, and frames.
1020+
*
1021+
* <p><b>WARNING</b>: {@link #setFlags(int)} method changes the behavior of new method visitors
1022+
* returned from {@link #visitMethod(int, String, String, String, String[])}. The behavior will be
1023+
* changed only after the next method visitor is returned. All the previously returned method
1024+
* visitors keep their previous behavior.
1025+
*
1026+
* @param flags option flags that can be used to modify the default behavior of this class. Must
1027+
* be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}.
1028+
*/
1029+
public final void setFlags(final int flags) {
1030+
if ((flags & ClassWriter.COMPUTE_FRAMES) != 0) {
1031+
compute = MethodWriter.COMPUTE_ALL_FRAMES;
1032+
} else if ((flags & ClassWriter.COMPUTE_MAXS) != 0) {
1033+
compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
1034+
} else {
1035+
compute = MethodWriter.COMPUTE_NOTHING;
1036+
}
1037+
}
1038+
10231039
// -----------------------------------------------------------------------------------------------
10241040
// Default method to compute common super classes when computing stack map frames
10251041
// -----------------------------------------------------------------------------------------------

spring-core/src/main/java/org/springframework/asm/MethodVisitor.java

+11-10
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,20 @@
3030
/**
3131
* A visitor to visit a Java method. The methods of this class must be called in the following
3232
* order: ( {@code visitParameter} )* [ {@code visitAnnotationDefault} ] ( {@code visitAnnotation} |
33-
* {@code visitAnnotableParameterCount} | {@code visitParameterAnnotation} {@code
33+
* {@code visitAnnotableParameterCount} | {@code visitParameterAnnotation} | {@code
3434
* visitTypeAnnotation} | {@code visitAttribute} )* [ {@code visitCode} ( {@code visitFrame} |
3535
* {@code visit<i>X</i>Insn} | {@code visitLabel} | {@code visitInsnAnnotation} | {@code
3636
* visitTryCatchBlock} | {@code visitTryCatchAnnotation} | {@code visitLocalVariable} | {@code
37-
* visitLocalVariableAnnotation} | {@code visitLineNumber} )* {@code visitMaxs} ] {@code visitEnd}.
38-
* In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel} methods must be called in the
39-
* sequential order of the bytecode instructions of the visited code, {@code visitInsnAnnotation}
40-
* must be called <i>after</i> the annotated instruction, {@code visitTryCatchBlock} must be called
41-
* <i>before</i> the labels passed as arguments have been visited, {@code
42-
* visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try catch block has
43-
* been visited, and the {@code visitLocalVariable}, {@code visitLocalVariableAnnotation} and {@code
44-
* visitLineNumber} methods must be called <i>after</i> the labels passed as arguments have been
45-
* visited.
37+
* visitLocalVariableAnnotation} | {@code visitLineNumber} | {@code visitAttribute} )* {@code
38+
* visitMaxs} ] {@code visitEnd}. In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel}
39+
* methods must be called in the sequential order of the bytecode instructions of the visited code,
40+
* {@code visitInsnAnnotation} must be called <i>after</i> the annotated instruction, {@code
41+
* visitTryCatchBlock} must be called <i>before</i> the labels passed as arguments have been
42+
* visited, {@code visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try
43+
* catch block has been visited, and the {@code visitLocalVariable}, {@code
44+
* visitLocalVariableAnnotation} and {@code visitLineNumber} methods must be called <i>after</i> the
45+
* labels passed as arguments have been visited. Finally, the {@code visitAttribute} method must be
46+
* called before {@code visitCode} for non-code attributes, and after it for code attributes.
4647
*
4748
* @author Eric Bruneton
4849
*/

spring-core/src/main/java/org/springframework/asm/Opcodes.java

+1
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ public interface Opcodes {
288288
int V21 = 0 << 16 | 65;
289289
int V22 = 0 << 16 | 66;
290290
int V23 = 0 << 16 | 67;
291+
int V24 = 0 << 16 | 68;
291292

292293
/**
293294
* Version flag indicating that the class is using 'preview' features.

spring-core/src/main/java/org/springframework/asm/Symbol.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,9 @@ abstract class Symbol {
178178
* <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link
179179
* #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG},
180180
* <li>the CONSTANT_MethodHandle_info reference_kind field value for {@link
181-
* #CONSTANT_METHOD_HANDLE_TAG} symbols,
181+
* #CONSTANT_METHOD_HANDLE_TAG} symbols (or this value left shifted by 8 bits for
182+
* reference_kind values larger than or equal to H_INVOKEVIRTUAL and if the method owner is
183+
* an interface),
182184
* <li>the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link
183185
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
184186
* <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for

0 commit comments

Comments
 (0)