【问题标题】:ASM - strange localVar index using newLocal from LocalVariableSorterASM - 使用 LocalVariableSorter 中的 newLocal 的奇怪 localVar 索引
【发布时间】:2018-10-12 21:37:49
【问题描述】:

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

因此,我预计会有以下插槽/索引:

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。

生成的代码虽然有效。我只想了解这里发生了什么magic 以及为什么。

谢谢

【问题讨论】:

  • 你能发布你的代码吗?另外,你确定你没有调用任何会隐式添加本地人的东西吗?尝试继承 LocalVariableSorter 并将打印语句添加到 newLocal

标签: java bytecode java-bytecode-asm byte-buddy jvm-bytecode


【解决方案1】:

LocalVariableSorter 类有一个设计,很容易用错。

在其上调用MethodVisitor API 定义的方法时,局部变量会经历class documentation 中提到的重新编号。

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

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

这种行为与类文档的第一句话完全吻合:

LocalVariablesSorter

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

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

【讨论】:

  • 啊顺便说一句:您是否发现没有调整我的代码以调用原始的 visit... 方法,包装 MethodVisitor 但在本地计数中留下空白?虽然不是很好,但它确实有效。只是想知道是否有任何副作用。
  • 这仅在您转换的代码不使用这些变量时才有效。关键是,您保留了某些索引,LocalVariablesSorter 将重新映射旧代码,因此它不会使用这些索引。当您使用不同的索引时,您不仅会失去这种保护,而且会完全使用 LocalVariablesSorter 毫无意义。当您事先知道时,哪些索引肯定是未使用的,例如当生成全新的代码时,您根本不需要使用LocalVariablesSorter,您可以将这些索引与由ClassWriter返回的MethodVisitor 一起使用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-03
  • 1970-01-01
相关资源
最近更新 更多