Visiting a method's local vars before rather than after visiting code
During a method visit the local variable table is not processed until after the
method code has been visited. This makes it easy to identify the scope of local
variables because the start and end labels offsets are determinate when
visitLocalvar is called. Conversely, it makes it hard for transformers which
are trying to track and, possibly, tweak accesses to local variables to
identify whether a specific visitLocalVar instruction refers to a local var or
param with a given name.
The problem is that by the time the transformer gets to see the details of the
variable (name, desc, signature, start position, end position and stack slot)
the code which reads or writes the variable has already been visited. It is
possible to record the local var scopes on a first pass visit and then patch
the code on a second pass. However, this is still not easy because changes
injected during the second pass relocate the start and end positions identified
during the first pass. In any case using a two pass approach forces the second
pass code to employ bytecode offsets instead of labels which feels very un-ASM.
If the local variables were visited before the bytecode the transformer would
be able to override visitLocalVariable to index the local var details by start
label and end label. It could then override visitLabel and detect the situation
where a local var came into scope or went out of scope. This is enough to
enable the transforming code to be aware of which named locals/params are
active and hence to know when a visitVarInsn is referring to a specific named
local variable or param.
One way to support this which would retain backwards compatibility would be to
provide a configuration option which allowed ClassReader and MethodNode
instance to be configured so that they visit local vars before the method
bytecode. This might be tricky if the transforming code also wants to add new
local variables. However, additional local vars should always get appended
further up the stack from any existing local vars and they would not normally
have symbol table info and so would not normally be visited.
Another option would be to retain the current order for the code and lcoal var
table visit but make ClassReader and MethodNode provide extra notifications if
they are expected by the next MethodVisitor in line. For example, Classreader
could read and record the local var info before visiting the code. If it
indexed the local var details by start and end label then when it visits a
label during the code visit it could use these indexes to identify locations
where a local var went in or out of scope. If the MethodVisitor implemented the
following interface then the Classreader could feed it the relevant notifications:
public interface LocalScopeMethodVisitor extends MethodVisitor
{
public void visitLocalScopeStart(String name, String desc, String sig, int
stackSlot);
public void visitLocalScopeEnd(String name, String desc, String sig, int
stackSlot);
}
The current visitLocalVar code could still be called after the code visit was
complete, although it might be appropriate to avoid that if these methods had
already been called.