ASM - 奇怪的localVar索引,使用来自LocalVariableSorter的newLocal



我正在通过LocalVariableSorternewLocal添加新的当地人。我添加局部变量的方法是一个带有长参数的实例方法。我正在添加两个当地人;一个长,一个对象。示例代码中没有其他本地变量。

因此,我本期望以下插槽/索引:

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得到的回报是 3 和 7。为什么差距这么大?

更奇怪的是,当我使用这些索引添加xSTORE指令并使用javap检查结果时,它会显示:

LSTORE 5
ASTORE 8

注意:不仅这些值与我传递给 xSTORE 指令的值不同,而且它们之间的差距现在是 3,而不是以前的 4。

不过,生成的代码有效。我只是想了解这里发生了什么魔术以及为什么。

谢谢

LocalVariableSorter类有一个设计,这使得它很容易被错误地使用。

当调用MethodVisitorAPI 在其上定义的方法时,局部变量将经历类文档中提到的重新编号。

因此,当与ClassReader一起使用时,访问的旧代码会被转换。由于您不希望注入的新代码进行此转换,而是要使用新定义的变量,因此您必须绕过LocalVariableSorter并在基础目标MethodVisitor上调用方法。

当你在LocalVariableSorter上调用visitVarInsn(LSTORE, 3)时,它被处理得像引用索引3的旧指令一样,并且由于你注入了一个占用索引的新变量34,索引3处的"旧变量"被重新映射到下一个自由索引,即5(和6(。然后,当您定义下一个新变量时,它会获得索引7,并且在LocalVariableSorter上调用visitVarInsn(ASTORE, 7)就像处理与新变量冲突的旧变量一样,因此它会重新映射到8

此行为与类文档的第一句话完全匹配:

LocalVariablesSorter

一个 MethodVisiter,它按局部变量的出现顺序重新编号。

因此,虽然您必须在LocalVariableSorter上调用newLocal以创建一个不会被重新映射的新变量,但您必须在原始包装MethodVisitor上调用visit…方法才能使用它。当你使用子类GeneratorAdapter时,你可以使用它新定义的方法(那些不以visit…开头的方法(来创建不会被转换的新指令,但对我来说,这会让事情变得更糟,有方法转换指令和在同一类上创建未转换的指令,并且始终需要记住visit…前缀会有所不同。对于某些方法,您仍然需要访问原始方法访问者,如本答案中所述,该答案涉及为创建的变量创建调试信息visitLocalVariable

相关内容

  • 没有找到相关文章

最新更新