使用visitJumpInsn的java.lang.VerifyError

时间:2013-10-30 12:04:12

标签: bytecode instrumentation java-bytecode-asm bytecode-manipulation

我试图将asm用于BCI,我有一个要求,我应该注入“if condition”,所以我尝试使用下面的东西

 Below is the code snippet..if i comment the jump instruction things work fine..with jump instruction i see verifyerror

@Override
protected void onMethodEnter() {
    try{            
    visitor.visitVarInsn(ALOAD, 0);
    visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
    Label jump = new Label();
    visitor.visitJumpInsn(IFEQ,jump);
    visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello","(Z)V");
    visitor.visitVarInsn(ALOAD, 0);
    visitor.visitInsn(ICONST_1);
    visitFieldInsn(PUTFIELD, "com/vish/MyWrapper", "isCached", "Z");
    visitor.visitLabel(jump);
    visitor.visitVarInsn(ALOAD, 0);
    visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
    visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello",
            "()V");
    }catch(Exception e){
        e.printStackTrace();
    }
}

但是当我尝试运行时,我得到以下异常

java.lang.VerifyError: JVMVRFY036 stack underflow; class=com/vish/MyWrapper, method=service()V, pc=10
       at java.lang.J9VMInternals.verifyImpl(Native Method)
       at java.lang.J9VMInternals.verify(J9VMInternals.java:72)
       at java.lang.J9VMInternals.verify(J9VMInternals.java:70)
       at java.lang.J9VMInternals.initialize(J9VMInternals.java:134)

如果我评论跳转指令,那么一切正常。

我做了一些阅读并且发现由于使用了JumpInstructions而有可能弄乱堆栈映射帧,并且还读到使用COMPUTE_FRAMES选项和SKIP_FRAMES将导致堆栈映射帧的自动计算< / p>

“public static final int COMPUTE_FRAMES 标记以从头开始自动计算方法的堆栈映射帧。如果设置了此标志,则忽略对MethodVisitor.visitFrame(int,int,java.lang.Object [],int,java.lang.Object [])方法的调用,并从中重新计算堆栈映射帧。方法字节码。 visitMaxs方法的参数也被忽略并从字节码重新计算。换句话说,computeFrames意味着computeMaxs。“

任何人都可以解释我在做什么错误。我还需要在跳转指令的情况下计算堆栈映射帧吗?如果是这样的话,可以在某个地方获取样本堆栈映射帧的计算方法吗? ?

由于

2 个答案:

答案 0 :(得分:1)

这里介绍的指令:

visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello","(Z)V");

...在堆栈上需要一个布尔(整数)参数。如果IFEQ存在,则堆栈为空。如果您注释掉IFEQ,则堆栈具有参数。堆栈下溢是通过调用方法而没有堆栈上的必要参数引起的。这与堆栈帧映射无关。

答案 1 :(得分:1)

问题在于你错过了第一个sayHello的参数。如果您想传递getCached的结果,则需要在其前添加另一个visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");

假设这是预期的,代码应该是

visitor.visitVarInsn(ALOAD, 0);
visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
Label jump = new Label();
visitor.visitJumpInsn(IFEQ,jump);
visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello","(Z)V");
visitor.visitVarInsn(ALOAD, 0);
visitor.visitInsn(ICONST_1);
visitFieldInsn(PUTFIELD, "com/vish/MyWrapper", "isCached", "Z");
visitor.visitLabel(jump);
visitor.visitVarInsn(ALOAD, 0);
visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello",
        "()V");