> you could just use MethodGen.getMaxLocals() as a local variable number
> that is not used throughout the method. Make sure you keep getMaxLocals
> up to date by calling setMaxLocals when appropriate.
That is indeed a solution but the manually calling setMaxLocals leaves a
bad taste in my mouth (this is just something that I'll forget).
When I was browsing the API I ran into the addLocalVariable method of
MethodGen that does what I want, but I it seems that it doesn't really
take into account scopes of local variables. Consider the following code:
public double foo (int i, double d, int ii, double dd)
{
{//scope block 1
String sss = "NEW SSS";
System.out.println(sss);
}
{//scope block 2
String rrr = "NEW RRR";
System.out.println(rrr);
}
return i + d + ii + dd;
}
I think we all can agree that the size of the local variables at the
beginning of the body is 7 {0=this, 1=i, 2-3=d, 4=ii, 5-6=dd} so the
variable sss should be stored at position 7 which is the 8th slot, but
since the scope blocks are used that location should be reused to store
variable rrr.
When compiling this code with javac 1.4.2 it'll nicely generate the
following for the two scope blocks and reuses the slot for the local
variables sss and rrr:
0 ldc #25 <String "NEW SSS">
2 astore 7
4 getstatic #11 <Field java.io.PrintStream out>
7 aload 7
9 invokevirtual #16 <Method void println(java.lang.String)>
12 ldc #26 <String "NEW RRR">
14 astore 7
16 getstatic #11 <Field java.io.PrintStream out>
19 aload 7
21 invokevirtual #16 <Method void println(java.lang.String)>
<...> cut out
Local variables for method double foo(int, double, int, double)
ClassB this pc=0, length=36, slot=0
int i pc=0, length=36, slot=1
double d pc=0, length=36, slot=2
int ii pc=0, length=36, slot=4
double dd pc=0, length=36, slot=5
java.lang.String sss pc=4, length=8, slot=7
java.lang.String rrr pc=16, length=8, slot=7
But using the BCEL API to instrument the two scope blocks into an existing
method using this code:
//sss
LocalVariableGen lg = mg.addLocalVariable("sss", Type.STRING,
null, null);
int sss = lg.getIndex();
print.append(new PUSH(_cp, "NEW SSS"));
print.append(_factory.createStore(Type.STRING, sss)); // "sss"
valid from here
lg.setStart(print.append(_factory.createFieldAccess("java.lang.System",
"out", new ObjectType("java.io.PrintStream"),
Constants.GETSTATIC)));
print.append(_factory.createLoad(Type.OBJECT, sss));
lg.setEnd(print.append(_factory.createInvoke("java.io.PrintStream",
"println", Type.VOID, new Type[] { Type.STRING },
Constants.INVOKEVIRTUAL)));
//rrr
lg = mg.addLocalVariable("rrr", Type.STRING, null, null);
int rrr = lg.getIndex();
print.append(new PUSH(_cp, "NEW RRR"));
print.append(_factory.createStore(Type.STRING, rrr)); // "rrr"
valid from here
lg.setStart(print.append(_factory.createFieldAccess("java.lang.System",
"out", new ObjectType("java.io.PrintStream"),
Constants.GETSTATIC)));
print.append(_factory.createLoad(Type.OBJECT, rrr));
lg.setEnd(print.append(_factory.createInvoke("java.io.PrintStream",
"println", Type.VOID, new Type[] { Type.STRING },
Constants.INVOKEVIRTUAL)));
also works fine, but does not take into account the fact that the scopes
and yields:
Method double foo(int, double, int, double)
0 ldc #90 <String "NEW SSS">
2 astore 7
4 getstatic #11 <Field java.io.PrintStream out>
7 aload 7
9 invokevirtual #16 <Method void println(java.lang.String)>
12 ldc #92 <String "NEW RRR">
14 astore 8
16 getstatic #11 <Field java.io.PrintStream out>
19 aload 8
21 invokevirtual #16 <Method void println(java.lang.String)>
<...> cut out
Local variables for method double foo(int, double, int, double)
ClassB this pc=24, length=12, slot=0
int i pc=24, length=12, slot=1
double d pc=24, length=12, slot=2
int ii pc=24, length=12, slot=4
double dd pc=24, length=12, slot=5
java.lang.String sss pc=4, length=8, slot=7
java.lang.String rrr pc=16, length=8, slot=8
and thus does not reuse the slot, which it should! Is this a bug? Is this
a feature? If it is shouldn't this be documented? What is the use of
setting the 'begin' and 'end' InstructionHandles if they are not used?
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]