使用 asm 重建方法时的杂散指令

Stray instructions when reconstructing method using asm

我正在使用 asm 修改 MethodNode 的指令。我的代码从 methodNode.instructions 构建了一个图表。使用此图,我重新排列和删除指令。然后,我使用该图为 MethodNode 生成一个新的指令列表。问题是指令仍然具有 .getNext() 的值,这会导致图形中不再包含的杂散指令被添加到方法指令的末尾。这也会在将 InsnList 转换为数组时导致 ArrayIndexOutOfBoundsException。

示例:

初步说明:

L0
 ALOAD 1
 LDC 1784196469
 INVOKEVIRTUAL dq.c (I)I
 ISTORE 2
 ILOAD 2
 IFNE L1
 GOTO L2
L3
 RETURN
L1
 ALOAD 0
 ALOAD 1
 ILOAD 2
 BIPUSH 15
 INVOKEVIRTUAL ac.f (Ldq;IB)V
 GOTO L0
L2
 GOTO L3

图形变化后。这些是清除列表后添加到 methodNode.instructions 的说明。

L0
 ALOAD 1
 LDC 1784196469
 INVOKEVIRTUAL dq.c (I)I
 ISTORE 2
 ILOAD 2
 IFNE L1
 RETURN
L1
 ALOAD 0
 ALOAD 1
 ILOAD 2
 BIPUSH 15
 INVOKEVIRTUAL ac.f (Ldq;IB)V
 GOTO L0

在最后一条指令上调用 .getNext() 时,结果如下:

org.objectweb.asm.tree.LabelNode@7a0ac6e3

如您所见,添加的最后一条指令 (GOTO L0) 具有 .getNext()

的值

当这个MethodNode被保存然后反编译时,这是结果。有一个指向不存在的标签的杂散 GOTO 语句。

L1 {
    aload1
    ldc 1784196469 (java.lang.Integer)
    invokevirtual dq c((I)I);
    istore2
    iload2
    ifne L2
    return
}
L2 {
     aload0 // reference to self
     aload1
     iload2
     bipush 15
     invokevirtual ac f((Ldq;IB)V);
     goto L1
     goto L3
}

如果我要更改指令的顺序,如何重用该方法中的指令?这是一个错误还是我使用了 asm 错误?

InsnList is a linked list of AbstractInsnNodeAbstractInsnNode 的每个实例都有一个名为 next 的指针,指向列表中的下一个节点。

重新排列列表中的节点时,您还需要注意这些指针。在您的例子中,GOTO L0 的节点最初指向 L2,并且由于其 next 指针在重排期间未更新,所以它最后仍指向 L2

更新 next 指针似乎没有简单的解决方案。没有 setter 方法。 clear 方法不会这样做。 removeAll 方法不可见。

一些可能性可能是 (i) 使用 remove 从列表中删除所有节点,然后再使用它们;或 (ii) 为新列表构建新节点。