jakarta-bcel-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Huw Evans <...@dcs.gla.ac.uk>
Subject Re: Instrumenting a constructor
Date Tue, 01 Oct 2002 15:03:47 GMT

> 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:bcel-user-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:bcel-user-help@jakarta.apache.org>


Mime
View raw message