asm-analysis Frame allocates an array unnecessarily inside executeInvokeInsn
When profiling my application, I've noticed that more than 1% of my analysis CPU time is spent on this line: https://gitlab.ow2.org/asm/asm/-/blob/master/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java?ref_type=heads#L675
int i = Type.getArgumentTypes(methodDescriptor).length
Here, we create a complete array of argument types (sometimes, along with Type
objects themselves), only to read its length. This looks wasteful. It would be nice to have a method inside Type
or somewhere else, which simply returns the number of arguments, so it could be used here. Something like this:
diff --git a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java
--- a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java (revision 2e22cefc43c0d274d97b7e0135e97bb4825b9e85)
+++ b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java (date 1694700910626)
@@ -672,7 +672,7 @@
final AbstractInsnNode insn, final String methodDescriptor, final Interpreter<V> interpreter)
throws AnalyzerException {
ArrayList<V> valueList = new ArrayList<>();
- for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
+ for (int i = Type.getArgumentCount(methodDescriptor); i > 0; --i) {
valueList.add(0, pop());
}
if (insn.getOpcode() != Opcodes.INVOKESTATIC && insn.getOpcode() != Opcodes.INVOKEDYNAMIC) {
Index: asm/src/main/java/org/objectweb/asm/Type.java
===================================================================
diff --git a/asm/src/main/java/org/objectweb/asm/Type.java b/asm/src/main/java/org/objectweb/asm/Type.java
--- a/asm/src/main/java/org/objectweb/asm/Type.java (revision 2e22cefc43c0d274d97b7e0135e97bb4825b9e85)
+++ b/asm/src/main/java/org/objectweb/asm/Type.java (date 1694700872437)
@@ -295,21 +295,8 @@
*/
public static Type[] getArgumentTypes(final String methodDescriptor) {
// First step: compute the number of argument types in methodDescriptor.
- int numArgumentTypes = 0;
- // Skip the first character, which is always a '('.
- int currentOffset = 1;
- // Parse the argument types, one at a each loop iteration.
- while (methodDescriptor.charAt(currentOffset) != ')') {
- while (methodDescriptor.charAt(currentOffset) == '[') {
- currentOffset++;
- }
- if (methodDescriptor.charAt(currentOffset++) == 'L') {
- // Skip the argument descriptor content.
- int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
- currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
- }
- ++numArgumentTypes;
- }
+ int numArgumentTypes = getArgumentCount(methodDescriptor);
+ int currentOffset;
// Second step: create a Type instance for each argument type.
Type[] argumentTypes = new Type[numArgumentTypes];
@@ -333,6 +320,31 @@
return argumentTypes;
}
+ /**
+ * Returns the number of arguments of the given method descriptor.
+ *
+ * @param methodDescriptor a method descriptor.
+ * @return the number of arguments of the given method descriptor.
+ */
+ public static int getArgumentCount(String methodDescriptor) {
+ int numArgumentTypes = 0;
+ // Skip the first character, which is always a '('.
+ int currentOffset = 1;
+ // Parse the argument types, one at a each loop iteration.
+ while (methodDescriptor.charAt(currentOffset) != ')') {
+ while (methodDescriptor.charAt(currentOffset) == '[') {
+ currentOffset++;
+ }
+ if (methodDescriptor.charAt(currentOffset++) == 'L') {
+ // Skip the argument descriptor content.
+ int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
+ currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
+ }
+ ++numArgumentTypes;
+ }
+ return numArgumentTypes;
+ }
+
/**
* Returns the {@link Type} values corresponding to the argument types of the given method.
*
Thank you in advance.