How can I use ASM lib in java to instrument an if-else block?

173 Views Asked by At

I've been trying to instrument branch-related code using ASM lib in java. Suppose this is a period of code I want to instrument:

        if (true) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }

Here is my code for instrumentation:

            //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);

The instrumented byte code can be shown and interpreted correctly with Intellij's own decompiler.

However, the code cannot be run, there is VerifyError enter image description here

And this is the readable bytecode generated by running "javap -c" command.

 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
}

Could you please help me with that? Thank you!

1

There are 1 best solutions below

1
a stand-out flamingo On

There is no mistake in adding bytecode. However, it is solved simply by passing ClassWriter.COMPUTE_FRAME rather than ClassWriter.ComputeMaxs.(Thanks Johannes Kuhn and anyone who helped me). And red-flagged VerifyError indicates that (though I don't know).

COMPUTE_MAX seems to work for java5 or earlier.