ASM - 使用来自 LocalVariableSorter 的 newLocal 的奇怪 localVar 索引
ASM - strange localVar index using newLocal from LocalVariableSorter
我正在通过 newLocal
从 LocalVariableSorter
添加新的本地人。我要将局部变量添加到的方法是一个带有长参数的实例方法。我要加两个当地人;一长一物。示例代码中没有其他本地变量。
因此,我预计会有以下插槽/索引:
0 - this
1 - the long param
3 - my 1st local added via `newLocal` - using two slots as it is a long
5 - my 2nd local added via `newLocal`
我从 newLocal
得到的 return 是 3 和 7。为什么会有这么大的差距?
让事情变得更奇怪的是,当我使用这些索引添加 xSTORE
指令并使用 javap 检查结果时,它显示:
LSTORE 5
ASTORE 8
注意:不仅值与我传递给 xSTORE 指令的值不同,而且它们之间的差距现在是 3,而不是以前的 4。
生成的代码虽然有效。我只想了解这里发生的 magic 是什么以及原因。
谢谢
LocalVariableSorter
class有一个设计,很容易用错
在其上调用MethodVisitor
API定义的方法时,局部变量会进行class documentation.
中提到的重新编号
因此,当与 ClassReader
一起使用时,访问的旧代码会被转换。由于您不希望注入的新代码进行此转换,而是要使用新定义的变量,因此您必须绕过 LocalVariableSorter
并在基础目标 MethodVisitor
.[= 上调用方法39=]
当您在 LocalVariableSorter
上调用 visitVarInsn(LSTORE, 3)
时,它会像引用索引 3
的旧指令一样处理,因为您注入了一个占用索引 3
的新变量和 4
,索引 3
处的“旧变量”被重新映射到下一个空闲索引,即 5
(和 6
)。然后,当您定义下一个新变量时,它会获得索引 7
并在 LocalVariableSorter
上调用 visitVarInsn(ASTORE, 7)
就像处理与新变量冲突的旧变量一样,因此它会重新映射到8
.
此行为与 class 文档的第一句完全一致:
LocalVariablesSorter
A MethodVisitor that renumbers local variables in their order of appearance.
因此,虽然您必须在 LocalVariableSorter
上调用 newLocal
来创建一个不会重新映射的新变量,但您必须在原始变量上调用 visit…
方法,包装 MethodVisitor
以使用它。当您使用 subclass GeneratorAdapter
时,您可以使用其新定义的方法(那些不以 visit…
开头的方法)来创建不被转换的新指令,但对我来说,这会使事情变得更糟,拥有转换指令的方法并在相同的 class 上创建未转换的指令,并且始终需要记住 visit…
前缀会有所不同。对于某些方法,您仍然需要访问原始方法访问者,如 中讨论的那样,它处理 visitLocalVariable
以创建已创建变量的调试信息。
我正在通过 newLocal
从 LocalVariableSorter
添加新的本地人。我要将局部变量添加到的方法是一个带有长参数的实例方法。我要加两个当地人;一长一物。示例代码中没有其他本地变量。
因此,我预计会有以下插槽/索引:
0 - this
1 - the long param
3 - my 1st local added via `newLocal` - using two slots as it is a long
5 - my 2nd local added via `newLocal`
我从 newLocal
得到的 return 是 3 和 7。为什么会有这么大的差距?
让事情变得更奇怪的是,当我使用这些索引添加 xSTORE
指令并使用 javap 检查结果时,它显示:
LSTORE 5
ASTORE 8
注意:不仅值与我传递给 xSTORE 指令的值不同,而且它们之间的差距现在是 3,而不是以前的 4。
生成的代码虽然有效。我只想了解这里发生的 magic 是什么以及原因。
谢谢
LocalVariableSorter
class有一个设计,很容易用错
在其上调用MethodVisitor
API定义的方法时,局部变量会进行class documentation.
因此,当与 ClassReader
一起使用时,访问的旧代码会被转换。由于您不希望注入的新代码进行此转换,而是要使用新定义的变量,因此您必须绕过 LocalVariableSorter
并在基础目标 MethodVisitor
.[= 上调用方法39=]
当您在 LocalVariableSorter
上调用 visitVarInsn(LSTORE, 3)
时,它会像引用索引 3
的旧指令一样处理,因为您注入了一个占用索引 3
的新变量和 4
,索引 3
处的“旧变量”被重新映射到下一个空闲索引,即 5
(和 6
)。然后,当您定义下一个新变量时,它会获得索引 7
并在 LocalVariableSorter
上调用 visitVarInsn(ASTORE, 7)
就像处理与新变量冲突的旧变量一样,因此它会重新映射到8
.
此行为与 class 文档的第一句完全一致:
LocalVariablesSorter
A MethodVisitor that renumbers local variables in their order of appearance.
因此,虽然您必须在 LocalVariableSorter
上调用 newLocal
来创建一个不会重新映射的新变量,但您必须在原始变量上调用 visit…
方法,包装 MethodVisitor
以使用它。当您使用 subclass GeneratorAdapter
时,您可以使用其新定义的方法(那些不以 visit…
开头的方法)来创建不被转换的新指令,但对我来说,这会使事情变得更糟,拥有转换指令的方法并在相同的 class 上创建未转换的指令,并且始终需要记住 visit…
前缀会有所不同。对于某些方法,您仍然需要访问原始方法访问者,如 visitLocalVariable
以创建已创建变量的调试信息。