Блуждающие инструкции при восстановлении метода с использованием asm

Я использую asm для изменения инструкций MethodNode. Мой код строит график из methodNode.instructions. Используя этот график, я переставляю и удаляю инструкции. Затем я использую график для создания нового списка инструкций для MethodNode. Проблема в том, что в инструкциях по-прежнему есть значения для .getNext(), что приводит к добавлению в конец инструкций методов случайных инструкций, которые больше не содержатся в графе. Это также вызывает ArrayIndexOutOfBoundsException при преобразовании InsnList в массив.

Пример:

Начальные инструкции:

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?


person user3552325    schedule 05.04.2016    source источник


Ответы (1)


InsnList — это связанный список < a href="http://asm.ow2.org/asm50/javadoc/user/org/objectweb/asm/tree/AbstractInsnNode.html" rel="nofollow">AbstractInsnNode. Каждый экземпляр AbstractInsnNode имеет указатель с именем next, который указывает на следующий узел в списке.

Когда вы переупорядочиваете узлы в списке, вам также нужно будет позаботиться об этих указателях. В вашем случае узел для GOTO L0 изначально указывает на L2, и поскольку его указатель next не был обновлен во время перестановки, он по-прежнему указывает на L2 в конце.

Кажется, нет простых решений для обновления указателя next. Для него нет метода установки. Метод clear не делает этого. Метод removeAll не виден.

Некоторые возможности могут заключаться в том, чтобы (i) использовать remove для удаления всех узлов из списка перед их повторным использованием; или (ii) построить новые узлы для нового списка.

person dejvuth    schedule 06.04.2016
comment
Я попытался вставить все AbstractInsnNodes в обратном порядке, но последний в списке по-прежнему имеет указатель на какую-то блуждающую инструкцию. - person user3552325; 06.04.2016
comment
@user3552325 user3552325 Конечно, это потому, что указатель next первого вставленного вами узла (который позже станет последним узлом в списке) не был обновлен. Как насчет использования метода, о котором я упоминал, для добавления нового узла к последнему узлу: insert(last, newNode). (Вы можете использовать, например, add, чтобы добавить первый узел в список.) - person dejvuth; 06.04.2016
comment
Мне нужен способ сделать следующий указатель на последнем узле нулевым. вставка не помогает с этим. - person user3552325; 06.04.2016
comment
@ user3552325 Извините. Виноват. Пожалуйста, смотрите редактирование. - person dejvuth; 06.04.2016
comment
Удаление каждой инструкции из списка вместо использования clear() устранило мою проблему. - person user3552325; 06.04.2016