ASM 5:初始化ClassWriter时,COMPUTE_MAXS和COMPUTE_FRAMES之间有什么区别?

fge*_*fge 9 java jvm bytecode-manipulation java-bytecode-asm

我是格拉巴酒的维护者.此包通过使用ASM生成一个扩展解析器类的类,从Java代码在运行时生成解析器.

我已经从ASM 4迁移到ASM 5,从生成JVM 1.5字节码到生成JVM 1.6字节码,现在我已经成功生成了JVM 1.7字节码而不是......除了我不知道为什么这样做.

基本上,我做了以下事情:

  • 将参数更改为ClassWriter构造函数; 在它之前,它new ClassWriter(ClassWriter.COMPUTE_MAXS)现在是new ClassWriter(ClassWriter.COMPUTE_FRAMES)
  • 将每个调用.visit()方法的第一个参数更改Opcodes.V1_6Opcodes.V1_7.

现在,为什么我不明白为什么它有效有两个原因:

  • 我有几个电话给MethodVisitors:

    mv.visitMaxs(0, 0); // trigger automatic computing
    
    Run Code Online (Sandbox Code Playgroud)

    这是否意味着可以删除这些说明?

  • 起初我只是尝试和添加COMPUTE_FRAMES参数的ClassWriter构造函数,但它没有在一个点为我的测试中,我宣布一个:

    static class TestJoinParser
        extends EventBusParser<Object>
    {
        protected final JoinMatcherBuilder builder
            = join('a').using('b');
    }
    
    Run Code Online (Sandbox Code Playgroud)

    错误是:

    java.lang.ClassFormatError: Arguments can't fit into locals
    
    Run Code Online (Sandbox Code Playgroud)

    鉴于它是一个实例字段,我想它与在构造函数中初始化的特定参数有关吗?

无论如何,我所有的测试现在都有效,我正在尝试更重的测试......但是我的目标是更进一步,我想至少了解为什么我的修改工作了... .

Cel*_*ggs 10

首先,一些背景COMPUTE_FRAMESCOMPUTE_MAXS

ClassWriter.COMPUTE_MAXS有一个不同的功能ClassWriter.COMPUTE_FRAMES.

在最新版本的JVM中,类包含堆栈映射以及方法代码.此映射描述了方法执行期间关键点(跳转目标)的堆栈布局.在以前的版本中,JVM必须计算此信息,这在计算上是昂贵的.通过要求此信息,JVM可以只验证框架是否有效,这比重新计算所有内容要容易得多.

当然,编译器必须生成这些帧.这也很困难,所以ASM包含ClassWriter.COMPUTE_FRAMES允许这一点 - 然后它会为你计算它们.

现在,ClassWriter.COMPUTE_MAXS执行类似的操作:JVM要求类文件指定每个方法使用的最大堆栈大小和变量数,以便它可以只验证这个而不必自己计算.这对于堆叠帧的类似原因很有用:它的计算成本较低.

所以,实际上,你想要两个!但是,正如您所说,当您尝试添加它时失败了.可能的答案在于文档ClassWriter.COMPUTE_FRAMES(当你对它感到困惑时,你应该首先看看它):它说"computeFrames意味着computeMaxs".因此,您只需指定即可ClassWriter.COMPUTE_FRAMES.

第一个问题

使用MethodVisitors,visitMaxs仍然需要呼叫ARE.此时ASM将重新计算帧和最大值.它只会忽略你给它的论据.所以,不,你不能删除它们.(另请注意,它实际上并不是指令.)

第二个问题

我在上面解释了为什么只使用它就足够了COMPUTE_FRAMES,这是这里的关键部分.我不确定为什么指定两个标志会破坏你的测试.如果您可以提供您在那里所做的确切代码,那么可能会有所帮助.我在ClassWriter/ MethodWritersource 上做了一些资源潜水,并且似乎没有任何理由说明为什么两者都会破坏你的代码.