jakarta-bcel-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Peter Lundin" <peter.lun...@home.se>
Subject Re: Re: Instrumenting a constructor
Date Wed, 23 Oct 2002 11:28:51 GMT
Hi Volker,

I have a question regarding inserting code before the return statement. How do you handle
branch instructions that targets the return instruction like in the method below?

    boolean bool = false;
    synchronized public void test11(String tmp) {
        if (bool) {

public synchronized void test11(String arg0), (Ljava/lang/String;)V
       0: aload_0[42](1)
       1: getfield[180](3) 70
       4: ifeq[153](3) -> return
       7: getstatic[178](3) 14
      10: aload_1[43](1)
      11: invokevirtual[182](3) 16
      14: return[177](1)
      15: return[177](1)

When bool is false the next instruction would be a branch to the last return instruction which
would lead to that the jsr to the finally clause is never executed.
I had a go too at the dreadful trace by injecting try finally problem but could not get all
enter and exit traces to match until I retargeted all branch instructions targeting return
instructions to the injected jsr instruction. Basically I looked at the targeters of the return
instrucions (which is visible through the getTargeters method on InstructionHandle) and retargeted
them. I must say that injecting try finally around the body of a method never stops to surprise
me and I still do not trust it completly. Injecting try finally around a method call I gave
up on and instead switched the invoke instruction to a injected dummy method invoking the
call from there instead.


-----Original Message-----
From: Volker Leidl <leidl@nt.imp.univie.ac.at>
To: bcel-user@jakarta.apache.org
Date: Mon, 21 Oct 2002 13:21:25 +0200
Subject: Re: Instrumenting a constructor

Hi Amol!

First of all, I would suggest to read through the section of the JVM 
specification that describes how a try-finally block is to be compiled 
into bytecode by use of the jsr and ret instructions 

As you correctly stated there are two ways to exit a method on the 
bytcode level: by explicitly returning
or by throwing an exception. In BCEL you can cope with the second one 
easily by adding a new exception handler that encloses the critical code 
section. You can do so by calling MethodGen.addExceptionHandler(...). 
The last parameter to this method takes the type of exception
to be caught by this handler. To accept any type, simply use null. At 
the target of the exception handler you
have to jump to your finally block.

Secondly you have to insert code before each return instruction in the 
method code, which is slightly more complicated. I did so by utilizing 
the Visitor facility of  BCEL. A convenient way is to sublcass 
org.apache.bcel.generic.EmptyVisitor and overwrite all visit* methods 
that handle return instructions, e.g. visitRETURN, visitARETURN, etc.

For example in my code the visitDRETURN (for double values) looks like 
the following:

        //double has a word size of 2
        public void visitDRETURN(DRETURN obj) {
            if (max - offset < 2) max += (2 - max + offset);

            //store away return value on the stack
            code.insert(handle, new DSTORE(offset + 1));
            code.insert(handle, new JSR(finallyClause));
            code.insert(handle, new DLOAD(offset + 1));

Since you need to store away the return value that is on the top of the 
stack before the respective return instruction is called,  you need some 
extra local variables. In the case of a double value you will need 2 
slots. The first line of the method is dedicated to reserving enough 
slots (Don't mind the details). Then the value on top of the stack is 
stored away with DSTORE, the finally block is called with JSR 
(finallyClasue contains the instruction handle to the first instruction 
of the finally clause) and in the end the previously stored value will 
be pushed back on the stack again. The handle variable in the code above 
holds an instruction handle to the actual  return instruction. I 
initialize it in a visitInstructionList() method in the visitor, which 
iterates over all instructions within a given interval of instruction 
handles of an InstructionList, and which I call initially to modify all 
return instructions.

So to sum up here is what I do in my instrumentation code:

*) Retrieve MethodGen of the method to be instrumented
*) Append instructions of finally block. See the link to the JVM 
specification above how to code a finally clause. Store away the 
instruction handle to the first instruction of the block.
*) Insert instructions for exception handler before the finally block. 
There you have to ASTORE the exception on the top of the stack, call JSR 
to jump to the first instruction of the finally block, ALOAD the 
exception back on the stack and ATHROW it.
*) Run the whole original code through an instance of the return 
instruction visitor. You will need to pass the instruction handle to the 
finally block to the visitor by some way.
*) Make sure that maxLocals and maxStack properties of the MethodGen get 
the correct values assigned.


P.S. I would suggest to transfer the thread to the bcel users list, so 
that others could possibly profit from it, or perhaps someone points me 
to a mistake in my solution I'm not aware of yet. If you have any 
questions, it would be best to post it there.

Amol Kulkarni wrote:

>Hi Volker,
>I'm working on bytecode instrumentation of java
>classes. I'm facing a problem tracing the method exit
>points. As you must be fully aware that method can
>exit from nay point due to exception and/or multiple
>return statements. So I plan to encapsulate the whole
>method body in to try-finally block and add my code
>snippet in the finally block. I understand that its
>very very complicated and found that you have already
>worked out on this from the link
>Can you help me in this problem by providing the
>details of "How to add try-finally block to a
>Do you Yahoo!?
>Y! Web Hosting - Let the expert host your web site

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>

View raw message