我在使用 Guava 库运行一个简单的主程序时遇到了一些问题。
我已使用此处的代码对类进行检测以获取方法参数:Java method parameters values in ASM
问题是,虽然代码适用于小型项目(又名汉诺塔),但使用 Guava 我会遇到错误和异常。
特别是在测试 Joiner.join 方法时,我有这个错误:
Exception in thread "Jalen Agent" java.lang.VerifyError: (class: com/google/common/base/Joiner, method: withKeyValueSeparator signature: (Ljava/lang/String;)Lcom/google/common/base/Joiner$MapJoiner;) Incompatible argument to function
at Main.joinBench(Main.java:42)
at Main.main(Main.java:20)
当使用 -noverify 运行示例时,出现异常:
Exception in thread "Jalen Agent" java.lang.ArrayIndexOutOfBoundsException: 1
at com.google.common.base.Joiner.<init>(Joiner.java)
at com.google.common.base.Joiner.on(Joiner.java:71)
at Main.joinBench(Main.java:42)
at Main.main(Main.java:20)
方法的字节码是一致的:
public static com.google.common.base.Joiner on(java.lang.String);
Code:
0: bipush 1
2: anewarray #4 // class java/lang/Object
5: astore_1
6: aload_1
7: bipush 0
9: aload_0
10: aastore
11: ldc #20 // int 369
13: ldc #21 // String com/google/common/base/Joiner
15: ldc #22 // String on
17: aload_1
18: invokestatic #28 // Method jalen/MethodStats.onMethodEntry:(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
21: new #2 // class com/google/common/base/Joiner
24: dup
25: aload_0
26: invokespecial #32 // Method "<init>":(Ljava/lang/String;)V
29: ldc #20 // int 369
31: invokestatic #36 // Method jalen/MethodStats.onMethodExit:(I)V
34: areturn
我知道错误可能与库版本有关,但主要 java 程序是针对检测库编译的,并使用库的相同 jar 运行。
关于为什么会发生这种情况的任何想法?又如何解决?
谢谢:)
编辑
这是检测前后 withKeyValueSeparator 方法的字节码
原始字节码:
public com.google.common.base.Joiner$MapJoiner withKeyValueSeparator(java.lang.String);
Code:
0: new #33 // class com/google/common/base/Joiner$MapJoiner
3: dup
4: aload_0
5: aload_1
6: aconst_null
7: invokespecial #34 // Method com/google/common/base/Joiner$MapJoiner."<init>":(Lcom/google/common/base/Joiner;Ljava/lang/String;Lcom/google/common/base/Joiner$1;)V
10: areturn
检测字节码:
public com.google.common.base.Joiner$MapJoiner withKeyValueSeparator(java.lang.String);
Code:
0: bipush 1
2: anewarray #4 // class java/lang/Object
5: astore_1
6: aload_1
7: bipush 1
9: aload_1
10: aastore
11: ldc #199 // int 390
13: ldc #21 // String com/google/common/base/Joiner
15: ldc #200 // String withKeyValueSeparator
17: aload_1
18: invokestatic #28 // Method jalen/MethodStats.onMethodEntry:(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
21: new #8 // class com/google/common/base/Joiner$MapJoiner
24: dup
25: aload_0
26: aload_1
27: aconst_null
28: invokespecial #203 // Method com/google/common/base/Joiner$MapJoiner."<init>":(Lcom/google/common/base/Joiner;Ljava/lang/String;Lcom/google/common/base/Joiner$1;)V
31: ldc #199 // int 390
33: invokestatic #36 // Method jalen/MethodStats.onMethodExit:(I)V
36: areturn
这里是 joiner 类的完整字节码:
最佳答案
withKeyValueSeparator
的原始代码将它的一堆参数传递给 MapJoiner
构造函数。您正在添加将数组存储在局部变量表的第二个槽中的检测代码(使用 astore_1
)。这会覆盖 withKeyValueSeparator
的第一个参数,它是一个 String
。 (局部变量表的第一个槽是一个 MapJoiner
实例本身,又名 this
。)所以当原始函数的代码试图传递第二个槽中的对象时构造函数的局部变量表,存在“参数不兼容”错误。
要解决这个问题,您应该在局部变量表中为您的数组分配一个新槽; this answer概述了方法。
关于java - 与 ASM 字节码检测功能不兼容的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14155614/