[Git][java-team/asm][upstream] 2 commits: New upstream version 9.10

Emmanuel Bourg (@ebourg) gitlab at salsa.debian.org
Fri Sep 18 14:21:29 BST 2026



Emmanuel Bourg pushed to branch upstream at Debian Java Maintainers / asm


Commits:
f04a1bf7 by Emmanuel Bourg at 2026-09-18T14:56:14+02:00
New upstream version 9.10
- - - - -
edbc7f58 by Emmanuel Bourg at 2026-09-18T15:03:12+02:00
New upstream version 9.10.1
- - - - -


25 changed files:

- asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Analyzer.java
- asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Subroutine.java
- asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Value.java
- asm-commons/src/test/java/org/objectweb/asm/commons/LambdaRemapTest.java
- asm-commons/src/test/java/org/objectweb/asm/commons/MethodNodeBuilder.java
- asm-test/src/main/java/org/objectweb/asm/test/ClassFile.java
- asm-test/src/main/java/org/objectweb/asm/test/Util.java
- asm-test/src/test/java/org/objectweb/asm/test/ClassFileTest.java
- asm-tree/src/main/java/org/objectweb/asm/tree/InsnList.java
- asm-util/src/main/java/org/objectweb/asm/util/ASMifier.java
- asm-util/src/main/java/org/objectweb/asm/util/ASMifierSupport.java
- asm-util/src/main/java/org/objectweb/asm/util/CheckFrameAnalyzer.java
- asm-util/src/main/java/org/objectweb/asm/util/Textifier.java
- asm-util/src/main/java/org/objectweb/asm/util/TextifierSupport.java
- asm-util/src/main/java/org/objectweb/asm/util/TraceSignatureVisitor.java
- asm-util/src/test/java/org/objectweb/asm/util/TraceSignatureVisitorTest.java
- asm/src/main/java/org/objectweb/asm/ClassReader.java
- asm/src/main/java/org/objectweb/asm/Frame.java
- asm/src/main/java/org/objectweb/asm/Opcodes.java
- asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java
- asm/src/test/java/org/objectweb/asm/ConstantsTest.java
- benchmarks/src/jmh/java/org/objectweb/asm/benchmarks/AbstractBenchmark.java
- build.gradle
- tools/pmd.xml
- tools/retrofitter/src/main/java/org/objectweb/asm/tools/Retrofitter.java


Changes:

=====================================
asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Analyzer.java
=====================================
@@ -119,15 +119,14 @@ public class Analyzer<V extends Value> implements Opcodes {
 
     // For each exception handler, and each instruction within its range, record in 'handlers' the
     // fact that execution can flow from this instruction to the exception handler.
-    for (int i = 0; i < method.tryCatchBlocks.size(); ++i) {
-      TryCatchBlockNode tryCatchBlock = method.tryCatchBlocks.get(i);
+    for (TryCatchBlockNode tryCatchBlock : method.tryCatchBlocks) {
       int startIndex = insnList.indexOf(tryCatchBlock.start);
       int endIndex = insnList.indexOf(tryCatchBlock.end);
-      for (int j = startIndex; j < endIndex; ++j) {
-        List<TryCatchBlockNode> insnHandlers = handlers[j];
+      for (int i = startIndex; i < endIndex; ++i) {
+        List<TryCatchBlockNode> insnHandlers = handlers[i];
         if (insnHandlers == null) {
           insnHandlers = new ArrayList<>();
-          handlers[j] = insnHandlers;
+          handlers[i] = insnHandlers;
         }
         insnHandlers.add(tryCatchBlock);
       }
@@ -197,8 +196,7 @@ public class Analyzer<V extends Value> implements Opcodes {
             currentFrame.initJumpTarget(insnOpcode, lookupSwitchInsn.dflt);
             merge(targetInsnIndex, currentFrame, subroutine);
             newControlFlowEdge(insnIndex, targetInsnIndex);
-            for (int i = 0; i < lookupSwitchInsn.labels.size(); ++i) {
-              LabelNode label = lookupSwitchInsn.labels.get(i);
+            for (LabelNode label : lookupSwitchInsn.labels) {
               targetInsnIndex = insnList.indexOf(label);
               currentFrame.initJumpTarget(insnOpcode, label);
               merge(targetInsnIndex, currentFrame, subroutine);
@@ -210,8 +208,7 @@ public class Analyzer<V extends Value> implements Opcodes {
             currentFrame.initJumpTarget(insnOpcode, tableSwitchInsn.dflt);
             merge(targetInsnIndex, currentFrame, subroutine);
             newControlFlowEdge(insnIndex, targetInsnIndex);
-            for (int i = 0; i < tableSwitchInsn.labels.size(); ++i) {
-              LabelNode label = tableSwitchInsn.labels.get(i);
+            for (LabelNode label : tableSwitchInsn.labels) {
               currentFrame.initJumpTarget(insnOpcode, label);
               targetInsnIndex = insnList.indexOf(label);
               merge(targetInsnIndex, currentFrame, subroutine);
@@ -221,8 +218,7 @@ public class Analyzer<V extends Value> implements Opcodes {
             if (subroutine == null) {
               throw new AnalyzerException(insnNode, "RET instruction outside of a subroutine");
             }
-            for (int i = 0; i < subroutine.callers.size(); ++i) {
-              JumpInsnNode caller = subroutine.callers.get(i);
+            for (JumpInsnNode caller : subroutine.callers) {
               int jsrInsnIndex = insnList.indexOf(caller);
               if (frames[jsrInsnIndex] != null) {
                 merge(


=====================================
asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Subroutine.java
=====================================
@@ -93,8 +93,7 @@ final class Subroutine {
       }
     }
     if (subroutine.start == start) {
-      for (int i = 0; i < subroutine.callers.size(); ++i) {
-        JumpInsnNode caller = subroutine.callers.get(i);
+      for (JumpInsnNode caller : subroutine.callers) {
         if (!callers.contains(caller)) {
           callers.add(caller);
           changed = true;


=====================================
asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Value.java
=====================================
@@ -32,6 +32,7 @@ package org.objectweb.asm.tree.analysis;
  *
  * @author Eric Bruneton
  */
+ at FunctionalInterface
 public interface Value {
 
   /**


=====================================
asm-commons/src/test/java/org/objectweb/asm/commons/LambdaRemapTest.java
=====================================
@@ -63,11 +63,9 @@ class LambdaRemapTest extends AsmTest implements Opcodes {
             "metafactory",
             LAMBDA_FACTORY_METAFACTORY,
             false),
-        new Object[] {
-          Type.getType("()V"),
-          new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false),
-          Type.getType("()V")
-        });
+        Type.getType("()V"),
+        new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false),
+        Type.getType("()V"));
   }
 
   void func_serializableLambda(final MethodVisitor methodVisitor) {
@@ -80,13 +78,11 @@ class LambdaRemapTest extends AsmTest implements Opcodes {
             "altMetafactory",
             LAMBDA_FACTORY_ALTMETAFACTORY,
             false),
-        new Object[] {
-          Type.getType("()V"),
-          new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false),
-          Type.getType("()V"),
-          Integer.valueOf(5),
-          Integer.valueOf(0)
-        });
+        Type.getType("()V"),
+        new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false),
+        Type.getType("()V"),
+        Integer.valueOf(5),
+        Integer.valueOf(0));
   }
 
   void func_advancedLambda(final MethodVisitor methodVisitor) {
@@ -99,15 +95,13 @@ class LambdaRemapTest extends AsmTest implements Opcodes {
             "altMetafactory",
             LAMBDA_FACTORY_ALTMETAFACTORY,
             false),
-        new Object[] {
-          Type.getType("()V"),
-          new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false),
-          Type.getType("()V"),
-          Integer.valueOf(7),
-          Integer.valueOf(1),
-          Type.getType("Lpkg/LambdaTest$TestInterface;"),
-          Integer.valueOf(0)
-        });
+        Type.getType("()V"),
+        new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false),
+        Type.getType("()V"),
+        Integer.valueOf(7),
+        Integer.valueOf(1),
+        Type.getType("Lpkg/LambdaTest$TestInterface;"),
+        Integer.valueOf(0));
   }
 
   public static Stream<Remapper> remappersLatest() {


=====================================
asm-commons/src/test/java/org/objectweb/asm/commons/MethodNodeBuilder.java
=====================================
@@ -191,7 +191,7 @@ final class MethodNodeBuilder {
   MethodNodeBuilder switchto(
       final Label defaultLabel, final int key, final Label target, final boolean useTableSwitch) {
     if (useTableSwitch) {
-      methodNode.visitTableSwitchInsn(key, key, defaultLabel, new Label[] {target});
+      methodNode.visitTableSwitchInsn(key, key, defaultLabel, target);
     } else {
       methodNode.visitLookupSwitchInsn(defaultLabel, new int[] {key}, new Label[] {target});
     }
@@ -200,7 +200,7 @@ final class MethodNodeBuilder {
 
   MethodNodeBuilder switchto(final Label label0, final Label label1, final boolean useTableSwitch) {
     if (useTableSwitch) {
-      methodNode.visitTableSwitchInsn(0, 1, label0, new Label[] {label0, label1});
+      methodNode.visitTableSwitchInsn(0, 1, label0, label0, label1);
     } else {
       methodNode.visitLookupSwitchInsn(label0, new int[] {1}, new Label[] {label1});
     }


=====================================
asm-test/src/main/java/org/objectweb/asm/test/ClassFile.java
=====================================
@@ -2356,11 +2356,13 @@ public class ClassFile {
   }
 
   /** A context to lookup constant pool items from their index. */
+  @FunctionalInterface
   private interface ClassContext {
     <C extends CpInfo> C getCpInfo(int cpIndex, Class<C> cpInfoType);
   }
 
   /** A context to lookup instruction indices from their bytecode offset. */
+  @FunctionalInterface
   private interface MethodContext {
     int getInsnIndex(int bytecodeOffset);
   }
@@ -2526,6 +2528,7 @@ public class ClassFile {
      * @param opcode a bytecode instruction opcode.
      * @param arguments the bytecode instruction arguments.
      */
+    @SuppressWarnings("PMD.UseArraysAsList") // false positive
     void addInsn(final int insnIndex, final int opcode, final Object... arguments) {
       children.add(insnIndex);
       children.add(": ");


=====================================
asm-test/src/main/java/org/objectweb/asm/test/Util.java
=====================================
@@ -26,6 +26,7 @@ final class Util {
     return Integer.parseInt(javaMajorVersionText);
   }
 
+  @SuppressWarnings("PMD.PreserveStackTrace")
   static boolean previewFeatureEnabled() {
     try {
       Class<?> managementFactoryClass = Class.forName("java.lang.management.ManagementFactory");


=====================================
asm-test/src/test/java/org/objectweb/asm/test/ClassFileTest.java
=====================================
@@ -62,6 +62,7 @@ class ClassFileTest extends AsmTest {
    */
   @ParameterizedTest
   @EnumSource(InvalidClass.class)
+  @SuppressWarnings("PMD.ExhaustiveSwitchHasDefault") // Checkstyle complains if default is missing!
   void testStaticNewInstance_invalidClass(final InvalidClass invalidClass) {
     String className = invalidClass.toString();
     byte[] classContent = invalidClass.getBytes();


=====================================
asm-tree/src/main/java/org/objectweb/asm/tree/InsnList.java
=====================================
@@ -226,7 +226,6 @@ public class InsnList implements Iterable<AbstractInsnNode> {
     ++size;
     if (lastInsn == null) {
       firstInsn = insnNode;
-      lastInsn = insnNode;
     } else {
       lastInsn.nextInsn = insnNode;
       insnNode.previousInsn = lastInsn;
@@ -268,7 +267,6 @@ public class InsnList implements Iterable<AbstractInsnNode> {
   public void insert(final AbstractInsnNode insnNode) {
     ++size;
     if (firstInsn == null) {
-      firstInsn = insnNode;
       lastInsn = insnNode;
     } else {
       firstInsn.previousInsn = insnNode;


=====================================
asm-util/src/main/java/org/objectweb/asm/util/ASMifier.java
=====================================
@@ -116,6 +116,7 @@ public class ASMifier extends Printer {
     classVersions.put(Opcodes.V24, "V24");
     classVersions.put(Opcodes.V25, "V25");
     classVersions.put(Opcodes.V26, "V26");
+    classVersions.put(Opcodes.V27, "V27");
     CLASS_VERSIONS = Collections.unmodifiableMap(classVersions);
   }
 
@@ -273,8 +274,7 @@ public class ASMifier extends Printer {
   @Override
   public Printer visitModule(final String name, final int flags, final String version) {
     stringBuilder.setLength(0);
-    stringBuilder.append("{\n");
-    stringBuilder.append("ModuleVisitor moduleVisitor = classWriter.visitModule(");
+    stringBuilder.append("{\nModuleVisitor moduleVisitor = classWriter.visitModule(");
     appendConstant(name);
     stringBuilder.append(", ");
     appendAccessFlags(flags | ACCESS_MODULE);
@@ -364,8 +364,7 @@ public class ASMifier extends Printer {
   public ASMifier visitRecordComponent(
       final String name, final String descriptor, final String signature) {
     stringBuilder.setLength(0);
-    stringBuilder.append("{\n");
-    stringBuilder.append("recordComponentVisitor = classWriter.visitRecordComponent(");
+    stringBuilder.append("{\nrecordComponentVisitor = classWriter.visitRecordComponent(");
     appendConstant(name);
     stringBuilder.append(", ");
     appendConstant(descriptor);
@@ -387,8 +386,7 @@ public class ASMifier extends Printer {
       final String signature,
       final Object value) {
     stringBuilder.setLength(0);
-    stringBuilder.append("{\n");
-    stringBuilder.append("fieldVisitor = classWriter.visitField(");
+    stringBuilder.append("{\nfieldVisitor = classWriter.visitField(");
     appendAccessFlags(access | ACCESS_FIELD);
     stringBuilder.append(", ");
     appendConstant(name);
@@ -414,8 +412,7 @@ public class ASMifier extends Printer {
       final String signature,
       final String[] exceptions) {
     stringBuilder.setLength(0);
-    stringBuilder.append("{\n");
-    stringBuilder.append("methodVisitor = classWriter.visitMethod(");
+    stringBuilder.append("{\nmethodVisitor = classWriter.visitMethod(");
     appendAccessFlags(access);
     stringBuilder.append(", ");
     appendConstant(name);
@@ -575,11 +572,11 @@ public class ASMifier extends Printer {
   public ASMifier visitAnnotation(final String name, final String descriptor) {
     stringBuilder.setLength(0);
     stringBuilder
-        .append("{\n")
-        .append("AnnotationVisitor annotationVisitor")
+        .append("{\nAnnotationVisitor annotationVisitor")
         .append(id + 1)
-        .append(" = annotationVisitor");
-    stringBuilder.append(id).append(".visitAnnotation(");
+        .append(" = annotationVisitor")
+        .append(id)
+        .append(".visitAnnotation(");
     appendConstant(name);
     stringBuilder.append(", ");
     appendConstant(descriptor);
@@ -594,12 +591,12 @@ public class ASMifier extends Printer {
   @Override
   public ASMifier visitArray(final String name) {
     stringBuilder.setLength(0);
-    stringBuilder.append("{\n");
     stringBuilder
-        .append("AnnotationVisitor annotationVisitor")
+        .append("{\nAnnotationVisitor annotationVisitor")
         .append(id + 1)
-        .append(" = annotationVisitor");
-    stringBuilder.append(id).append(".visitArray(");
+        .append(" = annotationVisitor")
+        .append(id)
+        .append(".visitArray(");
     appendConstant(name);
     stringBuilder.append(");\n");
     text.add(stringBuilder.toString());
@@ -887,9 +884,7 @@ public class ASMifier extends Printer {
     appendConstant(name);
     stringBuilder.append(", ");
     appendConstant(descriptor);
-    stringBuilder.append(", ");
-    stringBuilder.append(isInterface ? "true" : "false");
-    stringBuilder.append(");\n");
+    stringBuilder.append(", ").append(isInterface ? "true" : "false").append(");\n");
     text.add(stringBuilder.toString());
   }
 
@@ -1244,8 +1239,7 @@ public class ASMifier extends Printer {
       }
       stringBuilder.append("{\n");
       ((ASMifierSupport) attribute).asmify(stringBuilder, "attribute", labelNames);
-      stringBuilder.append(name).append(".visitAttribute(attribute);\n");
-      stringBuilder.append("}\n");
+      stringBuilder.append(name).append(".visitAttribute(attribute);\n}\n");
     }
     text.add(stringBuilder.toString());
   }
@@ -1449,22 +1443,30 @@ public class ASMifier extends Printer {
     } else if (value instanceof String) {
       appendString(stringBuilder, (String) value);
     } else if (value instanceof Type) {
-      stringBuilder.append("Type.getType(\"");
-      stringBuilder.append(((Type) value).getDescriptor());
-      stringBuilder.append("\")");
+      stringBuilder.append("Type.getType(\"").append(((Type) value).getDescriptor()).append("\")");
     } else if (value instanceof Handle) {
       stringBuilder.append("new Handle(");
       Handle handle = (Handle) value;
-      stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \"");
-      stringBuilder.append(handle.getOwner()).append(COMMA);
-      stringBuilder.append(handle.getName()).append(COMMA);
-      stringBuilder.append(handle.getDesc()).append("\", ");
-      stringBuilder.append(handle.isInterface()).append(')');
+      stringBuilder
+          .append("Opcodes.")
+          .append(HANDLE_TAG[handle.getTag()])
+          .append(", \"")
+          .append(handle.getOwner())
+          .append(COMMA)
+          .append(handle.getName())
+          .append(COMMA)
+          .append(handle.getDesc())
+          .append("\", ")
+          .append(handle.isInterface())
+          .append(')');
     } else if (value instanceof ConstantDynamic) {
       stringBuilder.append("new ConstantDynamic(\"");
       ConstantDynamic constantDynamic = (ConstantDynamic) value;
-      stringBuilder.append(constantDynamic.getName()).append(COMMA);
-      stringBuilder.append(constantDynamic.getDescriptor()).append("\", ");
+      stringBuilder
+          .append(constantDynamic.getName())
+          .append(COMMA)
+          .append(constantDynamic.getDescriptor())
+          .append("\", ");
       appendConstant(constantDynamic.getBootstrapMethod());
       stringBuilder.append(NEW_OBJECT_ARRAY);
       int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();


=====================================
asm-util/src/main/java/org/objectweb/asm/util/ASMifierSupport.java
=====================================
@@ -30,6 +30,7 @@ import org.objectweb.asm.Label;
  *
  * @author Eugene Kuleshov
  */
+ at FunctionalInterface
 // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
 public interface ASMifierSupport {
 


=====================================
asm-util/src/main/java/org/objectweb/asm/util/CheckFrameAnalyzer.java
=====================================
@@ -158,8 +158,7 @@ class CheckFrameAnalyzer<V extends Value> extends Analyzer<V> {
             LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) insnNode;
             int targetInsnIndex = insnList.indexOf(lookupSwitchInsn.dflt);
             checkFrame(targetInsnIndex, currentFrame, /* requireFrame= */ true);
-            for (int i = 0; i < lookupSwitchInsn.labels.size(); ++i) {
-              LabelNode label = lookupSwitchInsn.labels.get(i);
+            for (LabelNode label : lookupSwitchInsn.labels) {
               targetInsnIndex = insnList.indexOf(label);
               currentFrame.initJumpTarget(insnOpcode, label);
               checkFrame(targetInsnIndex, currentFrame, /* requireFrame= */ true);
@@ -171,8 +170,7 @@ class CheckFrameAnalyzer<V extends Value> extends Analyzer<V> {
             currentFrame.initJumpTarget(insnOpcode, tableSwitchInsn.dflt);
             checkFrame(targetInsnIndex, currentFrame, /* requireFrame= */ true);
             newControlFlowEdge(insnIndex, targetInsnIndex);
-            for (int i = 0; i < tableSwitchInsn.labels.size(); ++i) {
-              LabelNode label = tableSwitchInsn.labels.get(i);
+            for (LabelNode label : tableSwitchInsn.labels) {
               currentFrame.initJumpTarget(insnOpcode, label);
               targetInsnIndex = insnList.indexOf(label);
               checkFrame(targetInsnIndex, currentFrame, /* requireFrame= */ true);


=====================================
asm-util/src/main/java/org/objectweb/asm/util/Textifier.java
=====================================
@@ -350,9 +350,7 @@ public class Textifier extends Printer {
     stringBuilder.append(tab);
 
     appendDescriptor(FIELD_DESCRIPTOR, descriptor);
-    stringBuilder.append(' ').append(name);
-
-    stringBuilder.append('\n');
+    stringBuilder.append(' ').append(name).append('\n');
     text.add(stringBuilder.toString());
     return addNewTextifier(null);
   }
@@ -500,8 +498,7 @@ public class Textifier extends Printer {
   private void visitExportOrOpen(
       final String method, final String packaze, final int access, final String... modules) {
     stringBuilder.setLength(0);
-    stringBuilder.append(tab).append(method);
-    stringBuilder.append(packaze);
+    stringBuilder.append(tab).append(method).append(packaze);
     if (modules != null && modules.length > 0) {
       stringBuilder.append(" to");
     } else {
@@ -510,8 +507,10 @@ public class Textifier extends Printer {
     appendRawAccess(access);
     if (modules != null && modules.length > 0) {
       for (int i = 0; i < modules.length; ++i) {
-        stringBuilder.append(tab2).append(modules[i]);
-        stringBuilder.append(i != modules.length - 1 ? ",\n" : ";\n");
+        stringBuilder
+            .append(tab2)
+            .append(modules[i])
+            .append(i != modules.length - 1 ? ",\n" : ";\n");
       }
     }
     text.add(stringBuilder.toString());
@@ -791,9 +790,11 @@ public class Textifier extends Printer {
   @Override
   public Textifier visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
     stringBuilder.setLength(0);
-    stringBuilder.append(tab2).append("// annotable parameter count: ");
-    stringBuilder.append(parameterCount);
-    stringBuilder.append(visible ? " (visible)\n" : " (invisible)\n");
+    stringBuilder
+        .append(tab2)
+        .append("// annotable parameter count: ")
+        .append(parameterCount)
+        .append(visible ? " (visible)\n" : " (invisible)\n");
     text.add(stringBuilder.toString());
     return this;
   }
@@ -833,8 +834,7 @@ public class Textifier extends Printer {
       final int numStack,
       final Object[] stack) {
     stringBuilder.setLength(0);
-    stringBuilder.append(ltab);
-    stringBuilder.append("FRAME ");
+    stringBuilder.append(ltab).append("FRAME ");
     switch (type) {
       case Opcodes.F_NEW:
       case Opcodes.F_FULL:
@@ -939,17 +939,13 @@ public class Textifier extends Printer {
       final Handle bootstrapMethodHandle,
       final Object... bootstrapMethodArguments) {
     stringBuilder.setLength(0);
-    stringBuilder.append(tab2).append("INVOKEDYNAMIC").append(' ');
-    stringBuilder.append(name);
+    stringBuilder.append(tab2).append("INVOKEDYNAMIC").append(' ').append(name);
     appendDescriptor(METHOD_DESCRIPTOR, descriptor);
-    stringBuilder.append(" [");
-    stringBuilder.append('\n');
-    stringBuilder.append(tab3);
+    stringBuilder.append(" [").append('\n').append(tab3);
     appendHandle(bootstrapMethodHandle, tab3);
     stringBuilder.append('\n').append(tab3);
     appendBoostrapMethodArgs(bootstrapMethodArguments, tab3);
-    stringBuilder.append('\n');
-    stringBuilder.append(tab2).append("]\n");
+    stringBuilder.append('\n').append(tab2).append("]\n");
     text.add(stringBuilder.toString());
   }
 
@@ -1075,8 +1071,7 @@ public class Textifier extends Printer {
     stringBuilder.setLength(0);
     stringBuilder.append(") : ");
     appendTypeReference(typeRef);
-    stringBuilder.append(", ").append(typePath);
-    stringBuilder.append(visible ? "\n" : INVISIBLE);
+    stringBuilder.append(", ").append(typePath).append(visible ? "\n" : INVISIBLE);
     return addNewTextifier(stringBuilder.toString());
   }
 
@@ -1204,8 +1199,7 @@ public class Textifier extends Printer {
     stringBuilder.setLength(0);
     stringBuilder.append(") : ");
     appendTypeReference(typeRef);
-    stringBuilder.append(", ").append(typePath);
-    stringBuilder.append(visible ? "\n" : INVISIBLE);
+    stringBuilder.append(", ").append(typePath).append(visible ? "\n" : INVISIBLE);
     return addNewTextifier(stringBuilder.toString());
   }
 
@@ -1324,8 +1318,9 @@ public class Textifier extends Printer {
         .append(condy.getName())
         .append(" : ")
         .append(condy.getDescriptor())
-        .append(" [\n");
-    stringBuilder.append(condyIndent).append(tab);
+        .append(" [\n")
+        .append(condyIndent)
+        .append(tab);
     appendHandle(condy.getBootstrapMethod(), condyIndent + tab);
     stringBuilder.append('\n').append(condyIndent).append(tab);
     Object[] bsmArgs = new Object[condy.getBootstrapMethodArgumentCount()];
@@ -1414,11 +1409,9 @@ public class Textifier extends Printer {
     new SignatureReader(signature).accept(traceSignatureVisitor);
     stringBuilder.append("// declaration: ");
     if (traceSignatureVisitor.getReturnType() != null) {
-      stringBuilder.append(traceSignatureVisitor.getReturnType());
-      stringBuilder.append(' ');
+      stringBuilder.append(traceSignatureVisitor.getReturnType()).append(' ');
     }
-    stringBuilder.append(name);
-    stringBuilder.append(traceSignatureVisitor.getDeclaration());
+    stringBuilder.append(name).append(traceSignatureVisitor.getDeclaration());
     if (traceSignatureVisitor.getExceptions() != null) {
       stringBuilder.append(" throws ").append(traceSignatureVisitor.getExceptions());
     }
@@ -1500,11 +1493,9 @@ public class Textifier extends Printer {
       default:
         throw new IllegalArgumentException();
     }
-    stringBuilder.append('\n');
-    stringBuilder.append(afterComment);
+    stringBuilder.append('\n').append(afterComment);
     appendDescriptor(INTERNAL_NAME, handle.getOwner());
-    stringBuilder.append('.');
-    stringBuilder.append(handle.getName());
+    stringBuilder.append('.').append(handle.getName());
     if (!isMethodHandle) {
       stringBuilder.append('(');
     }


=====================================
asm-util/src/main/java/org/objectweb/asm/util/TextifierSupport.java
=====================================
@@ -29,6 +29,7 @@ import org.objectweb.asm.Label;
  *
  * @author Eugene Kuleshov
  */
+ at FunctionalInterface
 public interface TextifierSupport {
 
   /**


=====================================
asm-util/src/main/java/org/objectweb/asm/util/TraceSignatureVisitor.java
=====================================
@@ -27,6 +27,7 @@
 // THE POSSIBILITY OF SUCH DAMAGE.
 package org.objectweb.asm.util;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -86,19 +87,17 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
   /** Whether {@link #visitInterface} has been called. */
   private boolean interfaceVisited;
 
-  /**
-   * 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.
-   */
-  private int argumentStack;
+  /** A delayed task to perform when a type or a list of type arguments has been visited. */
+  static enum Task {
+    END_ARRAY_TYPE,
+    END_EMPTY_TYPE_ARGUMENTS,
+    END_NON_EMPTY_TYPE_ARGUMENTS,
+  }
 
   /**
-   * The stack used to keep track of array class types. Each element of this stack is a boolean
-   * encoded in one bit. The top of the stack is the lowest order bit. Pushing false = *2, pushing
-   * true = *2+1, popping = /2.
+   * A stack of pending tasks to perform when a type or a list of type arguments has been visited.
    */
-  private int arrayStack;
+  private ArrayList<Task> pendingTasks = new ArrayList<>();
 
   /** The separator to append before the next visited class or inner class type. */
   private String separator = "";
@@ -130,7 +129,6 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
   @Override
   public SignatureVisitor visitClassBound() {
     separator = EXTENDS_SEPARATOR;
-    startType();
     return this;
   }
 
@@ -138,7 +136,6 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
   public SignatureVisitor visitInterfaceBound() {
     separator = interfaceBoundVisited ? COMMA_SEPARATOR : EXTENDS_SEPARATOR;
     interfaceBoundVisited = true;
-    startType();
     return this;
   }
 
@@ -146,7 +143,6 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
   public SignatureVisitor visitSuperclass() {
     endFormals();
     separator = EXTENDS_SEPARATOR;
-    startType();
     return this;
   }
 
@@ -158,7 +154,6 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
       separator = isInterface ? EXTENDS_SEPARATOR : IMPLEMENTS_SEPARATOR;
       interfaceVisited = true;
     }
-    startType();
     return this;
   }
 
@@ -171,7 +166,6 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
       declaration.append('(');
       parameterTypeVisited = true;
     }
-    startType();
     return this;
   }
 
@@ -217,8 +211,7 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
 
   @Override
   public SignatureVisitor visitArrayType() {
-    startType();
-    arrayStack |= 1;
+    pendingTasks.add(Task.END_ARRAY_TYPE);
     return this;
   }
 
@@ -227,7 +220,10 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
     if ("java/lang/Object".equals(name)) {
       // 'Map<java.lang.Object,java.util.List>' or 'abstract public V get(Object key);' should have
       // Object 'but java.lang.String extends java.lang.Object' is unnecessary.
-      boolean needObjectClass = argumentStack % 2 != 0 || parameterTypeVisited;
+      boolean needObjectClass =
+          (!pendingTasks.isEmpty()
+                  && pendingTasks.get(pendingTasks.size() - 1) == Task.END_NON_EMPTY_TYPE_ARGUMENTS)
+              || parameterTypeVisited;
       if (needObjectClass) {
         declaration.append(separator).append(name.replace('/', '.'));
       }
@@ -235,25 +231,22 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
       declaration.append(separator).append(name.replace('/', '.'));
     }
     separator = "";
-    argumentStack *= 2;
+    pendingTasks.add(Task.END_EMPTY_TYPE_ARGUMENTS);
   }
 
   @Override
   public void visitInnerClassType(final String name) {
-    if (argumentStack % 2 != 0) {
-      declaration.append('>');
-    }
-    argumentStack /= 2;
-    declaration.append('.');
-    declaration.append(separator).append(name.replace('/', '.'));
+    endTypeArguments();
+    declaration.append('.').append(separator).append(name.replace('/', '.'));
+    pendingTasks.add(Task.END_EMPTY_TYPE_ARGUMENTS);
     separator = "";
-    argumentStack *= 2;
   }
 
   @Override
   public void visitTypeArgument() {
-    if (argumentStack % 2 == 0) {
-      ++argumentStack;
+    int lastTaskIndex = pendingTasks.size() - 1;
+    if (pendingTasks.get(lastTaskIndex) == Task.END_EMPTY_TYPE_ARGUMENTS) {
+      pendingTasks.set(lastTaskIndex, Task.END_NON_EMPTY_TYPE_ARGUMENTS);
       declaration.append('<');
     } else {
       declaration.append(COMMA_SEPARATOR);
@@ -263,29 +256,24 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
 
   @Override
   public SignatureVisitor visitTypeArgument(final char tag) {
-    if (argumentStack % 2 == 0) {
-      ++argumentStack;
+    int lastTaskIndex = pendingTasks.size() - 1;
+    if (pendingTasks.get(lastTaskIndex) == Task.END_EMPTY_TYPE_ARGUMENTS) {
+      pendingTasks.set(lastTaskIndex, Task.END_NON_EMPTY_TYPE_ARGUMENTS);
       declaration.append('<');
     } else {
       declaration.append(COMMA_SEPARATOR);
     }
-
     if (tag == EXTENDS) {
       declaration.append("? extends ");
     } else if (tag == SUPER) {
       declaration.append("? super ");
     }
-
-    startType();
     return this;
   }
 
   @Override
   public void visitEnd() {
-    if (argumentStack % 2 != 0) {
-      declaration.append('>');
-    }
-    argumentStack /= 2;
+    endTypeArguments();
     endType();
   }
 
@@ -327,18 +315,17 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
     }
   }
 
-  private void startType() {
-    arrayStack *= 2;
+  private void endTypeArguments() {
+    if (pendingTasks.remove(pendingTasks.size() - 1) == Task.END_NON_EMPTY_TYPE_ARGUMENTS) {
+      declaration.append('>');
+    }
   }
 
   private void endType() {
-    if (arrayStack % 2 == 0) {
-      arrayStack /= 2;
-    } else {
-      while (arrayStack % 2 != 0) {
-        arrayStack /= 2;
-        declaration.append("[]");
-      }
+    int numTasks = pendingTasks.size();
+    while (numTasks > 0 && pendingTasks.get(--numTasks) == Task.END_ARRAY_TYPE) {
+      declaration.append("[]");
+      pendingTasks.remove(numTasks);
     }
   }
 }


=====================================
asm-util/src/test/java/org/objectweb/asm/util/TraceSignatureVisitorTest.java
=====================================
@@ -88,7 +88,8 @@ class TraceSignatureVisitorTest {
     {
       "java.util.Hashtable<java.lang.Object, java.lang.String>",
       "Ljava/util/Hashtable<Ljava/lang/Object;Ljava/lang/String;>;"
-    }
+    },
+    {"java.util.List<java.lang.Boolean[]>[][][]", "[[[Ljava/util/List<[Ljava/lang/Boolean;>;"}
   };
 
   private static final String[][] METHOD_SIGNATURES = {
@@ -119,6 +120,10 @@ class TraceSignatureVisitorTest {
     {
       "java.util.Map<java.lang.Object, java.lang.String><E, T extends java.lang.Comparable<E>>(java.lang.Object, java.util.Map<java.lang.Object, java.lang.String>, T)",
       "<E:Ljava/lang/Object;T::Ljava/lang/Comparable<TE;>;>(Ljava/lang/Object;Ljava/util/Map<Ljava/lang/Object;Ljava/lang/String;>;TT;)Ljava/util/Map<Ljava/lang/Object;Ljava/lang/String;>;"
+    },
+    {
+      "(java.util.Map<java.util.Map<java.lang.String, ? extends java.util.List<? super java.lang.Runnable>>, java.util.List<java.lang.Boolean[]>[]>)",
+      "(Ljava/util/Map<Ljava/util/Map<Ljava/lang/String;+Ljava/util/List<-Ljava/lang/Runnable;>;>;[Ljava/util/List<[Ljava/lang/Boolean;>;>;)Ljava/lang/Object;"
     }
   };
 


=====================================
asm/src/main/java/org/objectweb/asm/ClassReader.java
=====================================
@@ -195,7 +195,7 @@ public class ClassReader {
     this.b = classFileBuffer;
     // Check the class' major_version. This field is after the magic and minor_version fields, which
     // use 4 and 2 bytes respectively.
-    if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V26) {
+    if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V27) {
       throw new IllegalArgumentException(
           "Unsupported class file major version " + readShort(classFileOffset + 6));
     }


=====================================
asm/src/main/java/org/objectweb/asm/Frame.java
=====================================
@@ -577,7 +577,8 @@ class Frame {
       return outputStack[--outputStackTop];
     } else {
       // If the output frame stack is empty, pop from the input stack.
-      return STACK_KIND | -(--outputStackStart);
+      --outputStackStart;
+      return STACK_KIND | -outputStackStart;
     }
   }
 


=====================================
asm/src/main/java/org/objectweb/asm/Opcodes.java
=====================================
@@ -293,6 +293,7 @@ public interface Opcodes {
   int V24 = 0 << 16 | 68;
   int V25 = 0 << 16 | 69;
   int V26 = 0 << 16 | 70;
+  int V27 = 0 << 16 | 71;
 
   /**
    * Version flag indicating that the class is using 'preview' features.


=====================================
asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java
=====================================
@@ -89,8 +89,7 @@ public class SignatureWriter extends SignatureVisitor {
       hasFormals = true;
       stringBuilder.append('<');
     }
-    stringBuilder.append(name);
-    stringBuilder.append(':');
+    stringBuilder.append(name).append(':');
   }
 
   @Override
@@ -148,9 +147,7 @@ public class SignatureWriter extends SignatureVisitor {
 
   @Override
   public void visitTypeVariable(final String name) {
-    stringBuilder.append('T');
-    stringBuilder.append(name);
-    stringBuilder.append(';');
+    stringBuilder.append('T').append(name).append(';');
   }
 
   @Override
@@ -161,8 +158,7 @@ public class SignatureWriter extends SignatureVisitor {
 
   @Override
   public void visitClassType(final String name) {
-    stringBuilder.append('L');
-    stringBuilder.append(name);
+    stringBuilder.append('L').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 <<= 1;
@@ -171,8 +167,7 @@ public class SignatureWriter extends SignatureVisitor {
   @Override
   public void visitInnerClassType(final String name) {
     endArguments();
-    stringBuilder.append('.');
-    stringBuilder.append(name);
+    stringBuilder.append('.').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 <<= 1;


=====================================
asm/src/test/java/org/objectweb/asm/ConstantsTest.java
=====================================
@@ -259,6 +259,7 @@ class ConstantsTest {
       case "V24":
       case "V25":
       case "V26":
+      case "V27":
         return ConstantType.CLASS_VERSION;
       case "ACC_PUBLIC":
       case "ACC_PRIVATE":


=====================================
benchmarks/src/jmh/java/org/objectweb/asm/benchmarks/AbstractBenchmark.java
=====================================
@@ -81,6 +81,7 @@ public abstract class AbstractBenchmark {
   ArrayList<byte[]> java8classFiles;
 
   /** The ASM versions that can be benchmarked. */
+  @SuppressWarnings("PMD.ExhaustiveSwitchHasDefault") // Checkstyle complains if default is missing!
   public enum AsmVersion {
     V4_0,
     V5_0,


=====================================
build.gradle
=====================================
@@ -47,8 +47,8 @@ dependencies {
 
 allprojects {
   group = 'org.ow2.asm'
-  version = '9.9.1' + (rootProject.hasProperty('release') ? '' : '-SNAPSHOT')
-  ext.osgi_version_upper_bound = '9.10'
+  version = '9.10.1' + (rootProject.hasProperty('release') ? '' : '-SNAPSHOT')
+  ext.osgi_version_upper_bound = '9.11'
 }
 
 subprojects {
@@ -223,8 +223,8 @@ subprojects {
   tasks.withType(AbstractArchiveTask).configureEach {
     preserveFileTimestamps = false
     reproducibleFileOrder = true
-    dirMode = 0775
-    fileMode = 0664
+    dirPermissions { unix("0755") } 
+    filePermissions { unix("0664") }
   }
 }
 
@@ -233,7 +233,7 @@ subprojects {
 // and packaged with generated module-info classes.
 configure(subprojects.findAll{it.provides}) {
   // Code coverage configuration.
-  jacoco.toolVersion = '0.8.12'
+  jacoco.toolVersion = '0.8.14'
   jacocoTestReport {
     reports { xml.required = true }
     classDirectories.setFrom(sourceSets.main.output.classesDirs)
@@ -253,9 +253,9 @@ configure(subprojects.findAll{it.provides}) {
   // Retrofit the code in-place to Java 1.5 and generate a module-info class
   // from the code content, in compileJava.doLast.
   if (name != 'asm-test') {
+    def path = project(':tools:retrofitter').sourceSets.main.runtimeClasspath
     compileJava.dependsOn ':tools:retrofitter:classes'
     compileJava.doLast {
-      def path = project(':tools:retrofitter').sourceSets.main.runtimeClasspath
       def loader = new URLClassLoader(path.collect {f -> f.toURL()} as URL[])
       def retrofitter =
           loader.loadClass('org.objectweb.asm.tools.Retrofitter').newInstance()
@@ -269,6 +269,7 @@ configure(subprojects.findAll{it.provides}) {
   // Create one backward compatibility checking task for each 'sigtest-*' file
   // in test/resources, and make the 'check' task depend on all these tasks.
   if (file('src/test/resources/').exists()) {
+    def jdk8ApiJarPath = project(':tools').file('jdk8-api.jar').path
     file('src/test/resources/').eachFileMatch(~/sigtest-.*/) { f ->
       task "${f.name}"(dependsOn: 'classes') {
         inputs.files(f, sourceSets.main.java)
@@ -277,7 +278,7 @@ configure(subprojects.findAll{it.provides}) {
           def sigtest = new com.sun.tdk.signaturetest.SignatureTest()
           def args = ['-ApiVersion', version, '-Backward', '-Static',
               '-Mode', 'bin', '-FileName', f, '-Classpath',
-              project(':tools').file('jdk8-api.jar').path + File.pathSeparator +
+              jdk8ApiJarPath + File.pathSeparator +
               sourceSets.main.output.classesDirs.asPath, '-Package'] + provides
           outputs.getFiles()[0].withPrintWriter { printWriter -> 
             sigtest.run(args as String[], printWriter, null)
@@ -294,7 +295,7 @@ configure(subprojects.findAll{it.provides}) {
       doLast {
         def setup = new com.sun.tdk.signaturetest.Setup()
         def args = ['-ApiVersion', version, '-FileName', outputs.getFiles()[0],
-            '-Classpath', project(':tools').file('jdk8-api.jar').path +
+            '-Classpath', jdk8ApiJarPath +
             File.pathSeparator + sourceSets.main.output.classesDirs.asPath +
             File.pathSeparator + sourceSets.main.compileClasspath.asPath,
             '-Package'] + provides
@@ -381,15 +382,15 @@ configure([rootProject] + subprojects.findAll { it.provides }) {
         name = 'nexus'
         url = rootProject.hasProperty('release') ? releasesUrl : snapshotsUrl
         credentials { 
-          username System.env.NEXUS_USER_NAME
-          password System.env.NEXUS_PASSWORD
+          username = System.env.NEXUS_USER_NAME
+          password = System.env.NEXUS_PASSWORD
         }
       }
     }
     publications {
       maven(MavenPublication) {
         def isRoot = project == rootProject
-        artifactId (isRoot ? 'asm-bom' : project.name)
+        artifactId = (isRoot ? 'asm-bom' : project.name)
         from (isRoot ? components.javaPlatform : components.java)
         pom.withXml {
           def parent = asNode().appendNode('parent')
@@ -460,7 +461,7 @@ configure([rootProject] + subprojects.findAll { it.provides }) {
     }
   }
   signing {
-    required rootProject.hasProperty('release')
+    required = rootProject.hasProperty('release')
     sign publishing.publications.maven
   }
   tasks.withType(GenerateModuleMetadata) { enabled = false }


=====================================
tools/pmd.xml
=====================================
@@ -20,17 +20,11 @@
     <exclude name="CheckResultSet" />
     <!-- Already covered with Checkstyle 'InterfaceIsType' rule. -->   
     <exclude name="ConstantsInInterface" />
-    <!-- Already covered with Checkstyle 'DefaultComesLast' rule. -->   
-    <exclude name="DefaultLabelNotLastInSwitchStmt" />
-    <!-- Not relevant for ASM (no logging and using JUnit 5). -->
+    <!-- Not relevant for ASM (no logging). -->
     <exclude name="GuardLogStatement" />
-    <exclude name="JUnit4SuitesShouldUseSuiteAnnotation" />
-    <exclude name="JUnit4TestShouldUseAfterAnnotation" />
-    <exclude name="JUnit4TestShouldUseBeforeAnnotation" />
-    <exclude name="JUnit4TestShouldUseTestAnnotation" />
     <!-- Would give too verbose code. -->
-    <exclude name="JUnitAssertionsShouldIncludeMessage" />
-    <exclude name="JUnitTestContainsTooManyAsserts" />
+    <exclude name="UnitTestAssertionsShouldIncludeMessage" />
+    <exclude name="UnitTestContainsTooManyAsserts" />
     <!-- Not relevant for ASM (using JUnit 5). -->
     <exclude name="JUnitUseExpected" />
     <!-- Already covered with Checkstyle 'IllegalType' rule. -->   
@@ -40,24 +34,20 @@
     <!-- Actually not a best practice. -->   
     <exclude name="LiteralsFirstInComparisons" />
     <!-- Already covered with Checkstyle 'MissingSwitchDefault' rule. -->   
-    <exclude name="SwitchStmtsShouldHaveDefault" />
     <!-- Already covered with google-java-format. -->
-    <exclude name="UnusedImports" />
     <!-- Too many false positives. -->
     <exclude name="UseVarargs" />
   </rule>
   <rule ref="category/java/bestpractices.xml/ArrayIsStoredDirectly">
     <properties>
       <property name="violationSuppressXPath"
-          value="//MethodDeclaration[@Private='true' or 
-              @PackagePrivate='true']" />
+          value="//MethodDeclaration[@Visibility!='public']" />
     </properties>
   </rule>
   <rule ref="category/java/bestpractices.xml/MethodReturnsInternalArray">
     <properties>
       <property name="violationSuppressXPath"
-          value="//MethodDeclaration[@Private='true' or 
-              @PackagePrivate='true']" />
+          value="//MethodDeclaration[@Visibility!='public']" />
     </properties>
   </rule>
   <rule ref="category/java/bestpractices.xml/ForLoopVariableCount">
@@ -77,8 +67,6 @@
     <exclude name="AvoidLiteralsInIfCondition" />
     <!-- Too many false positives. -->
     <exclude name="CompareObjectsWithEquals" />
-    <!-- Does not work, too  many false positives. -->
-    <exclude name="DataflowAnomalyAnalysis" />
     <!-- Not relevant for ASM. -->
     <exclude name="DoNotHardCodeSDCard" />
     <exclude name="DontImportSun" />
@@ -87,11 +75,6 @@
     <exclude name="FinalizeOnlyCallsSuperFinalize" />
     <exclude name="FinalizeOverloaded" />
     <exclude name="FinalizeShouldBeProtected" />
-    <!-- Not relevant for ASM (no logging and using JUnit 5). -->
-    <exclude name="JUnitSpelling" />
-    <exclude name="JUnitStaticSuite" />
-    <exclude name="LoggerIsNotStaticFinal" />
-    <exclude name="MoreThanOneLogger" />
     <!-- Needed to implement custom data structures such as linked lists. -->
     <exclude name="NullAssignment" />
     <!-- Not relevant for ASM (no logging, no dates, no EJB). -->
@@ -103,15 +86,13 @@
   <rule ref="category/java/errorprone.xml/ReturnEmptyCollectionRatherThanNull">
     <properties>
       <property name="violationSuppressXPath"
-          value="//MethodDeclaration[@Private='true']"/>
+          value="//MethodDeclaration[@Visibility!='public']"/>
     </properties>
   </rule>
 
   <rule ref="category/java/performance.xml">
     <!-- Too many false positives. -->
     <exclude name="AvoidInstantiatingObjectsInLoops" />
-    <!-- Shorts can be decrease memory use, without decreasing performance. -->
-    <exclude name="AvoidUsingShortType" />
     <!-- Not relevant for ASM (no BigInteger). -->
     <exclude name="BigIntegerInstantiation" />
     <!-- Does not work, too many false positives. -->


=====================================
tools/retrofitter/src/main/java/org/objectweb/asm/tools/Retrofitter.java
=====================================
@@ -58,6 +58,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.stream.Stream;
 import java.util.zip.GZIPInputStream;
+import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
@@ -345,7 +346,7 @@ public final class Retrofitter {
       }
     }
     if (moduleNames.size() != 1) {
-      throw new IllegalArgumentException("Module name can't be infered from classes");
+      throw new IllegalArgumentException("Module name can't be inferred from classes");
     }
     ModuleVisitor moduleVisitor =
         classWriter.visitModule(moduleNames.get(0).replace('/', '.'), Opcodes.ACC_OPEN, version);
@@ -443,6 +444,14 @@ public final class Retrofitter {
       super.visit(Opcodes.V1_5, access, name, signature, superName, interfaces);
     }
 
+    @Override
+    public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+      if (descriptor.equals("Ljava/lang/FunctionalInterface;")) {
+        return null;
+      }
+      return super.visitAnnotation(descriptor, visible);
+    }
+
     @Override
     public void visitNestHost(final String nestHost) {
       // Remove the NestHost attribute.
@@ -453,6 +462,20 @@ public final class Retrofitter {
       // Remove the NestMembers attribute.
     }
 
+    private AnnotationVisitor removeDeprecatedForRemoval(final AnnotationVisitor av) {
+      // We use @Deprecated(forRemoval = false) instead of a plain @Deprecated
+      // but forRemoval was introduced in Java 9, so we need to remove it
+      return new AnnotationVisitor(api, av) {
+        @Override
+        public void visit(final String name, final Object value) {
+          if (name.equals("forRemoval")) {
+            return;
+          }
+          super.visit(name, value);
+        }
+      };
+    }
+
     @Override
     public FieldVisitor visitField(
         final int access,
@@ -461,7 +484,17 @@ public final class Retrofitter {
         final String signature,
         final Object value) {
       addPackageReferences(Type.getType(descriptor), /* export= */ false);
-      return super.visitField(access, name, descriptor, signature, value);
+      FieldVisitor fv = super.visitField(access, name, descriptor, signature, value);
+      return new FieldVisitor(api, fv) {
+        @Override
+        public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+          AnnotationVisitor av = super.visitAnnotation(descriptor, visible);
+          if (descriptor.equals("Ljava/lang/Deprecated;")) {
+            return removeDeprecatedForRemoval(av);
+          }
+          return av;
+        }
+      };
     }
 
     @Override
@@ -475,6 +508,15 @@ public final class Retrofitter {
       return new MethodVisitor(
           api, super.visitMethod(access, name, descriptor, signature, exceptions)) {
 
+        @Override
+        public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+          AnnotationVisitor av = super.visitAnnotation(descriptor, visible);
+          if (descriptor.equals("Ljava/lang/Deprecated;")) {
+            return removeDeprecatedForRemoval(av);
+          }
+          return av;
+        }
+
         @Override
         public void visitParameter(final String name, final int access) {
           // Javac 21 generates a Parameter attribute for the synthetic/mandated parameters.
@@ -648,9 +690,6 @@ public final class Retrofitter {
     /** The internal name of the visited class. */
     String className;
 
-    /** The name and descriptor of the currently visited method. */
-    String currentMethodName;
-
     public ClassVerifier() {
       // Make sure use we don't use Java 9 or higher classfile features.
       // We also want to make sure we don't use Java 6, 7 or 8 classfile
@@ -673,6 +712,49 @@ public final class Retrofitter {
       className = name;
     }
 
+    @Override
+    public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+      var av = super.visitAnnotation(descriptor, visible);
+      if (descriptor.equals("Ljava/lang/FunctionalInterface;")) {
+        throw new IllegalArgumentException(
+            format("ERROR: @FunctionalInterface in %s is not available in JDK 1.5", className));
+      }
+      return av;
+    }
+
+    private AnnotationVisitor deprecatedAnnotationVisitor(
+        final String descriptor, final AnnotationVisitor av, final String member) {
+      if (descriptor.equals("Ljava/lang/Deprecated;")) {
+        return new AnnotationVisitor(Opcodes.ASM4, av) {
+          @Override
+          public void visit(final String name, final Object value) {
+            throw new IllegalArgumentException(
+                format(
+                    "ERROR: @Deprecated name %s on %s %s is not available in JDK 1.5",
+                    name, member, className));
+          }
+        };
+      }
+      return av;
+    }
+
+    @Override
+    public FieldVisitor visitField(
+        final int access,
+        final String name,
+        final String descriptor,
+        final String signature,
+        final Object value) {
+      var fv = super.visitField(access, name, descriptor, signature, value);
+      return new FieldVisitor(Opcodes.ASM4, fv) {
+        @Override
+        public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+          var av = super.visitAnnotation(descriptor, visible);
+          return deprecatedAnnotationVisitor(descriptor, av, name);
+        }
+      };
+    }
+
     @Override
     public MethodVisitor visitMethod(
         final int access,
@@ -680,14 +762,28 @@ public final class Retrofitter {
         final String descriptor,
         final String signature,
         final String[] exceptions) {
-      currentMethodName = name + descriptor;
+      String methodName = name + descriptor;
       MethodVisitor methodVisitor =
           super.visitMethod(access, name, descriptor, signature, exceptions);
       return new MethodVisitor(Opcodes.ASM4, methodVisitor) {
+        @Override
+        public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+          var av = super.visitAnnotation(descriptor, visible);
+          return deprecatedAnnotationVisitor(descriptor, av, methodName);
+        }
+
+        @Override
+        public void visitParameter(final String name, final int access) {
+          throw new IllegalArgumentException(
+              format(
+                  "ERROR: parameter %s in %s %s is not available in JDK 1.5",
+                  name, className, methodName));
+        }
+
         @Override
         public void visitFieldInsn(
             final int opcode, final String owner, final String name, final String descriptor) {
-          check(owner, name);
+          check(owner, name, methodName);
         }
 
         @Override
@@ -697,7 +793,7 @@ public final class Retrofitter {
             final String name,
             final String descriptor,
             final boolean isInterface) {
-          check(owner, name + descriptor);
+          check(owner, name + descriptor, methodName);
         }
 
         @Override
@@ -708,13 +804,13 @@ public final class Retrofitter {
               throw new IllegalArgumentException(
                   format(
                       "ERROR: ldc with a MethodType called in %s %s is not available in JDK 1.5",
-                      className, currentMethodName));
+                      className, methodName));
             }
           } else if (value instanceof Handle) {
             throw new IllegalArgumentException(
                 format(
                     "ERROR: ldc with a MethodHandle called in %s %s is not available in JDK 1.5",
-                    className, currentMethodName));
+                    className, methodName));
           }
         }
 
@@ -727,7 +823,7 @@ public final class Retrofitter {
           throw new IllegalArgumentException(
               format(
                   "ERROR: invokedynamic called in %s %s is not available in JDK 1.5",
-                  className, currentMethodName));
+                  className, methodName));
         }
       };
     }
@@ -737,8 +833,9 @@ public final class Retrofitter {
      *
      * @param owner A class name.
      * @param member A field name or a method name and descriptor.
+     * @param methodName The name and descriptor of the currently visited method.
      */
-    private void check(final String owner, final String member) {
+    private void check(final String owner, final String member, final String methodName) {
       if (owner.startsWith("java/")) {
         String currentOwner = owner;
         while (currentOwner != null) {
@@ -750,7 +847,7 @@ public final class Retrofitter {
         throw new IllegalArgumentException(
             format(
                 "ERROR: %s %s called in %s %s is not defined in the JDK 1.5 API",
-                owner, member, className, currentMethodName));
+                owner, member, className, methodName));
       }
     }
   }



View it on GitLab: https://salsa.debian.org/java-team/asm/-/compare/c8bd3e4e3e504a5c090ae93065b950992128b551...edbc7f58f5c873aa8961b74c6c16afb9c112573a

-- 
View it on GitLab: https://salsa.debian.org/java-team/asm/-/compare/c8bd3e4e3e504a5c090ae93065b950992128b551...edbc7f58f5c873aa8961b74c6c16afb9c112573a
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20260918/e9989a2b/attachment.htm>


More information about the pkg-java-commits mailing list