ASM - странный локальный индекс с использованием newLocal от LocalVariableSorter - PullRequest
0 голосов
/ 02 мая 2018

Я добавляю новых местных жителей через newLocal из LocalVariableSorter. Метод, к которому я добавляю localals, является методом экземпляра с длинным параметром. Я добавляю двух местных жителей; один длинный, один предмет. В этом примере кода нет других локальных переменных.

В результате я бы ожидал следующие слоты / индексы:

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, как раньше.

Полученный код работает, хотя. Я просто хотел бы понять, что магия происходит здесь и почему.

Спасибо

1 Ответ

0 голосов
/ 03 мая 2018

Класс LocalVariableSorter имеет дизайн, который позволяет очень легко использовать его неправильно.

При вызове методов, определенных API-интерфейсом MethodVisitor, они проходят перенумерацию, указанную в документации класса .
Поэтому при использовании с ClassReader посещенный старый код трансформируется. Поскольку вы не хотите, чтобы внедренный новый код проходил это преобразование, а чтобы использовать вновь определенные переменные (переменные), вы должны обойти LocalVariableSorter и вызвать методы для базовой цели MethodVisitor.

Когда вы вызываете visitVarInsn(LSTORE, 3) на LocalVariableSorter, она обрабатывается как старая инструкция, ссылающаяся на индекс 3, и поскольку вы внедрили новую переменную, занимающую индексы 3 и 4, «старая переменная» по индексу 3 переводится в следующий свободный индекс, который равен 56). Затем, когда вы определяете вашу следующую новую переменную, она получает индекс 7 и вызов visitVarInsn(ASTORE, 7) для LocalVariableSorter обрабатывается как старая переменная, которая конфликтует с вашей новой переменной, поэтому она преобразуется в 8.

Это поведение точно соответствует тому, что говорится в первом предложении документации класса:

LocalVariablesSorter

MethodVisitor, который нумерует локальные переменные в порядке их появления.

Поэтому, хотя вам нужно вызвать newLocal для LocalVariableSorter, чтобы создать новую переменную, которая не будет переназначена, вы должны вызвать visit… методы для оригинала, обернутые MethodVisitor, чтобы использовать ее. Когда вы используете подкласс GeneratorAdapter, вы можете использовать его недавно определенные методы (те, которые не начинаются с visit…), чтобы создавать новые инструкции, которые не преобразуются, но, на мой взгляд, это могло бы ухудшить ситуацию, имея методы для преобразование инструкций и создание нетрансформированных инструкций для одного и того же класса, и всегда нужно помнить, что префикс visit… имеет значение. Для некоторых методов вам все равно потребуется доступ к исходному посетителю метода, как обсуждалось в в этом ответе , в котором рассматривается visitLocalVariable для создания отладочной информации для созданной переменной.

...