Java ASM 生成捕获块
Java ASM Generate Catch Block
我正在尝试使用我的编译器中的 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)
(请注意,writer
以 writeX
开头的方法只是对 MethodVisitor.visitX
的委托。writeFrameLabel
还告诉 MethodWriter
它应该生成写入下一条指令之前的堆栈帧)
我通过替换这部分设法自己找到了解决方案:
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
处的堆栈映射帧不应该包含局部变量,而是应该在帧之后初始化局部变量。
我正在尝试使用我的编译器中的 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)
(请注意,writer
以 writeX
开头的方法只是对 MethodVisitor.visitX
的委托。writeFrameLabel
还告诉 MethodWriter
它应该生成写入下一条指令之前的堆栈帧)
我通过替换这部分设法自己找到了解决方案:
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
处的堆栈映射帧不应该包含局部变量,而是应该在帧之后初始化局部变量。