我成功地实现了字节码方法的内联优化,生成的代码对我来说似乎还可以。然而,验证失败的消息如下:
java.lang.VerifyError: Expecting a stackmap frame at branch target 47
Exception Details:
Location:
code/sxu/asm/example/Caller.test(II)V @44: goto
Reason:
Expected stackmap frame at this location.相应的字节码是:
public void test(int, int);
flags: ACC_PUBLIC
Code:
stack=4, locals=8, args_size=3
0: iload_1
1: iload_2
2: iadd
3: aload_0
4: getfield #14 // Field _callee:Lcode/sxu/asm/example/Callee;
7: iload_1
8: iload_2
9: istore_3
10: istore 4
12: astore 5
14: aload 5
16: getfield #40 // Field code/sxu/asm/example/Callee._a:Ljava/lang/String;
19: invokevirtual #46 // Method java/lang/String.length:()I
22: aload 5
24: getfield #49 // Field code/sxu/asm/example/Callee._b:Ljava/lang/String;
27: invokevirtual #46 // Method java/lang/String.length:()I
30: iadd
31: istore 6
33: iload 6
35: iload 4
37: iload_3
38: iadd
39: iadd
40: istore 6
42: iload 6
44: goto 47
47: isub
48: istore 7
50: getstatic #59 // Field java/lang/System.out:Ljava/io/PrintStream;
53: iload 7
55: invokevirtual #65 // Method java/io/PrintStream.println:(I)V
58: getstatic #59 // Field java/lang/System.out:Ljava/io/PrintStream;
61: ldc #67 // String 1..........
63: invokevirtual #70 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
66: return
LocalVariableTable:
Start Length Slot Name Signature
14 33 0 this Lcode/sxu/asm/example/Callee;
14 33 1 t I
14 33 2 p I
33 14 7 tmp I
0 67 0 this Lcode/sxu/asm/example/Caller;
0 67 1 a I
0 67 2 b I
50 17 7 r I
LineNumberTable:
line 16: 0
line 13: 14
line 14: 33
line 15: 42
line 18: 50
line 19: 58
line 20: 66
}第9-11行:存储堆叠参数.第14-44行: Callee的内联字节码,其最后一个ireturn被GOTO替换.
Java7中验证失败的两种可能的解决方案:
-XX:-UseSplitVerifier。该选项工作正常,但它在Java8中不受欢迎。对我来说,选择2更好,但我在框架的构造上有问题。我的代码是:
if (opcode == Opcodes.RETURN || opcode == Opcodes.IRETURN) {
FrameNode stackMap = new FrameNode(Opcodes.NEW, -1, null, -1, null);
stackMap.accept(mv); //Visit The framenode before GOTO
super.visitJumpInsn(Opcodes.GOTO, end);
} else {
super.visitInsn(opcode);
}我认为两个Opcodes.NEW/SMAE都应该在这里工作。但是不可能计算出其余的四个参数,因为访问者没有访问目标代码,并且不知道nStack,n局部变量。
那么,在这里构建或示例以处理这种情况时,有人能给出建议吗?谢谢,
FramNodeFrameNode ASM文档的描述:
公共FrameNode(int类型,int nLocal,Object[] local,int nStack,Object[]堆栈) 构造一个新的FrameNode。 参数:
type - the type of this frame. Must be Opcodes.F_NEW for expanded frames, or Opcodes.F_FULL, Opcodes.F_APPEND, Opcodes.F_CHOP, Opcodes.F_SAME or Opcodes.F_APPEND, Opcodes.F_SAME1 for compressed frames.
nLocal - number of local variables of this stack map frame.
local - the types of the local variables of this stack map frame. Elements of this list can be Integer, String or LabelNode objects (for primitive, reference and uninitialized types respectively - see MethodVisitor).
nStack - number of operand stack elements of this stack map frame.
stack - the types of the operand stack elements of this stack map frame. Elements of this list can be Integer, String or LabelNode objects (for primitive, reference and uninitialized types respectively - see MethodVisitor). 发布于 2015-05-01 04:07:11
只要您的字节码是正确的,您可以让asm为您创建框架节点。
我通常这样做:
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES)
{
@Override
protected String getCommonSuperClass(final String type1, final String type2)
{
// the default asm merge uses Class.forName(), this prevents that.
return "java/lang/Object";
}
};
cn.accept(cw);说明:使用COMPUTE_FRAMES初始化类编写器,并避免类加载问题覆盖getCommonSuperClass。
假设您使用任何路径生成字节码(访问者、ClassNode等)最终,您将使用一个ClassWriter来生成类字节。
如果您确实希望手动执行,请先尝试此操作,然后使用asmifier查看如何使用asm编写框架代码。
https://stackoverflow.com/questions/29833663
复制相似问题