> So, my primary question is this: What's the easiest way
> to instrument the constructor to add the new logic?
Rather than rename the constructor which generates the problems you mention,
you could call a private method that you define which contains your code. The
private method would have to be added to the class for which you are changing
the constructor. For example, this constructor:
public class Foo {
public Foo() {
if(thing) {
i++;
return;
}
switch(j) {
case 0 : return;
case 1 : j--;
break;
default : j++;
return;
}
}
would be instrumented to look like this:
public class Foo {
public Foo() {
if(thing) {
i++;
my_method();
return;
}
switch(j) {
case 0 : my_method();
return;
case 1 : j--;
break;
default : j++;
my_method();
return;
}
my_method(); // needed at end, due to implicit return
}
and my_method added to class Foo as a private method.
I think you only have to identify the return statements (and the end of the
constructor) and do an insert of the call to your method (taking care about
pushing any necessary parameters).
You will have to be careful about branches, e.g., in the switch. If j is 1,
we do j-- and then break to the end of the constructor where we do the
my_method(). If j is zero or any other non-zero value, you need to call the
correct block of code which has to have a call to my_method embedded within
it. However, this is achievable as you are only looking for one kind of
bytecode, a return type. You just then need to insert the correct bytecodes
to call the new method and patch up any branches and any try-catch blocks.
However, BCEL helps *A LOT* with the branches and try-catch clauses (which are
also branches as they cause jumps to different targets which you will change
as you are putting code in.
Be sure to only call insert on the instruction list object and the other
bytecode in it will be OK, e.g., targets for try should still work as these
bytecodes have just been shifted in the list. Do NOT work with a copy of the
list or else you inserts will not work as copies of the bytecodes have been
taken and then BCEL looses its notion of which bytecode it's dealing with (as
the instruction handle has changed) and so you have to do a lot of your own
work patching up the branches and try-catch blocks.
> Some other questions:
>
> There's no guarantee that the "this" reference will be in
> slot 0, by the time my code executes, right? (There
> doesn't seem to be any hard and fast rule that says
> argument slots shouldn't be overwritten - I've seen javac
> overwrite them with impugnity). So I'll have to add some
> instructions at the top of the method to immediately
> store it to an unused slot, correct?
I'm not sure about this, I would hope this would be in slot 0 right from the
start, as there is an implicit call to the super constructor which is
dispatched via the VM with respect to this (i.e., there is nothing at the
bytecode level to indicate super, 'this' is passed to the VM and it does the
step up to super).
> When instrumenting a method, I need to create a new one
> and selectively copy instructions from the old one. Will
> the jump targets remain correct when I add or remove
> instructions as long as I don't remove the targetted
> instructions?
No, see above. Copying destroys all of this as you copy the underlying
instruction handle.
> If I use InstructionFactory.addLocalVariable before I
> begin adding any of the old instructions to the new
> method, will the old instructions retarget adjusted
> variable slots?
If you leave the original alone and insert into its list I believe the
branches to the original bytecodes should be OK.
Try all of this out on a very simple example first, get the fundamental
questions answered first and gradually increase the generality from there.
Huw
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>