Класс LocalVariableSorter
имеет дизайн, который позволяет очень легко использовать его неправильно.
При вызове методов, определенных API-интерфейсом MethodVisitor
, они проходят перенумерацию, указанную в документации класса .
Поэтому при использовании с ClassReader
посещенный старый код трансформируется. Поскольку вы не хотите, чтобы внедренный новый код проходил это преобразование, а чтобы использовать вновь определенные переменные (переменные), вы должны обойти LocalVariableSorter
и вызвать методы для базовой цели MethodVisitor
.
Когда вы вызываете visitVarInsn(LSTORE, 3)
на LocalVariableSorter
, она обрабатывается как старая инструкция, ссылающаяся на индекс 3
, и поскольку вы внедрили новую переменную, занимающую индексы 3
и 4
, «старая переменная» по индексу 3
переводится в следующий свободный индекс, который равен 5
(и 6
). Затем, когда вы определяете вашу следующую новую переменную, она получает индекс 7
и вызов visitVarInsn(ASTORE, 7)
для LocalVariableSorter
обрабатывается как старая переменная, которая конфликтует с вашей новой переменной, поэтому она преобразуется в 8
.
Это поведение точно соответствует тому, что говорится в первом предложении документации класса:
LocalVariablesSorter
MethodVisitor, который нумерует локальные переменные в порядке их появления.
Поэтому, хотя вам нужно вызвать newLocal
для LocalVariableSorter
, чтобы создать новую переменную, которая не будет переназначена, вы должны вызвать visit…
методы для оригинала, обернутые MethodVisitor
, чтобы использовать ее. Когда вы используете подкласс GeneratorAdapter
, вы можете использовать его недавно определенные методы (те, которые не начинаются с visit…
), чтобы создавать новые инструкции, которые не преобразуются, но, на мой взгляд, это могло бы ухудшить ситуацию, имея методы для преобразование инструкций и создание нетрансформированных инструкций для одного и того же класса, и всегда нужно помнить, что префикс visit…
имеет значение. Для некоторых методов вам все равно потребуется доступ к исходному посетителю метода, как обсуждалось в в этом ответе , в котором рассматривается visitLocalVariable
для создания отладочной информации для созданной переменной.