Here I use "bci" (bytecode index) to mean the byte offset into the bytecode of
a method -- I have heard this called by many other names: bcp (bytecode
pointer), Java pc, bytecode offset, etc.
I need to know the original bci for instructions because the data I collect
needs to be integrated with external resources indexed by bci
(CharacterRangeTable attribute, a possible external version of the
CharacterRangeTable attribute, databases of past run information, etc).
However, I don't believe this need is unique to my project, for example, to
implement javap with ASM you would need this information. I need the bci
before instrumentation is inserted.
I can think of several mechanisms to achieve this: hooks into ClassReader, a
mapping query, an optional visitOffset, or fork the original visits off to the
ClassWriter sprinkled with Labels. If there are other solutions, I would love
to hear them.
Currently I do this by modifying ClassReader by insertion of half a dozen
hooks, which call protected empty stubs. My code then has a subclass of
ClassReader which overrides these stubs. My stubs, as they currently exist are
probably too special purpose to include in a release, but a very generic
single-hook version would be possible (see below). It is not practical to copy
the hooked version out of org.objectweb.asm as there are a large number of
package-private dependencies. Neither a personal modified version in place or a
copy elsewhere is a good solution because of version drift.
ClassReader could store the mapping and then be queried for it, but this seems
contrary to ASM style and is more awkward than other approaches.
A new MethodVistor method could be added visitOffset(int offset) which would
only be sent if a new ClassReader flag was set. This seems a clean approach,
however it is a change to an interface and thus introduces version
incompatibility -- I don't know how significant that would be for ASM.
The idea of redirecting to ClassWriter to force resolution with added labels
seems too inefficient.
So, unless that visitOffset idea seems appealing, the path of least resistance
would be to add a single hook. It would be at what is in ASM 3.0 line 1142 of
ClassReader:
while (v < codeEnd) {
w = v - codeStart;
insnOffset(mv, w); // added hook
l = labels[w];
if (l != null) {
mv.visitLabel(l);
if (!skipDebug && l.line > 0) {
mv.visitLineNumber(l.line, l);
}
}
Then an empty stub would be needed:
protected void insnOffset(MethodVisitor mv, int offset) {}
Two lines only.
For visitOffset the code would be in the same location.
Thanks for ASM, for resolving the Label.info issue, and for reading all this.