jakarta-bcel-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Volker Leidl <le...@nt.imp.univie.ac.at>
Subject Re: Instrumenting a constructor
Date Wed, 02 Oct 2002 15:30:24 GMT
Hi!

In my project I solved a similar problem by implementing a try finally 
block with jsr and ret instructions.
To identify all exit points in an InstructionList I have written a 
Visitor that visits all return statements to insert code to store away 
possible stack values, jump to a finally block that has been appended to 
the instruction list previously, and to load a previously stored value 
back onto the stack again when execution returns. An exception handler 
 for type "any" (MethodGen.addExceptionHandler(..., null)) that causes 
the finally block to
be executed if an exception is thrown has to be added also.
Unfortunately this solution is much more complicated on the bytecode 
level than on the Java language level.

Regards,
Volker.

Huw Evans wrote:

>>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>
>
>
>  
>


--
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