我正在通过newLocal从LocalVariableSorter添加新的本地用户。我要添加局部变量的方法是一个具有长参数的实例方法。我要增加两个局部变量,一个长的,一个对象。在示例代码中没有其他本地vars。
因此,我希望看到以下时隙/索引:
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。
但是,生成的代码可以工作。我只想了解一下这里发生了什么魔法以及原因。
谢谢
发布于 2018-05-03 08:46:35
LocalVariableSorter类有一个设计,这使得它很容易使用错误。
当调用由MethodVisitor API定义的方法时,局部变量将经历类文档中提到的重命名。
因此,当与ClassReader一起使用时,访问的旧代码将被转换。由于您不希望注入的新代码经历这种转换,而是要使用新定义的变量,所以您必须绕过LocalVariableSorter和调用底层目标MethodVisitor上的方法。
当您在visitVarInsn(LSTORE, 3)上调用LocalVariableSorter时,它的处理方式就像引用索引3的旧指令一样,并且由于注入了一个新变量,即占用索引3和4,索引3处的“旧变量”被重新映射到下一个空闲索引,即5 (和6)。然后,当您定义下一个新变量时,它将获得索引7,并对LocalVariableSorter上的visitVarInsn(ASTORE, 7)进行处理,就像处理一个与新变量冲突的旧变量一样,因此它将被映射到8。
这种行为与类文档的第一句所述完全吻合:
一个按外观顺序重命名局部变量的MethodVisitor。
因此,虽然您必须在newLocal上调用LocalVariableSorter来创建一个不会被重新映射的新变量,但是您必须调用原始包装的MethodVisitor上的visit…方法才能使用它。当您使用子类GeneratorAdapter时,您可以使用它新定义的方法(那些不是以visit…开头的方法)来创建新的指令,这些指令不会被转换,但是对我来说,这会使事情变得更糟,因为有方法可以在同一个类上转换指令和创建未转换的指令,并且始终需要记住,visit…前缀带来了不同。对于某些方法,您仍然需要访问原始的方法访问者,正如这个答案中所讨论的,它处理visitLocalVariable来为创建的变量创建调试信息。
https://stackoverflow.com/questions/50140365
复制相似问题