【问题标题】:Java ASM Generate Catch BlockJava ASM 生成 Catch 块
【发布时间】:2015-03-14 21:36:01
【问题描述】:

我正在尝试使用我的编译器中的 ASM 框架编译 Try/Catch 块(这意味着 try 块、处理程序块和变量是动态的)。这是我的代码目前的样子:

    org.objectweb.asm.Label tryStart = new org.objectweb.asm.Label();
    org.objectweb.asm.Label tryEnd = new org.objectweb.asm.Label();
    org.objectweb.asm.Label endLabel = new org.objectweb.asm.Label();

    writer.writeLabel(tryStart);
    if (this.action != null)
    {
        this.action.writeStatement(writer);
        writer.writeJumpInsn(Opcodes.GOTO, endLabel);
    }
    writer.writeLabel(tryEnd);

    for (int i = 0; i < this.catchBlockCount; i++)
    {
        CatchBlock block = this.catchBlocks[i];
        org.objectweb.asm.Label handlerLabel = new org.objectweb.asm.Label();
        int varIndex;

        writer.push(block.type);
        // Check if the block's variable is actually used
        if (block.variable != null)
        {
            // If yes register a new local variable for the exception and
            // store it.
            varIndex = block.variable.index = writer.registerLocal(block.type);
            writer.writeFrameLabel(handlerLabel);
            writer.writeVarInsn(Opcodes.ASTORE, varIndex);
            block.action.writeStatement(writer);
            writer.removeLocals(1);
        }
        // Otherwise pop the exception from the stack
        else
        {
            varIndex = -1;
            writer.writeFrameLabel(handlerLabel);
            writer.writeInsn(Opcodes.POP);
            block.action.writeStatement(writer);
        }

        writer.writeTryCatchBlock(tryStart, tryEnd, handlerLabel, block.type);
        writer.writeJumpInsn(Opcodes.GOTO, endLabel);
    }
    writer.writeFrameLabel(endLabel);

但是,此实现会生成以下VerifyError

java.lang.VerifyError: Stack map does not match the one at exception handler 20
Exception Details:
  Location:
    dyvil/test/Main.main([Ljava/lang/String;)V @20: astore_1
  Reason:
    Type top (current frame, locals[1]) is not assignable to 'Ljava/lang/Exception;' (stack map, locals[1])
  Current Frame:
    bci: @0
    flags: { }
    locals: { '[Ljava/lang/String;' }
    stack: { 'java/lang/Exception' }
  Stackmap Frame:
    bci: @20
    flags: { }
    locals: { '[Ljava/lang/String;', 'Ljava/lang/Exception;' }
    stack: { 'Ljava/lang/Exception;' }
  Bytecode:
    0000000: b200 1312 15b6 001b b200 1304 036c b600
    0000010: 1ea7 0013 4cb2 0013 1224 b600 1b2b b600
    0000020: 29a7 0003 b1                           
  Exception Handler Table:
    bci [0, 20] => handler: 20
  Stackmap Table:
    full_frame(@20,{Object[#32],Object[#34]},{Object[#34]})
    chop_frame(@36,1)

(注意writerwriteX 开头的方法只是委托给MethodVisitor.visitXwriteFrameLabel 还告诉MethodWriter 它应该在编写下一条指令之前生成一个堆栈帧)

【问题讨论】:

  • 您是否创建了带有ClassWriter.COMPUTE_FRAMES 选项的ClassWriter 并且课程版本为1.6+?
  • 出于性能原因,这正是我试图通过使用自定义 MethodWriter 来避免的。课程版本设置为 1.8。

标签: java jvm java-bytecode-asm verifyerror


【解决方案1】:

我设法自己找到了解决方案,通过替换这部分:

varIndex = block.variable.index = writer.registerLocal(block.type);
writer.writeFrameLabel(handlerLabel);
writer.writeVarInsn(Opcodes.ASTORE, varIndex);

有了这个:

writer.writeLabel(handlerLabel);
writer.writeFrame();
varIndex = block.variable.index = writer.registerLocal(block.type);
writer.writeVarInsn(Opcodes.ASTORE, varIndex);

基本上,ASTORE 的堆栈映射帧不应该包含局部变量,而是应该在帧之后初始化局部变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 2015-05-09
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    相关资源
    最近更新 更多