asm issueshttps://gitlab.ow2.org/asm/asm/-/issues2024-01-26T17:34:43Zhttps://gitlab.ow2.org/asm/asm/-/issues/318008ClassRemapper fails to transform Calcite 1.36.0 SqlFunctions2024-01-26T17:34:43ZGuillaume MasséClassRemapper fails to transform Calcite 1.36.0 SqlFunctionsI'm sorry I can't minimize this issue further, I'm using asm via sbt-assembly to perform class shading on some of our libraries. When upgrading from calcite 1.35.0 to 1.36.0.
Good: https://github.com/apache/calcite/blob/calcite-1.35.0/c...I'm sorry I can't minimize this issue further, I'm using asm via sbt-assembly to perform class shading on some of our libraries. When upgrading from calcite 1.35.0 to 1.36.0.
Good: https://github.com/apache/calcite/blob/calcite-1.35.0/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
Bad: https://github.com/apache/calcite/blob/calcite-1.36.0/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
I noticed that class shading failed with:
```
java.lang.ArrayIndexOutOfBoundsException: Index 65536 out of bounds for length 297
at org.objectweb.asm.ClassReader.readLabel(ClassReader.java:2695)
at org.objectweb.asm.ClassReader.createLabel(ClassReader.java:2711)
```
I first reproduced the issue with Scala's fork of jarjar: https://github.com/eed3si9n/jarjar-abrams/pull/45
But then I noticed that it's most likely a asm bug and made more minimization to limit myself to asm: https://github.com/MasseGuillaume/asm-remapper-bug
In the issue template, you mention `CheckClassAdapter`, I gave it a shot and it's indeed an error with labels:
```
java.lang.IllegalArgumentException: Invalid end label (must be visited first)
at org.objectweb.asm.util.CheckMethodAdapter.checkLabel(CheckMethodAdapter.java:1453)
at org.objectweb.asm.util.CheckMethodAdapter.visitLocalVariableAnnotation(CheckMethodAdapter.java:996)
at org.objectweb.asm.MethodVisitor.visitLocalVariableAnnotation(MethodVisitor.java:757)
at org.objectweb.asm.commons.MethodRemapper.visitLocalVariableAnnotation(MethodRemapper.java:257)
at org.objectweb.asm.ClassReader.readCode(ClassReader.java:2614)
at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1515)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:745)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:425)
at remapper.bug.RemapperTest.remapper(RemapperTest.java:42)
```
I don't think it's because of how I use asm (maybe I'm wrong):
```java
byte[] bytecode = Files.readAllBytes(Paths.get("../SqlFunctions.class"));
Remapper remapper = new Remapper() {};
ClassReader classReader = new ClassReader(bytecode);
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor classVisitor = new CheckClassAdapter(classWriter);
ClassRemapper classRemapper = new ClassRemapper(classVisitor, remapper);
classReader.accept(classRemapper, ClassReader.EXPAND_FRAMES);
byte[] outputBytecode = classWriter.toByteArray();
ClassReader classReader2 = new ClassReader(outputBytecode);
ClassWriter classWriter2 = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor visitor = new ClassVisitor(Opcodes.ASM9, classWriter2) {};
classReader2.accept(visitor, ClassReader.EXPAND_FRAMES);
```https://gitlab.ow2.org/asm/asm/-/issues/318007`ClassNode#outerClass` has incorrect JavaDocs.2023-11-18T13:54:41ZMarcus Sawyer`ClassNode#outerClass` has incorrect JavaDocs.See title. The docs read:
```java
/**
* The internal name of the enclosing class of this class (see {@link
* org.objectweb.asm.Type#getInternalName()}). Must be {@literal null} if this class has no
* enclosing class, or if it ...See title. The docs read:
```java
/**
* The internal name of the enclosing class of this class (see {@link
* org.objectweb.asm.Type#getInternalName()}). Must be {@literal null} if this class has no
* enclosing class, or if it is a local or anonymous class.
*/
```
whereas in fact, the attribute is *only* populated for anonymous and local classes. It seems to have been erroneously copied from [this part of the spec](https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.6:~:text=representing%20C.-,outer_class_info_index,-If%20C%20is), which is in fact talking about the `InnerClasses` attribute.
The correct section is [here](https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.7:~:text=must%20be%20four.-,class_index,-The%20value%20of), since this field is actually populated by the (slightly poorly-named) `visitOuterClass` method based on the `enclosingMethodOffset` in `ClassReader`.https://gitlab.ow2.org/asm/asm/-/issues/318005Is there an opportunity to improve the JDK major release upgrade experience?2023-10-21T13:41:59ZDanny ThomasIs there an opportunity to improve the JDK major release upgrade experience?Hello! Danny from the Netflix JVM Ecosystem team here. I just finished our readiness work for JDK 21 and our friends `ClassReader` and `ClassVisitor` were responsible for the majority of issues we've seen across many libraries, except fo...Hello! Danny from the Netflix JVM Ecosystem team here. I just finished our readiness work for JDK 21 and our friends `ClassReader` and `ClassVisitor` were responsible for the majority of issues we've seen across many libraries, except for one compatibility issue in Lombok due to changes in javac. It's a problem exacerbated by the common practice of shading ASM, which means though the project is quite proactive about adding support for the next release, we can't just force an upgrade to ASM-latest, we're coupled to releases of the libraries themselves. Just off the top of my head there's shaded ASM in:
- Byte Buddy (own experimental property)
- Guice
- Groovy
- Gradle Test Retry Plugin
- JaCoCo
- Javassist
- Jersey
- Spring Framework (forked, but still has version checks but set to latest version, experimental check in ClassVisitor patched out)
With JDK releases accelerated to the extent they are now this is something everyone is dealing with far more regularly than years past. It's doubly a problem for our team, not only getting ready for a GA releases, but because we're often testing on ea, nightly or custom builds, and we need to build and canary against real applications. To unblock us, I had to build an `asm-all` dependency that takes `spring-core` ASM and copies it it to every known shaded asm package and inject it first on the classpath. While updating that library today to test [a PR that's particularly important to us](https://github.com/openjdk/jdk/pull/15718) and ASM breaking the build, tests, runtime and Jenkins code coverage plugins, but after hacking in the upgrade everything working great, I wondered to myself if these strict version checks are really necessary, and perhaps the same safety could be guaranteed while throwing an error only when a class file is truly unreadable/incompatible.
That approach would have seen us through JDK 16 to 22, and perhaps beyond without an error. So, I thought I'd come and ask what your current thinking about this is. Are the strict version/experimental checks really necessary, or is it safe to throw an incompatible version exception when encountering unknown constant tags, opcodes, etc.? I understand the format itself imposes those restrictions, because the sizes of each block needs to be known ahead of time. I guess there must have been changes that don't involve new block types, but still aren't backwards compatible, generic type annotations maybe?
With the `ClassFile` API is still a long time away from being available, not to mention adopted broadly, I think any improvement to the JDK upgrade experience w/ ASM would be a real boon to the ecosystem.
We use Gradle, so I was considering doing what we did for the JakartaEE migration: we use Gradle transforms in our [gradle-jakartaee-migration-plugin](https://github.com/nebula-plugins/gradle-jakartaee-migration-plugin), we would just upgrade ASM on the fly during artifact resolution. That's saved us a _huge_ amount of trouble, as we have a lot of legacy code with `javax` references, and made roman riding two legacy frameworks, plus Spring Boot 2 and Spring Boot 3 at the same time a cinch. It'd be very little effort to build (in fact the Tomcat JakartaEE migration tool is a fine streaming and recursive shading implementation, I'd just use as an implementation detail). It'd would work for dependencies of both the build and the project, but would only benefit Gradle users, so thought I'd ask here first before I solve this problem for us, when there might an opportunity to help out here instead.
If you think there is an opportunity here, some advice on what kind of confidence/quality bar we'd need to meet to allow the removal of these specific version and experimental version checks would be all I'd need to get started.
Appreciate your time. Cheers!Eric BrunetonEric Brunetonhttps://gitlab.ow2.org/asm/asm/-/issues/318004ASM library is running into an internal error2023-10-21T12:39:52ZPavlo DorokhovASM library is running into an internal error### Expected Behavior
No exception when ASM library load "zzZOF.class" class file
### Current Behavior
Method "zzZ" of class "zzZOF" of the "aspose-words-15.8.0.jar" has an unusual structure within it, that doesn't prevent execution by ...### Expected Behavior
No exception when ASM library load "zzZOF.class" class file
### Current Behavior
Method "zzZ" of class "zzZOF" of the "aspose-words-15.8.0.jar" has an unusual structure within it, that doesn't prevent execution by the JVM, but the library that used class files experiences an exception.
### Steps to Reproduce
Jar file from "http://develop.centit.com/nexus/content/repositories/centit-releases/com/aspose/aspose-words/15.8.0/aspose-words-15.8.0-jdk16.jar".
Below is a raw reproduction of the issue using the most recent 9.5 version of this "asm" java bytecode reader library:
ifn="/Users/pavel/Downloads/aspose-words-15.8.0-jdk16/com/aspose/words/zzZOF.class";echo 'String ifn=System.getProperty("ifn");FileInputStream fis=new FileInputStream(new File(ifn));import org.objectweb.asm.ClassReader;import org.objectweb.asm.tree.ClassNode;import org.objectweb.asm.ClassVisitor;ClassNode clazz=new ClassNode();ClassReader reader=new ClassReader(fis);reader.accept((ClassVisitor)clazz, 0);fis.close();' | /Users/pavel/Documents/jre/bin/jshell -R-Difn="$ifn" -c /Users/pavel/Downloads/asm-9.5.jar:/Users/pavel/Downloads/asm-tree-9.5.jar -
Exception java.lang.ArrayIndexOutOfBoundsException: Index 107 out of bounds for length 99
at ClassReader.readLabel (ClassReader.java:2694)
at ClassReader.createLabel (ClassReader.java:2710)
at ClassReader.readStackMapFrame (ClassReader.java:3369)
at ClassReader.readCode (ClassReader.java:2089)
at ClassReader.readMethod (ClassReader.java:1514)
at ClassReader.accept (ClassReader.java:744)
at ClassReader.accept (ClassReader.java:424)
at (#8:1)
If you have any questions please contact pashadtvwork@gmail.comhttps://gitlab.ow2.org/asm/asm/-/issues/318002asm-analysis Frame allocates an array unnecessarily inside executeInvokeInsn2023-09-23T17:58:20ZTagir Valeevasm-analysis Frame allocates an array unnecessarily inside executeInvokeInsnWhen 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=head...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.https://gitlab.ow2.org/asm/asm/-/issues/318001recognize Java 22 version (66)2023-06-17T09:21:06Zcushonrecognize Java 22 version (66)ASM should be updated to recognize Java 22 version (66).
The latest upstream JDK versions are being updated to use the new version in https://github.com/openjdk/jdk/pull/13567 (which is still pending).
The previous ASM issue for versio...ASM should be updated to recognize Java 22 version (66).
The latest upstream JDK versions are being updated to use the new version in https://github.com/openjdk/jdk/pull/13567 (which is still pending).
The previous ASM issue for version 21 was https://gitlab.ow2.org/asm/asm/-/issues/317990https://gitlab.ow2.org/asm/asm/-/issues/318000java.lang.IllegalArgumentException in SignatureReader for method return an Op...2023-05-12T16:01:29ZMaximilian Ostjava.lang.IllegalArgumentException in SignatureReader for method return an Optional StreamFollowing exception stack trace
>
> java.lang.IllegalArgumentException
> at org.objectweb.asm.signature.SignatureReader.parseType(SignatureReader.java:249)
> at org.objectweb.asm.signature.SignatureReader.accept(SignatureReader.java:...Following exception stack trace
>
> java.lang.IllegalArgumentException
> at org.objectweb.asm.signature.SignatureReader.parseType(SignatureReader.java:249)
> at org.objectweb.asm.signature.SignatureReader.accept(SignatureReader.java:114)
> at org.apache.maven.shared.dependency.analyzer.asm.DefaultClassVisitor.addSignature(DefaultClassVisitor.java:153)
> at org.apache.maven.shared.dependency.analyzer.asm.DefaultClassVisitor.visitMethod(DefaultClassVisitor.java:133)
> at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1353)
> at org.objectweb.asm.ClassReader.accept(ClassReader.java:744)
> at org.objectweb.asm.ClassReader.accept(ClassReader.java:424)
> at org.apache.maven.shared.dependency.analyzer.asm.DependencyClassFileVisitor.visitClass(DependencyClassFileVisitor.java:71)
> at org.apache.maven.shared.dependency.analyzer.asm.ResultCollectorTest.getDependencies(ResultCollectorTest.java:38)
> at org.apache.maven.shared.dependency.analyzer.asm.ResultCollectorTest.testClassWithStreamAndOptional(ResultCollectorTest.java:69)
is thrown for class
`
package pkg;
import java.io.Serializable;
import java.util.Optional;
import java.util.stream.Stream;
public class CUnderTest {
public Stream<Serializable> doMyStuff() {
Stream<Serializable> s = Stream.empty();
return Optional.ofNullable(s).orElseGet(Stream::of);
}
}
`
### Expected Behavior
no exception is thrown and signature for '()+Ljava/util/stream/Stream<Ljava/io/Serializable;>;' parsing works
### Current Behavior
IllegalArgumentException is thrown. The signature '()+Ljava/util/stream/Stream<Ljava/io/Serializable;>;' contains a + which is not handled correctly in the method org.objectweb.asm.signature.SignatureReader.parseType(String, int, SignatureVisitor)
### Steps to Reproduce
Extend the test class in
org.apache.maven.shared.dependency.analyzer.asm.ResultCollectorTest
of
https://github.com/apache/maven-dependency-analyzer.git
with following test:
`
@Test
public void testClassWithStreamAndOptional() throws IOException {
Set<String> dependencies = getDependencies(CUnderTest.class);
assertThat(dependencies).contains("java.util.stream.Stream");
}
`https://gitlab.ow2.org/asm/asm/-/issues/317995Invalid stackmap generated when the instruction stream has new instruction af...2023-06-26T17:36:57ZSøren GjesseInvalid stackmap generated when the instruction stream has new instruction after invokespecial to <init>Using the ASM code below generates a class file which fails on the JVM with:
```
StackMapTable format error: bad offset for Uninitialized in method Test.main([Ljava/lang/String;)V
```
The javap dump of the generated `main` method is:
```...Using the ASM code below generates a class file which fails on the JVM with:
```
StackMapTable format error: bad offset for Uninitialized in method Test.main([Ljava/lang/String;)V
```
The javap dump of the generated `main` method is:
```
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: goto 12
6: invokespecial #21 // Method "<init>":()V
9: goto 19
12: new #2 // class Test
15: dup
16: goto 6
19: invokevirtual #25 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
22: return
StackMapTable: number_of_entries = 4
frame_type = 255 /* full_frame */
offset_delta = 6
locals = [ class "[Ljava/lang/String;" ]
stack = [ class java/io/PrintStream, uninitialized 0, uninitialized 0 ]
frame_type = 255 /* full_frame */
offset_delta = 2
locals = [ class "[Ljava/lang/String;" ]
stack = [ class java/io/PrintStream, class Test ]
frame_type = 255 /* full_frame */
offset_delta = 2
locals = [ class "[Ljava/lang/String;" ]
stack = [ class java/io/PrintStream ]
frame_type = 255 /* full_frame */
offset_delta = 6
locals = [ class "[Ljava/lang/String;" ]
stack = [ class java/io/PrintStream, class Test ]
```
The issue are the two `uninitialized 0` in the stackmap. The code has the `new` instruction later in the instruction stream than the `invokespecial` to `<init>`.
Code to generate the class file:
```
public static byte[] dump() throws Exception {
ClassWriter classWriter = new ClassWriter(0);
MethodVisitor methodVisitor;
classWriter.visit(V1_8, ACC_FINAL | ACC_SUPER, "Test", null, "java/lang/Object", null);
{
methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
}
{
Label labelNew = new Label();
Label labelInit = new Label();
Label labelAfterInit = new Label();
methodVisitor =
classWriter.visitMethod(
ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
methodVisitor.visitCode();
methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
methodVisitor.visitJumpInsn(GOTO, labelNew);
methodVisitor.visitLabel(labelInit);
methodVisitor.visitFrame(
Opcodes.F_FULL,
1,
new Object[] {"[Ljava/lang/String;"},
3,
new Object[] {"java/io/PrintStream", labelNew, labelNew});
methodVisitor.visitMethodInsn(INVOKESPECIAL, MAIN_CLASS, "<init>", "()V", false);
methodVisitor.visitFrame(
Opcodes.F_FULL,
1,
new Object[] {"[Ljava/lang/String;"},
2,
new Object[] {"java/io/PrintStream", MAIN_CLASS});
methodVisitor.visitJumpInsn(GOTO, labelAfterInit);
methodVisitor.visitLabel(labelNew);
methodVisitor.visitFrame(
Opcodes.F_FULL,
1,
new Object[] {"[Ljava/lang/String;"},
1,
new Object[] {"java/io/PrintStream"});
methodVisitor.visitTypeInsn(NEW, MAIN_CLASS);
methodVisitor.visitInsn(DUP);
methodVisitor.visitJumpInsn(GOTO, labelInit);
methodVisitor.visitLabel(labelAfterInit);
methodVisitor.visitFrame(
Opcodes.F_FULL,
1,
new Object[] {"[Ljava/lang/String;"},
2,
new Object[] {"java/io/PrintStream", MAIN_CLASS});
methodVisitor.visitMethodInsn(
INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(3, 1);
methodVisitor.visitEnd();
}
{
methodVisitor =
classWriter.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
methodVisitor.visitCode();
methodVisitor.visitLdcInsn("Hello, world!");
methodVisitor.visitInsn(ARETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
}
classWriter.visitEnd();
return classWriter.toByteArray();
}
```
To work around the issue for my concrete application I added patching of the bytes from ASM using javassist (see [here](https://r8.googlesource.com/r8/+/9baf2a528d42b1b238605f73568d589b0b32fb83/src/test/java/com/android/tools/r8/cf/frames/InitBeforeNewInInstructionStreamTest.java#86))https://gitlab.ow2.org/asm/asm/-/issues/317994ConstantDynamic instances should not be canonicalized as they define distinct...2023-04-06T17:51:28ZSøren GjesseConstantDynamic instances should not be canonicalized as they define distinct constantsI would like to construct the class file shown at the bottom of this issue. However, that is not possible with ASM. The issue arises from the two `ldc` instructions using a dynamic constant using the exact same BSM and arguments to that ...I would like to construct the class file shown at the bottom of this issue. However, that is not possible with ASM. The issue arises from the two `ldc` instructions using a dynamic constant using the exact same BSM and arguments to that BSM seen in the two methods `getConstant1` and `getConstant2`:
```
public static java.lang.Object getConstant1();
descriptor: ()Ljava/lang/Object;
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #27 // Dynamic #0:constantName:Ljava/lang/Object;
2: areturn
LineNumberTable:
line 135: 0
public static java.lang.Object getConstant2();
descriptor: ()Ljava/lang/Object;
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #29 // Dynamic #1:constantName:Ljava/lang/Object;
2: areturn
LineNumberTable:
line 139: 0
```
When trying to generate these methods using ASM:
```
{
methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, "getConstant1", "()Ljava/lang/Object;", null, null);
methodVisitor.visitCode();
Label label0 = new Label();
methodVisitor.visitLabel(label0);
methodVisitor.visitLineNumber(135, label0);
methodVisitor.visitLdcInsn(new ConstantDynamic("constantName", "Ljava/lang/Object;", new Handle(Opcodes.H_INVOKESTATIC, "A", "myConstant", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;", false), new Object[] {}));
methodVisitor.visitInsn(ARETURN);
methodVisitor.visitMaxs(1, 0);
methodVisitor.visitEnd();
}
{
methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, "getConstant2", "()Ljava/lang/Object;", null, null);
methodVisitor.visitCode();
Label label0 = new Label();
methodVisitor.visitLabel(label0);
methodVisitor.visitLineNumber(139, label0);
methodVisitor.visitLdcInsn(new ConstantDynamic("constantName", "Ljava/lang/Object;", new Handle(Opcodes.H_INVOKESTATIC, "A", "myConstant", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;", false), new Object[] {}));
methodVisitor.visitInsn(ARETURN);
methodVisitor.visitMaxs(1, 0);
methodVisitor.visitEnd();
}
```
the two `new ConstantDynamic` taking the exact same arguments will be canonicalized during writing and the generated class file will not have two dynamic constants but only one.
To actually generate the class file below I did a crude patch on ASM (see [here](https://r8.googlesource.com/r8/+/9baf2a528d42b1b238605f73568d589b0b32fb83/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicMultipleConstantsWithDifferentSymbolicReferenceUsingSameBSMAndArgumentsTest.java#544)), which is not a general solution.
Full javap output of the class file (the bytes for it is [here](https://r8.googlesource.com/r8/+/9baf2a528d42b1b238605f73568d589b0b32fb83/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicMultipleConstantsWithDifferentSymbolicReferenceUsingSameBSMAndArgumentsTest.java#318)):
```
Classfile A.class
Last modified Mar 17, 2023; size 1364 bytes
SHA-256 checksum 4379e359d727521479cee1aa5b6d711090b2777553454d9b667fe502a1b0daa9
Compiled from "A.java"
public class A
minor version: 0
major version: 55
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #2 // A
super_class: #4 // java/lang/Object
interfaces: 0, fields: 0, methods: 5, attributes: 3
Constant pool:
#1 = Utf8 A
#2 = Class #1 // A
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 A.java
#6 = Utf8 java/lang/invoke/MethodHandles$Lookup
#7 = Class #6 // java/lang/invoke/MethodHandles$Lookup
#8 = Utf8 java/lang/invoke/MethodHandles
#9 = Class #8 // java/lang/invoke/MethodHandles
#10 = Utf8 Lookup
#11 = Utf8 <init>
#12 = Utf8 ()V
#13 = NameAndType #11:#12 // "<init>":()V
#14 = Methodref #4.#13 // java/lang/Object."<init>":()V
#15 = Utf8 this
#16 = Utf8 LA;
#17 = Utf8 getConstant1
#18 = Utf8 ()Ljava/lang/Object;
#19 = Utf8 myConstant
#20 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
#21 = NameAndType #19:#20 // myConstant:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
#22 = Methodref #2.#21 // A.myConstant:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
#23 = MethodHandle 6:#22 // REF_invokeStatic A.myConstant:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
#24 = Utf8 constantName
#25 = Utf8 Ljava/lang/Object;
#26 = NameAndType #24:#25 // constantName:Ljava/lang/Object;
#27 = Dynamic #0:#26 // #0:constantName:Ljava/lang/Object;
#28 = Utf8 getConstant2
#29 = Dynamic #1:#26 // #1:constantName:Ljava/lang/Object;
#30 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class<*>;)Ljava/lang/Object;
#31 = Utf8 lookup
#32 = Utf8 Ljava/lang/invoke/MethodHandles$Lookup;
#33 = Utf8 name
#34 = Utf8 Ljava/lang/String;
#35 = Utf8 type
#36 = Utf8 Ljava/lang/Class<*>;
#37 = Utf8 Ljava/lang/Class;
#38 = Utf8 main
#39 = Utf8 ([Ljava/lang/String;)V
#40 = Utf8 java/lang/System
#41 = Class #40 // java/lang/System
#42 = Utf8 out
#43 = Utf8 Ljava/io/PrintStream;
#44 = NameAndType #42:#43 // out:Ljava/io/PrintStream;
#45 = Fieldref #41.#44 // java/lang/System.out:Ljava/io/PrintStream;
#46 = NameAndType #17:#18 // getConstant1:()Ljava/lang/Object;
#47 = Methodref #2.#46 // A.getConstant1:()Ljava/lang/Object;
#48 = NameAndType #28:#18 // getConstant2:()Ljava/lang/Object;
#49 = Methodref #2.#48 // A.getConstant2:()Ljava/lang/Object;
#50 = Utf8 java/io/PrintStream
#51 = Class #50 // java/io/PrintStream
#52 = Utf8 [Ljava/lang/String;
#53 = Class #52 // "[Ljava/lang/String;"
#54 = Utf8 println
#55 = Utf8 (Z)V
#56 = NameAndType #54:#55 // println:(Z)V
#57 = Methodref #51.#56 // java/io/PrintStream.println:(Z)V
#58 = Utf8 Code
#59 = Utf8 LineNumberTable
#60 = Utf8 LocalVariableTable
#61 = Utf8 LocalVariableTypeTable
#62 = Utf8 Signature
#63 = Utf8 StackMapTable
#64 = Utf8 InnerClasses
#65 = Utf8 SourceFile
#66 = Utf8 BootstrapMethods
{
public A();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #14 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 132: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LA;
public static java.lang.Object getConstant1();
descriptor: ()Ljava/lang/Object;
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #27 // Dynamic #0:constantName:Ljava/lang/Object;
2: areturn
LineNumberTable:
line 135: 0
public static java.lang.Object getConstant2();
descriptor: ()Ljava/lang/Object;
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #29 // Dynamic #1:constantName:Ljava/lang/Object;
2: areturn
LineNumberTable:
line 139: 0
private static java.lang.Object myConstant(java.lang.invoke.MethodHandles$Lookup, java.lang.String, java.lang.Class<?>);
descriptor: (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=3, args_size=3
0: new #4 // class java/lang/Object
3: dup
4: invokespecial #14 // Method java/lang/Object."<init>":()V
7: areturn
LineNumberTable:
line 143: 0
LocalVariableTable:
Start Length Slot Name Signature
0 8 0 lookup Ljava/lang/invoke/MethodHandles$Lookup;
0 8 1 name Ljava/lang/String;
0 8 2 type Ljava/lang/Class;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 8 2 type Ljava/lang/Class<*>;
Signature: #30 // (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class<*>;)Ljava/lang/Object;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
0: getstatic #45 // Field java/lang/System.out:Ljava/io/PrintStream;
3: invokestatic #47 // Method getConstant1:()Ljava/lang/Object;
6: invokestatic #49 // Method getConstant2:()Ljava/lang/Object;
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #57 // Method java/io/PrintStream.println:(Z)V
20: return
StackMapTable: number_of_entries = 2
frame_type = 80 // same_locals_1_stack_item
stack = [ class java/io/PrintStream ]
frame_type = 255 // full_frame
offset_delta = 0
locals = [ class "[Ljava/lang/String;" ]
stack = [ class java/io/PrintStream, int ]
LineNumberTable:
line 12: 0
line 13: 20
}
InnerClasses:
public static final #10= #7 of #9; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
SourceFile: "A.java"
BootstrapMethods:
0: #23 REF_invokeStatic A.myConstant:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
Method arguments:
1: #23 REF_invokeStatic A.myConstant:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
Method arguments:
```https://gitlab.ow2.org/asm/asm/-/issues/317992Compiled wildcard is not correctly handled by ASM2023-05-10T16:00:56ZKrystian KosekCompiled wildcard is not correctly handled by ASMI have a fragment of code:
`.findFirst().orElseThrow(() -> new Error("Code not found"))`
Which after compiling with use of jdk8 with tycho-maven-plugin 0.22 generates below code:
`Signature ()+Ljava/lang/Error; ~ java/lang/Error € Co...I have a fragment of code:
`.findFirst().orElseThrow(() -> new Error("Code not found"))`
Which after compiling with use of jdk8 with tycho-maven-plugin 0.22 generates below code:
`Signature ()+Ljava/lang/Error; ~ java/lang/Error € Code not found`
When I pass the compiled code through ASM, SignatureReader class throws an IllegalArgumentException when it encounters ‘+’ character.
I've tested this on several asm versions and I see that versions below 6.1 pass this while newer versions throw this exception.
(Compiling code without tycho or with newer tycho version doesn't generate this `Signature� �()+Ljava/lang/Error;� ` part and generated code passes through asm, but for internal reason I am unable to upgrade tycho to a newer version at the moment)
Whereas javap command read generated .class file correctly without informing about any error. On the contrary jd-gui is not able to decompile this .class file.
I assume that if javap doesn't report any error, it's a valid java bytecode.
File compiled with tycho 0.22: [TestClass.class](/uploads/23b75f061a1928f12f5c5f7a4f778699/TestClass.class)https://gitlab.ow2.org/asm/asm/-/issues/317990recognize Java 21 version (65)2023-06-01T17:36:41Zcushonrecognize Java 21 version (65)ASM should be updated to recognize Java 21 version (65).
The latest upstream JDK versions now were updated to use that class file version in https://github.com/openjdk/jdk/commit/175e3d3ff332be25cca9822c58c46f1e012953c2
The previous AS...ASM should be updated to recognize Java 21 version (65).
The latest upstream JDK versions now were updated to use that class file version in https://github.com/openjdk/jdk/commit/175e3d3ff332be25cca9822c58c46f1e012953c2
The previous ASM commit that added support for version 20 was https://gitlab.ow2.org/asm/asm/-/commit/8b7090dc7fc280aeff270473658766179cb2024b.Remi ForaxRemi Foraxhttps://gitlab.ow2.org/asm/asm/-/issues/317989Silent removal of zero-valued entries from the line-number table2022-12-21T08:10:52ZIan ZernySilent removal of zero-valued entries from the line-number tableWhen using ASM to inspect or transform line tables it will silently ignore/strip zero-valued lines.
### Expected Behavior
Zero-valued line entries should be treated as any other line value and a call to MethodVisitor.visitLineNumber sho...When using ASM to inspect or transform line tables it will silently ignore/strip zero-valued lines.
### Expected Behavior
Zero-valued line entries should be treated as any other line value and a call to MethodVisitor.visitLineNumber should be made.
(The JVM spec does not appear to have any other requirement than that the line entries are unsigned 2-byte values IFAICT. That is also consistent with JVM execution as illustrated by the attached code).
### Current Behavior
MethodVisitor never receives a callback.
### Steps to Reproduce
Attached is a .class file with a method that has respectively a non-zero line followed by a zero-valued line. Any use of MethodVisitor on these lines will fail to act on the zero-valued entry. The result is that the throw will inherent the previous line value.
Second line number table is that of the main method:
```
$ javap -v -cp /tmp/test.zip com.android.tools.r8.debuginfo.AsmZeroLineEntryRegressionTest\$TestClass |grep line -B 1
LineNumberTable:
line 126: 0
--
LineNumberTable:
line 1: 0
line 0: 8
```
Executing the program will throw on "line 0":
```
$ java -cp /tmp/test.zip com.android.tools.r8.debuginfo.AsmZeroLineEntryRegressionTest\$TestClass
Hello, world!
Exception in thread "main" java.lang.RuntimeException: BOO!
at com.android.tools.r8.debuginfo.AsmZeroLineEntryRegressionTest$TestClass.main(AsmZeroLineEntryRegressionTest.java:0)
```
Doing an "identity" transformation on this will strip the zero-valued line and the result will be a stack trace at line `:1`
More details can be found in the [R8 regression test](https://r8-review.git.corp.google.com/c/r8/+/74032) or via the [R8 tracking bug](https://issuetracker.google.com/260389461).
Archive with the single class file [test.zip](/uploads/4d40776f00a15074cabbab2c14c89891/test.zip)https://gitlab.ow2.org/asm/asm/-/issues/317988Interface not being added to class2022-11-27T09:17:18ZAlex HoweInterface not being added to classI'm trying to make the Minecraft class implement my MinecraftBridge interface using
```kt
node.interfaces.add(Type.getInternalName(MinecraftBridge::class.java))
```
When I add it to my own MinecraftBridgeImpl class it adds fine using the...I'm trying to make the Minecraft class implement my MinecraftBridge interface using
```kt
node.interfaces.add(Type.getInternalName(MinecraftBridge::class.java))
```
When I add it to my own MinecraftBridgeImpl class it adds fine using the same code but when I try to add it to the Minecraft class it doesnt add it. No errors are thrown it just writes it without the added interface.
### Expected Behavior
The MinecraftBridge interface is added to the Minecraft class.
### Current Behavior
The MinecraftBridge interface is not added to the Minecraft class.
### Steps to Reproduce
This is the MinecraftBridge interface I'm trying to implement along with the LocalPlayerBridge
```java
public interface LocalPlayerBridge {
void addChatMessage(String msg);
}
public interface MinecraftBridge {
LocalPlayerBridge getLocalPlayer();
}
```
```kt
val reader = ClassReader(/* The Minecraft class bytes */)
val node = ClassNode()
reader.accept(node, 0)
node.interfaces.add(Type.getInternalName(MinecraftBridge::class.java))
val cw = ClassWriter(reader, ClassWriter.COMPUTE_FRAMES)
node.accept(cw)
val bytes = cw.toByteArray()
```
## Example Class Files
The .class is the original class I'm trying to add the interface to. The .modif.class is what ow2.asm
[MinecraftPatch.class](/uploads/c94326e95463a70cd4484194cb31e7fa/MinecraftPatch.class)
[MinecraftPatch.modif.class](/uploads/5a8bf5abcae41b50095c2d78574d040c/MinecraftPatch.modif.class)
[MinecraftBridgeImplPatch.class](/uploads/532a199c44b0463256f905721dc9de1a/MinecraftBridgeImplPatch.class)
[MinecraftBridgeImplPatch.modif.class](/uploads/dcac94cee0b0a2a6d26be642b6ab282c/MinecraftBridgeImplPatch.modif.class)https://gitlab.ow2.org/asm/asm/-/issues/317986Using ClassWriter with COMPUTE_MAXS may generate non-valid frames2022-11-27T08:16:14ZThomas BitontiUsing ClassWriter with COMPUTE_MAXS may generate non-valid frames### Expected Behavior
When performing code injection using COMPUTE_MAXS correct frames should be generated.
### Current Behavior
Non-valid frames may be generated.
### Steps to Reproduce
See the attached projects and test class "com.ib...### Expected Behavior
When performing code injection using COMPUTE_MAXS correct frames should be generated.
### Current Behavior
Non-valid frames may be generated.
### Steps to Reproduce
See the attached projects and test class "com.ibm.l3.util.VerifyClass".
####
**Short Description:** Using ClassWriter with COMPUTE_MAXS may generate non-valid frames.
**Long Description:**
When performing dynamic trace injection using ClassWriter and using flag COMPUTE_MAXS, non-valid frames may be generated. Attempting to load a class with non-valid frames fails with a VerifyError.
The problem is visible comparing byte codes generated using COMPUTE_MAXS with byte codes generated using COMPUTE_FRAMES.
The problem occurs using both v9.3 and v9.4 of ASM (using current published versions on Maven Central).
This non-valid frame was analyzed in detail by the IBM Java L3 support, with the following being the main comment:
> So this means that the VerifyError is correct. The problem is the mismatch between the boolean type found in locals[1] at offset 42, vs the 'top' type specified in the stackmap table, i.e.:
>
> locals = [ class com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager, 'top' ] (locals[0] = 0xc0, locals[1] = 0x1)
>
> The JVM expected the stackmap entry to look something like this:
>
> locals = [ class com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager, '[Z' ] (locals[0] = 0xc0, locals[1] = 0x1002)
####
See the attached archive for a test program which demonstrates the problem. The archive contains three Eclipse projects, "ASM 9.3", "ASM 9.4", and "TraceInjection".
Test class "com.ibm.l3.util.VerifyClass" in project "TraceInjection" reproduces the problem.
The test may be varied in two independent ways:
* By changing between COMPUTE_MAX and COMPUTE_FRAMES.
* By changing between ASM 9.3 and ASM 9.4.
The COMPUTE flag is updated at line 269 of "LibertyRuntimeTransformer.transform":
```
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
// ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
```
The test class performs the following functions:
* Loads the initial byte codes for the class "ZosAssetFactoryManager". These are loaded from "initial/ZosAssetFactoryManager.class".
* Loads the byte codes for the (non-valid) COMPUTE_MAXS generated byte codes. These are loaded from "final/ZosAssetFactoryManager.class".
* Transforms the initial bytes using the Liberty dynamic trace injection, using API com.ibm.ws.ras.instrument.internal.main.LibertyRuntimeTransformer.transform.
* Runs all three versions of the byte codes through the ASM class verifier, which includes the display of the byte codes.
* Does a test load of the byte codes. (Note: In the Eclipse Environment, the Verify error does not occur.)
* Does a comparison of the "final" byte codes with the freshly instrumented byte codes. When COMPUTE_MAXS is set, the freshly instrumented byte codes match the "final" byte codes. When COMPUTE_FRAMES is set, the byte codes do not match.
The project includes Liberty source obtained from the Open Liberty GIT repository: https://github.com/OpenLiberty/open-liberty. The source is current as of 09-Nov-2022.
The project includes source for ASM 9.3 and ASM 9.4, obtained from Maven Central: https://search.maven.org/search?q=org.ow2.asm.
####
The non-valid frames cause class loading to throw a VerifyError:
> ERROR ] TRAS3000E: Runtime injection of detailed method trace failed for class com.ibm.zosconnect.engine.impl.ZosAssetFactoryManager with exception java.lang.reflect.UndeclaredThrowableException
> at com.sun.proxy.$Proxy0.retransformClasses(Unknown Source)
> at com.ibm.ws.ras.instrument.internal.main.LibertyRuntimeTransformer.retransformClass(LibertyRuntimeTransformer.java:250)
> at [internal classes]
> at com.ibm.zosconnect.engine.impl.ZosAssetFactoryManager.(ZosAssetFactoryManager.java:28)
> at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
> at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:83)
> at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:57)
> at java.lang.reflect.Constructor.newInstance(Constructor.java:437)
> at org.apache.felix.scr.impl.inject.internal.ComponentConstructorImpl.newInstance(ComponentConstructorImpl.java:312)
> at [internal classes]
> Caused by: java.lang.reflect.InvocationTargetException
> ... 16 more
> Caused by: java.lang.VerifyError
> ... 18 more
####
Byte code listings. The error is present at line 00017 of the byte codes which were generated using COMPUTE_MAXS.
**Initial:**
```
<init>()V
00000 ZosAssetFactoryManager . : : INVOKESTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.$jacocoInit ()[Z
00001 ZosAssetFactoryManager . : [Z : ASTORE 1
00002 ZosAssetFactoryManager [Z : : ALOAD 0
00003 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : INVOKESPECIAL java/lang/Object.<init> ()V
// TRACE INJECTION POINT
00004 ZosAssetFactoryManager [Z : : ALOAD 1
00005 ZosAssetFactoryManager [Z : [Z : ICONST_0
00006 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00007 ZosAssetFactoryManager [Z : [Z I I : BASTORE
00008 ZosAssetFactoryManager [Z : : ALOAD 0
00009 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : NEW java/util/HashMap
00010 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : DUP
00011 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap HashMap : INVOKESPECIAL java/util/HashMap.<init> ()V
00012 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : PUTFIELD com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.assetFactories : Ljava/util/Map;
00013 ZosAssetFactoryManager [Z : : ALOAD 1
00014 ZosAssetFactoryManager [Z : [Z : ICONST_1
00015 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00016 ZosAssetFactoryManager [Z : [Z I I : BASTORE
// TRACE INJECTION POINT
00017 ZosAssetFactoryManager [Z : : RETURN
```
**Using COMPUTE_MAXS:**
```
<init>()V
00000 ZosAssetFactoryManager . : : INVOKESTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.$jacocoInit ()[Z
00001 ZosAssetFactoryManager . : [Z : ASTORE 1
00002 ZosAssetFactoryManager [Z : : ALOAD 0
00003 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : INVOKESPECIAL java/lang/Object.<init> ()V
// BEGIN INJECTED TRACE
00004 ZosAssetFactoryManager [Z : : INVOKESTATIC com/ibm/websphere/ras/TraceComponent.isAnyTracingEnabled ()Z
00005 ZosAssetFactoryManager [Z : I : IFEQ L0
00006 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00007 ZosAssetFactoryManager [Z : TraceComponent : IFNULL L0
00008 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00009 ZosAssetFactoryManager [Z : TraceComponent : INVOKEVIRTUAL com/ibm/websphere/ras/TraceComponent.isEntryEnabled ()Z
00010 ZosAssetFactoryManager [Z : I : IFEQ L0
00011 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00012 ZosAssetFactoryManager [Z : TraceComponent : LDC "<init>"
00013 ZosAssetFactoryManager [Z : TraceComponent String : LDC 0
00014 ZosAssetFactoryManager [Z : TraceComponent String I : ANEWARRAY java/lang/Object
00015 ZosAssetFactoryManager [Z : TraceComponent String [Object : INVOKESTATIC com/ibm/websphere/ras/Tr.entry (Lcom/ibm/websphere/ras/TraceComponent;Ljava/lang/String;[Ljava/lang/Object;)V
00016 ZosAssetFactoryManager [Z : : L0
00017 ZosAssetFactoryManager [Z : : FRAME FULL [com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager] [] // ***** NON-VALID *****
00018 ZosAssetFactoryManager [Z : : NOP
// END INJECTED TRACE
00019 ZosAssetFactoryManager [Z : : ALOAD 1
00020 ZosAssetFactoryManager [Z : [Z : ICONST_0
00021 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00022 ZosAssetFactoryManager [Z : [Z I I : BASTORE
00023 ZosAssetFactoryManager [Z : : ALOAD 0
00024 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : NEW java/util/HashMap
00025 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : DUP
00026 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap HashMap : INVOKESPECIAL java/util/HashMap.<init> ()V
00027 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : PUTFIELD com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.assetFactories : Ljava/util/Map;
00028 ZosAssetFactoryManager [Z : : ALOAD 1
00029 ZosAssetFactoryManager [Z : [Z : ICONST_1
00030 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00031 ZosAssetFactoryManager [Z : [Z I I : BASTORE
// BEGIN INJECTED TRACE
00032 ZosAssetFactoryManager [Z : : INVOKESTATIC com/ibm/websphere/ras/TraceComponent.isAnyTracingEnabled ()Z
00033 ZosAssetFactoryManager [Z : I : IFEQ L1
00034 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00035 ZosAssetFactoryManager [Z : TraceComponent : IFNULL L1
00036 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00037 ZosAssetFactoryManager [Z : TraceComponent : INVOKEVIRTUAL com/ibm/websphere/ras/TraceComponent.isEntryEnabled ()Z
00038 ZosAssetFactoryManager [Z : I : IFEQ L1
00039 ZosAssetFactoryManager [Z : : ALOAD 0
00040 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : ALOAD 0
00041 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager : SWAP
00042 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00043 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager TraceComponent : SWAP
00044 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent ZosAssetFactoryManager : LDC "<init>"
00045 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent ZosAssetFactoryManager String : SWAP
00046 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent String ZosAssetFactoryManager : INVOKESTATIC com/ibm/websphere/ras/Tr.exit (Ljava/lang/Object;Lcom/ibm/websphere/ras/TraceComponent;Ljava/lang/String;Ljava/lang/Object;)V
00047 ZosAssetFactoryManager [Z : : L1
00048 ZosAssetFactoryManager [Z : : FRAME SAME
// END INJECTED TRACE
00049 ZosAssetFactoryManager [Z : : RETURN
```
**Using COMPUTE_FRAMES:**
```
<init>()V
00000 ZosAssetFactoryManager . : : INVOKESTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.$jacocoInit ()[Z
00001 ZosAssetFactoryManager . : [Z : ASTORE 1
00002 ZosAssetFactoryManager [Z : : ALOAD 0
00003 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : INVOKESPECIAL java/lang/Object.<init> ()V
// BEGIN INJECTED TRACE
00004 ZosAssetFactoryManager [Z : : INVOKESTATIC com/ibm/websphere/ras/TraceComponent.isAnyTracingEnabled ()Z
00005 ZosAssetFactoryManager [Z : I : IFEQ L0
00006 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00007 ZosAssetFactoryManager [Z : TraceComponent : IFNULL L0
00008 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00009 ZosAssetFactoryManager [Z : TraceComponent : INVOKEVIRTUAL com/ibm/websphere/ras/TraceComponent.isEntryEnabled ()Z
00010 ZosAssetFactoryManager [Z : I : IFEQ L0
00011 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00012 ZosAssetFactoryManager [Z : TraceComponent : LDC "<init>"
00013 ZosAssetFactoryManager [Z : TraceComponent String : LDC 0
00014 ZosAssetFactoryManager [Z : TraceComponent String I : ANEWARRAY java/lang/Object
00015 ZosAssetFactoryManager [Z : TraceComponent String [Object : INVOKESTATIC com/ibm/websphere/ras/Tr.entry (Lcom/ibm/websphere/ras/TraceComponent;Ljava/lang/String;[Ljava/lang/Object;)V
00016 ZosAssetFactoryManager [Z : : L0
00017 ZosAssetFactoryManager [Z : : FRAME FULL [com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager [Z] [] // ***** VALID *****
00018 ZosAssetFactoryManager [Z : : NOP
// END INJECTED TRACE
00019 ZosAssetFactoryManager [Z : : ALOAD 1
00020 ZosAssetFactoryManager [Z : [Z : ICONST_0
00021 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00022 ZosAssetFactoryManager [Z : [Z I I : BASTORE
00023 ZosAssetFactoryManager [Z : : ALOAD 0
00024 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : NEW java/util/HashMap
00025 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : DUP
00026 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap HashMap : INVOKESPECIAL java/util/HashMap.<init> ()V
00027 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : PUTFIELD com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.assetFactories : Ljava/util/Map;
00028 ZosAssetFactoryManager [Z : : ALOAD 1
00029 ZosAssetFactoryManager [Z : [Z : ICONST_1
00030 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00031 ZosAssetFactoryManager [Z : [Z I I : BASTORE
// BEGIN INJECTED TRACE
00032 ZosAssetFactoryManager [Z : : INVOKESTATIC com/ibm/websphere/ras/TraceComponent.isAnyTracingEnabled ()Z
00033 ZosAssetFactoryManager [Z : I : IFEQ L1
00034 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00035 ZosAssetFactoryManager [Z : TraceComponent : IFNULL L1
00036 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00037 ZosAssetFactoryManager [Z : TraceComponent : INVOKEVIRTUAL com/ibm/websphere/ras/TraceComponent.isEntryEnabled ()Z
00038 ZosAssetFactoryManager [Z : I : IFEQ L1
00039 ZosAssetFactoryManager [Z : : ALOAD 0
00040 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : ALOAD 0
00041 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager : SWAP
00042 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00043 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager TraceComponent : SWAP
00044 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent ZosAssetFactoryManager : LDC "<init>"
00045 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent ZosAssetFactoryManager String : SWAP
00046 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent String ZosAssetFactoryManager : INVOKESTATIC com/ibm/websphere/ras/Tr.exit (Ljava/lang/Object;Lcom/ibm/websphere/ras/TraceComponent;Ljava/lang/String;Ljava/lang/Object;)V
00047 ZosAssetFactoryManager [Z : : L1
00048 ZosAssetFactoryManager [Z : : FRAME SAME
// END INJECTED TRACE
00049 ZosAssetFactoryManager [Z : : RETURN
```https://gitlab.ow2.org/asm/asm/-/issues/317982Get offsets of instructions in MethodVisitor2022-12-13T07:25:22ZAo LiGet offsets of instructions in MethodVisitorI need to get offsets of instructions in MethodVisitor and I followed the implementation of `CodeSizeEvaluator`, which works for most instructions except for `LDC` and `LDC_W`. `LDC` requires 2 bytes and `LDC_W` requires 3 bytes but they...I need to get offsets of instructions in MethodVisitor and I followed the implementation of `CodeSizeEvaluator`, which works for most instructions except for `LDC` and `LDC_W`. `LDC` requires 2 bytes and `LDC_W` requires 3 bytes but they are both passed to `visitLdcInsn`.
One solution is to pass opcode to `visitLdcInsn` which may break many dependencies.
Another solution is to make `readCode` method in `ClassReader` public or protected so that I can override the method to maintain the code offset manually.
Please let me know if there is another way to solve this issue.https://gitlab.ow2.org/asm/asm/-/issues/317981Add public getDelegate method to all visitor classes.2022-10-01T15:53:55ZraphwAdd public getDelegate method to all visitor classes.Currently, only the RecordComponentVisitor offers a public method for reading the underlying visitor. Sometimes, it is however desirable to communicate with a visitor that lies beneath another visitor also for the other visitor implement...Currently, only the RecordComponentVisitor offers a public method for reading the underlying visitor. Sometimes, it is however desirable to communicate with a visitor that lies beneath another visitor also for the other visitor implementations. Could an equivalent getter be added for the other visitors, too?
Also, would you consider to make the delegate field for the record component visitor protected as with the other visitors? This can be handy when a subclass of a visitor wants to change its delegate after visiting some properties, for example after all attributes were passed. Ideally, ASM would be consistent here.Remi ForaxRemi Foraxhttps://gitlab.ow2.org/asm/asm/-/issues/317976ASM processing error2022-06-12T09:18:53Ztang yanASM processing error![image](/uploads/6b0565ab8bd768716f953a6659b9be5f/image.png)
![image](/uploads/5bc504df5b7e320b4315e9c25c5474d8/image.png)
mv.visitInsn(AALOAD); to case Opcodes.FCONST_2:
![image](/uploads/a86524d3a288b39bb44d0590ba4ec2e7/image.png)![image](/uploads/6b0565ab8bd768716f953a6659b9be5f/image.png)
![image](/uploads/5bc504df5b7e320b4315e9c25c5474d8/image.png)
mv.visitInsn(AALOAD); to case Opcodes.FCONST_2:
![image](/uploads/a86524d3a288b39bb44d0590ba4ec2e7/image.png)https://gitlab.ow2.org/asm/asm/-/issues/317972ClassVisitor inner class and outer class documentation confusing2022-11-27T08:15:23ZtoadstreetClassVisitor inner class and outer class documentation confusing### Expected Behavior
The documentation on `ClassVisitor.visitInnerClass` should mention it is a few inner class relations observed by this class. For instance, classes that use `invokedynamic` instructions compiled by `javac` usually ha...### Expected Behavior
The documentation on `ClassVisitor.visitInnerClass` should mention it is a few inner class relations observed by this class. For instance, classes that use `invokedynamic` instructions compiled by `javac` usually have the `MethodHandles.Lookup` described as a nested class (static inner class) of `MethodHandles` upon inspection by `javap`.
It should also mention that the member classes and the enclosing class of this class, if any, **must** be described in this attribute per [JVMS 18 - 4.7.6](https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.7.6).
The documentation for `ClassVisitor.visitOuterClass` should state it is only called for anonymous or local classes, which are defined in method bodies or initializers. In addition, if the class is defined in an initializer, then the `name` and `descriptor` will be `null`. It is not called for instance inner or nested classes, i.e. classes that are direct members of other classes. Refer to [JVMS 18 - 4.7.7](https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.7.7).
### Current Behavior
The documentation for `ClassVisitor.visitInnerClass` fails to ask users to supply all the member classes and the enclosing class relations of this class.
The documentation for `ClassVisitor.visitOuterClass` fails to mention that it should only be called for anonymous or local classes (i.e. classes defined in method bodies or initializers in source code), and `null` method name and descriptors mean the class is defined in an initializer as opposed to a regular method.
### Notes
In addition, the documentations for the tree API, such as `ClassNode`, should be updated simultaneously.https://gitlab.ow2.org/asm/asm/-/issues/317971java 19 support?2022-06-12T09:19:20ZAndres Luukjava 19 support?ASM Latest release was a year ago and now JDK19 Early-Access Builds is relevant.
As expected currently it get's IllegalArgumentException: Unsupported class file major version 63 when trying to parse a file from there.ASM Latest release was a year ago and now JDK19 Early-Access Builds is relevant.
As expected currently it get's IllegalArgumentException: Unsupported class file major version 63 when trying to parse a file from there.https://gitlab.ow2.org/asm/asm/-/issues/317969The stack calculation logic is inconsistent in ASM5 and ASM92022-03-15T17:13:08ZGodRuiThe stack calculation logic is inconsistent in ASM5 and ASM9I also encountered a similar problem. When I used ASM5 to process this c.class, stack=3 in the bytecode calculated by ASM, and when I upgraded to ASM9, the bytecode calculated by ASM was in stack =2, the configuration of classReader and ...I also encountered a similar problem. When I used ASM5 to process this c.class, stack=3 in the bytecode calculated by ASM, and when I upgraded to ASM9, the bytecode calculated by ASM was in stack =2, the configuration of classReader and classWriter has not been changed, only the ASM version has been upgraded, which caused me to generate a "simException: overflow" error when converting Dex.[c.class](/uploads/b887edbc089201bba4f439b6b389c684/c.class)