instrumenting try block

Yudi Zheng <[email protected]>
Newsgroups gmane.comp.java.objectweb.asm
Message-ID <CAA=eNoM6bKfpAtskNFyuFaTWu4CcJkLqhewFfh=hUCVF96MJeA@mail.gmail.com>
Hi,

We are trying to insert new code section into existing exception handler.
In an example below is just simplified scenario, but we are using similar
code to insert try-finally into methods.

We have encountered buggy behavior when using COMPUTE_FRAMES
 in conjunction with COMPUTE_MAXS within ClassWriter.

The following code (for full runnable code see attachments) produces
Java VerifyError. If we use the Class writer twice in a row at the end,
the produced result is as expected.

Do you have any idea, what can cause the error?

Code segment of instrumenting a finally clause:

// Method 'main' of Example.class
> MethodNode method = cn.methods.get(1);
> InsnList ilst = method.instructions;
>
> TryCatchBlockNode original_handler = method.tryCatchBlocks.get(0);
> LabelNode start = original_handler.start;
> LabelNode end = original_handler.end;
>
> ilst.insertBefore(end, new JumpInsnNode(Opcodes.GOTO, end));
> LabelNode handler = createLabel();
> ilst.insertBefore(end, handler);
> ilst.insert(handler, new InsnNode(Opcodes.ATHROW));
> ilst.insert(handler, new IntInsnNode(Opcodes.ALOAD,
> method.maxLocals));
> ilst.insert(handler, new IntInsnNode(Opcodes.ASTORE,
> method.maxLocals));
>
> method.tryCatchBlocks.add(0, new TryCatchBlockNode(start, handler,
> handler, null));



The code above will instrument 5 asm instructions to the original
instruction list:


> goto original_handler_end
> new_handler:
> astore_2
> aload_2
> athrow
> original_handler_end:


The problem is, when we are using the COMPUTE_MAXS, it will
automatically compute the maximum local slot number of the method.
But it leads to an incorrect result, which seems not considering the
handler we inserted. When running the generated class file, it will
throw a VerifyError.

  // Method descriptor #10 ([Ljava/lang/String;)V
>   // Stack: 3, Locals: 2
>   public static void main(java.lang.String[] arg0);


The solution is quite simple: use another ClassReader and ClassWriter
 to generate the byte array again.

 cr = new ClassReader(cw.toByteArray());
>  cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
>  cr.accept(cw, ClassReader.SKIP_DEBUG | ClassReader.EXPAND_FRAMES);


Then the maximum local slot number will be corrected. and the generated
class file runs without VerifyError.

  // Method descriptor #10 ([Ljava/lang/String;)V
>   // Stack: 3, Locals: 3
>   public static void main(java.lang.String[] arg0);



p.s. There is some other differences between these two generated class file.

Single-round:

>     14  goto 22
>     17  astore 2
>     19  aload 2
>     21  athrow


Two-round:

>     14  goto 20
>     17  astore_2
>     18  aload_2
>     19  athrow


This implies that the optimization of replacing a two-word load/store to
a single-word load/store instruction does not take place in the first
round.
Hope this might help.


Yudi
Example.java (application/octet-stream, 278 B) - not displayed
FinallyClause.java (application/octet-stream, 2.9 KB) - not displayed
message-footer.txt (text/plain, 238 B)
-- 
You receive this message as a subscriber of the [email protected] mailing list.
To unsubscribe: mailto:[email protected]
For general help: mailto:[email protected]?subject=help
OW2 mailing lists service home page: http://www.ow2.org/wws
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.