首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用api构造FrameNode

用api构造FrameNode
EN

Stack Overflow用户
提问于 2015-04-23 20:26:59
回答 1查看 550关注 0票数 2

我成功地实现了字节码方法的内联优化,生成的代码对我来说似乎还可以。然而,验证失败的消息如下:

代码语言:javascript
复制
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.

相应的字节码是:

代码语言:javascript
复制
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的内联字节码,其最后一个ireturnGOTO替换.

Java7中验证失败的两种可能的解决方案:

  • 为VM参数添加-XX:-UseSplitVerifier。该选项工作正常,但它在Java8中不受欢迎。
  • 在第44行(在GOTO指令之前)之前添加stackmap表,列出跳转目标的位置类型(来自Stackmap框架描述)。

对我来说,选择2更好,但我在框架的构造上有问题。我的代码是:

代码语言:javascript
复制
    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。 参数:

代码语言:javascript
复制
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). 
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-05-01 04:07:11

只要您的字节码是正确的,您可以让asm为您创建框架节点。

我通常这样做:

代码语言:javascript
复制
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编写框架代码。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29833663

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档