我一直在尝试使用java中的ASM库来插装分支相关的代码,假设这是我想插装的一段代码:
if (true) {
System.out.println("true");
} else {
System.out.println("false");
}
下面是我的代码:
//put true on stack
mv.visitInsn(Opcodes.ICONST_1);
//create labels
Label elseLabel = new Label();
Label endLabel = new Label();
mv.visitJumpInsn(Opcodes.IFEQ, elseLabel);
// instrument code for the "if" block
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("true");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
mv.visitJumpInsn(Opcodes.GOTO, endLabel);
mv.visitLabel(elseLabel);
//instrument code for else block
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("false");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
mv.visitLabel(endLabel);
可以使用Intellij自己的反编译器正确地显示和解释插入的字节码。
但是,代码无法运行,存在VerifyError x1c 0d1x
而这是运行“javap -c”命令生成的可读字节码。
public void doSomething1();
Code:
0: aload_0
1: invokevirtual #5 // Method doSomething:()V
4: iconst_1
5: invokestatic #6 // Method org/junit/jupiter/api/Assertions.assertTrue:(Z)V
8: iconst_1
9: ifeq 23
12: getstatic #44 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #46 // String true
17: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: goto 31
23: getstatic #44 // Field java/lang/System.out:Ljava/io/PrintStream;
26: ldc #48 // String false
28: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
31: return
}
你能帮我一下吗?谢谢!
1条答案
按热度按时间7gyucuyw1#
添加字节码是没有错误的。但是,只需传递ClassWriter.COMPUTE_FRAME而不是ClassWriter.ComputeMax就可以解决这个问题。(感谢JohannesKuhn和任何帮助过我的人)。红色标记的VerifyError表明了这一点(尽管我不知道)。
COMPUTE_MAX似乎适用于java5或更早版本。