问题
I'm adding new locals via newLocal
from LocalVariableSorter
. The method I'm adding the locals to is an instance method with a long parameter. I'm adding two locals; one long, one object. There are no other local vars in the sample code.
As a result I would have expected the following slots / indexes:
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`
What I do get as return from newLocal
is 3 and 7 though. Why such a big gap?
And to make things even more strange, when I add xSTORE
instructions using those indexes and check the result with javap it shows me:
LSTORE 5
ASTORE 8
Note: Not only are the values different then the ones I've passed to the xSTORE instruction, also the gap between them is now 3 instead of 4 as before.
The resulting code works though. I would just like to understand what magic is happening here an why.
Thanks
回答1:
The LocalVariableSorter
class has a design, which makes it very easy to use it wrong.
When calling methods defined by the MethodVisitor
API on it, they undergo the renumbering mentioned in the class documentation.
So when being used with a ClassReader
, the visited old code gets transformed. Since you do not want the injected new code to undergo this transformation, but to use the newly defined variable(s), you have to bypass the LocalVariableSorter
and call methods on the underlying target MethodVisitor
.
When you call visitVarInsn(LSTORE, 3)
on the LocalVariableSorter
, it gets handled like an old instruction referring to index 3
and since you injected a new variable occupying index 3
and 4
, the “old variable” at index 3
gets remapped to the next free index, which is 5
(and 6
). Then, when you define your next new variable, it gets index 7
and calling visitVarInsn(ASTORE, 7)
on the LocalVariableSorter
is handled like an old variable which conflicts with your new variable, so it gets remapped to 8
.
This behavior matches exactly what the first sentence of the class documentation states:
LocalVariablesSorterA MethodVisitor that renumbers local variables in their order of appearance.
So while you have to call newLocal
on the LocalVariableSorter
to create a new variable that won’t get remapped, you have to call the visit…
methods on the original, wrapped MethodVisitor
to use it. When you use the subclass GeneratorAdapter
, you can use its newly defined methods (those not starting with visit…
) to create new instructions which don’t get transformed, but to me, this would make matters even worse, having methods for transforming instructions and creating untransformed instructions on the same class and always needing to keep in mind that the visit…
prefix makes the difference. For some methods, you would still need to access the original method visitor, as discussed in this answer which deals with visitLocalVariable
to create debug information for the created variable.
来源:https://stackoverflow.com/questions/50140365/asm-strange-localvar-index-using-newlocal-from-localvariablesorter