Skip to content

Commit 8f6d26f

Browse files
authored
Merge pull request #217 from ebean-orm/feature/asm971
Update to ASM 9.7.1
2 parents c035b80 + 2fe80c7 commit 8f6d26f

15 files changed

+221
-55
lines changed

ebean-agent/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<groupId>io.ebean</groupId>
1111
<artifactId>ebean-agent</artifactId>
12-
<version>14.6.1</version>
12+
<version>14.7.0</version>
1313
<packaging>jar</packaging>
1414

1515
<name>ebean-agent</name>

ebean-agent/src/main/java/io/ebean/enhance/asm/Attribute.java

Lines changed: 129 additions & 10 deletions
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);

ebean-agent/src/main/java/io/ebean/enhance/asm/ClassReader.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ public ClassReader(
195195
this.b = classFileBuffer;
196196
// Check the class' major_version. This field is after the magic and minor_version fields, which
197197
// use 4 and 2 bytes respectively.
198-
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V23) {
198+
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V24) {
199199
throw new IllegalArgumentException(
200200
"Unsupported class file major version " + readShort(classFileOffset + 6));
201201
}
@@ -3597,6 +3597,20 @@ public int readByte(final int offset) {
35973597
return classFileBuffer[offset] & 0xFF;
35983598
}
35993599

3600+
/**
3601+
* Reads several bytes in this {@link ClassReader}. <i>This method is intended for {@link
3602+
* Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
3603+
*
3604+
* @param offset the start offset of the bytes to be read in this {@link ClassReader}.
3605+
* @param length the number of bytes to read.
3606+
* @return the read bytes.
3607+
*/
3608+
public byte[] readBytes(final int offset, final int length) {
3609+
byte[] result = new byte[length];
3610+
System.arraycopy(classFileBuffer, offset, result, 0, length);
3611+
return result;
3612+
}
3613+
36003614
/**
36013615
* Reads an unsigned short value in this {@link ClassReader}. <i>This method is intended for
36023616
* {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>

ebean-agent/src/main/java/io/ebean/enhance/asm/ClassWriter.java

Lines changed: 23 additions & 7 deletions
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
// -----------------------------------------------------------------------------------------------

ebean-agent/src/main/java/io/ebean/enhance/asm/Constants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ static void checkIsPreview(final InputStream classInputStream) {
215215
}
216216
if (minorVersion != 0xFFFF) {
217217
throw new IllegalStateException(
218-
"ASM9_EXPERIMENTAL can only be used by classes compiled with --enable-preview");
218+
"ASM10_EXPERIMENTAL can only be used by classes compiled with --enable-preview");
219219
}
220220
}
221221
}

ebean-agent/src/main/java/io/ebean/enhance/asm/MethodVisitor.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@
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
*/

ebean-agent/src/main/java/io/ebean/enhance/asm/Opcodes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ public interface Opcodes {
289289
int V21 = 0 << 16 | 65;
290290
int V22 = 0 << 16 | 66;
291291
int V23 = 0 << 16 | 67;
292+
int V24 = 0 << 16 | 68;
292293

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

ebean-agent/src/main/java/io/ebean/enhance/asm/Symbol.java

Lines changed: 3 additions & 1 deletion
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)