summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Bruneton <ebruneton@free.fr>2022-09-11 09:14:12 +0200
committerEric Bruneton <ebruneton@free.fr>2022-09-11 09:14:12 +0200
commitd3c9ced1a5697c3f7a30eec0d492c5ff09d3b334 (patch)
tree5025016f05680f22f3f840cbafa0ac161d349d57
parent965c0069c2ed9818c2ee91469ec3ef0e8534c36b (diff)
parentedb880104a5f2b1a918b0da3ee668febe0ba45bb (diff)
downloadow2-asm-d3c9ced1a5697c3f7a30eec0d492c5ff09d3b334.tar.gz
Merge branch 'asm-fix/signature-writer/use-unsigned-arg-stack'
-rw-r--r--asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java33
-rw-r--r--asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java15
2 files changed, 35 insertions, 13 deletions
diff --git a/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java b/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java
index 2217a88a..df5f61d0 100644
--- a/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java
+++ b/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java
@@ -41,7 +41,7 @@ import org.objectweb.asm.Opcodes;
public class SignatureWriter extends SignatureVisitor {
/** The builder used to construct the visited signature. */
- private final StringBuilder stringBuilder = new StringBuilder();
+ private final StringBuilder stringBuilder;
/** Whether the visited signature contains formal type parameters. */
private boolean hasFormals;
@@ -51,8 +51,9 @@ public class SignatureWriter extends SignatureVisitor {
/**
* The stack used to keep track of class types that have arguments. Each element of this stack is
- * a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false
- * = *2, pushing true = *2+1, popping = /2.
+ * a boolean encoded in one bit. The top of the stack is the least significant bit. The bottom of
+ * the stack is a sentinel element always equal to 1 (used to detect when the stack is full).
+ * Pushing false = {@code <<= 1}, pushing true = {@code '( <<= 1) | 1}, popping = {@code >>>= 1}.
*
* <p>Class type arguments must be surrounded with '&lt;' and '&gt;' and, because
*
@@ -62,15 +63,20 @@ public class SignatureWriter extends SignatureVisitor {
* SignatureWriter instances),
* </ol>
*
- * <p>we need a stack to properly balance these 'parentheses'. A new element is pushed on this
- * stack for each new visited type, and popped when the visit of this type ends (either is
+ * <p>we need a stack to properly balance these angle brackets. A new element is pushed on this
+ * stack for each new visited type, and popped when the visit of this type ends (either in
* visitEnd, or because visitInnerClassType is called).
*/
- private int argumentStack;
+ private int argumentStack = 1;
/** Constructs a new {@link SignatureWriter}. */
public SignatureWriter() {
+ this(new StringBuilder());
+ }
+
+ private SignatureWriter(final StringBuilder stringBuilder) {
super(/* latest api =*/ Opcodes.ASM9);
+ this.stringBuilder = stringBuilder;
}
// -----------------------------------------------------------------------------------------------
@@ -159,7 +165,7 @@ public class SignatureWriter extends SignatureVisitor {
stringBuilder.append(name);
// Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as
// we can tell at this point).
- argumentStack *= 2;
+ argumentStack <<= 1;
}
@Override
@@ -169,7 +175,7 @@ public class SignatureWriter extends SignatureVisitor {
stringBuilder.append(name);
// Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as
// we can tell at this point).
- argumentStack *= 2;
+ argumentStack <<= 1;
}
@Override
@@ -177,7 +183,7 @@ public class SignatureWriter extends SignatureVisitor {
// If the top of the stack is 'false', this means we are visiting the first type argument of the
// currently visited type. We therefore need to append a '<', and to replace the top stack
// element with 'true' (meaning that the current type does have type arguments).
- if (argumentStack % 2 == 0) {
+ if ((argumentStack & 1) == 0) {
argumentStack |= 1;
stringBuilder.append('<');
}
@@ -189,14 +195,15 @@ public class SignatureWriter extends SignatureVisitor {
// If the top of the stack is 'false', this means we are visiting the first type argument of the
// currently visited type. We therefore need to append a '<', and to replace the top stack
// element with 'true' (meaning that the current type does have type arguments).
- if (argumentStack % 2 == 0) {
+ if ((argumentStack & 1) == 0) {
argumentStack |= 1;
stringBuilder.append('<');
}
if (wildcard != '=') {
stringBuilder.append(wildcard);
}
- return this;
+ // If the stack is full, start a nested one by returning a new SignatureWriter.
+ return (argumentStack & (1 << 31)) == 0 ? this : new SignatureWriter(stringBuilder);
}
@Override
@@ -232,9 +239,9 @@ public class SignatureWriter extends SignatureVisitor {
// If the top of the stack is 'true', this means that some type arguments have been visited for
// the type whose visit is now ending. We therefore need to append a '>', and to pop one element
// from the stack.
- if (argumentStack % 2 == 1) {
+ if ((argumentStack & 1) == 1) {
stringBuilder.append('>');
}
- argumentStack /= 2;
+ argumentStack >>>= 1;
}
}
diff --git a/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java b/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java
index ce6cf22a..a04d5801 100644
--- a/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java
+++ b/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java
@@ -32,6 +32,9 @@ public final class SignaturesProviders {
assertFalse(CLASS_SIGNATURES.isEmpty());
assertFalse(FIELD_SIGNATURES.isEmpty());
assertFalse(METHOD_SIGNATURES.isEmpty());
+ for (int depth = 0; depth < 48; ++depth) {
+ METHOD_SIGNATURES.add(buildDeepSignature(new StringBuilder(), depth).toString());
+ }
}
private SignaturesProviders() {}
@@ -82,6 +85,18 @@ public final class SignaturesProviders {
0);
}
+ private static StringBuilder buildDeepSignature(final StringBuilder signature, final int depth) {
+ signature.append("LGeneric");
+ if (depth == 0) {
+ signature.append(';');
+ } else {
+ signature.append("<LOpen;");
+ buildDeepSignature(signature, depth - 1);
+ signature.append("LClose;>;");
+ }
+ return signature;
+ }
+
static Stream<String> classSignatures() {
return CLASS_SIGNATURES.stream();
}