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

ASM 5: when initializing a ClassWriter, what is the difference between COMPUTE_MAXS and COMPUTE_FRAMES?

我是 grappa 的维护者。此包在运行时从 Java 代码生成解析器,方法是使用 ASM 生成 class 扩展您的解析器 class.

我已经从 ASM 4 迁移到 ASM 5,从生成 JVM 1.5 字节码迁移到生成 JVM 1.6 字节码,现在我刚刚成功地让它生成 JVM 1.7 字节码......除了我不知道为什么 这行得通。

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

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

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

首先,COMPUTE_FRAMESCOMPUTE_MAXS

的一些背景知识

ClassWriter.COMPUTE_MAXSClassWriter.COMPUTE_FRAMES 的功能不同。

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

当然,编译器 必须生成这些帧。这也很困难,因此 ASM 包含 ClassWriter.COMPUTE_FRAMES 以允许这样做 - 然后它会为您计算它们。

现在,ClassWriter.COMPUTE_MAXS 做了类似的事情:JVM 要求 class 文件指定每个方法使用的最大堆栈大小和变量数,以便它可以验证这一点必须自己计算这些。由于与堆栈帧类似的原因,这很有用:计算成本较低。

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

第一题

对于 MethodVisitor,仍然需要 visitMaxs 调用。正是在这一点上,ASM 将重新计算帧数和最大值。它只会忽略你给它的参数。所以,不,你不能删除它们。 (另请注意,它实际上并不是一条指令。)

第二个问题

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