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 字节码......除了我不知道为什么 这行得通。
基本上,我做了以下事情:
- 正在更改 ClassWriter 构造函数的参数;之前是
new ClassWriter(ClassWriter.COMPUTE_MAXS)
,现在是 new ClassWriter(ClassWriter.COMPUTE_FRAMES)
- 将每次调用
.visit()
方法的第一个参数从 Opcodes.V1_6
更改为 Opcodes.V1_7
。
现在,为什么我不明白为什么它起作用有两个原因:
我有好几次打电话给 MethodVisitor
s,上面写着:
mv.visitMaxs(0, 0); // trigger automatic computing
这是否意味着可以删除这些指令?
起初我只尝试 添加 COMPUTE_FRAMES
构造函数的 COMPUTE_FRAMES
参数,但有一次失败了我声明的一项测试:
static class TestJoinParser
extends EventBusParser<Object>
{
protected final JoinMatcherBuilder builder
= join('a').using('b');
}
错误是:
java.lang.ClassFormatError: Arguments can't fit into locals
鉴于它是一个实例字段,我想它与在构造函数中初始化的特定参数有关?
无论如何,我所有的测试现在都有效,我正在尝试更重的测试等......但由于我的目标是更进一步,我想至少了解一点为什么我的修改完全有效...
首先,COMPUTE_FRAMES
和 COMPUTE_MAXS
的一些背景知识
ClassWriter.COMPUTE_MAXS
与 ClassWriter.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
源上做了一些源代码潜水,似乎没有任何理由说明为什么同时指定两者会破坏您的代码。
我是 grappa 的维护者。此包在运行时从 Java 代码生成解析器,方法是使用 ASM 生成 class 扩展您的解析器 class.
我已经从 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_6
更改为Opcodes.V1_7
。
现在,为什么我不明白为什么它起作用有两个原因:
我有好几次打电话给
MethodVisitor
s,上面写着:mv.visitMaxs(0, 0); // trigger automatic computing
这是否意味着可以删除这些指令?
起初我只尝试 添加
COMPUTE_FRAMES
构造函数的COMPUTE_FRAMES
参数,但有一次失败了我声明的一项测试:static class TestJoinParser extends EventBusParser<Object> { protected final JoinMatcherBuilder builder = join('a').using('b'); }
错误是:
java.lang.ClassFormatError: Arguments can't fit into locals
鉴于它是一个实例字段,我想它与在构造函数中初始化的特定参数有关?
无论如何,我所有的测试现在都有效,我正在尝试更重的测试等......但由于我的目标是更进一步,我想至少了解一点为什么我的修改完全有效...
首先,COMPUTE_FRAMES
和 COMPUTE_MAXS
的一些背景知识
ClassWriter.COMPUTE_MAXS
与 ClassWriter.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
源上做了一些源代码潜水,似乎没有任何理由说明为什么同时指定两者会破坏您的代码。