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