How to add a code to the message before each return?

I'm currently trying to generate code through a wonderfully crafted java-asm library (version 4). More specifically, I want to add code at the end of the method immediately before each callback. I can successfully add the code BEFORE the method code. However, I currently have no idea how to perform the above conversion. I would really appreciate how this can be done.

MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 42); return mv; 
+6
source share
2 answers

You have two solutions:

1. Use the visitInsn(int opcode) method in MethodVisitor :

 //this is the custom method visitor private class InsertInitCodeBeforeReturnMethodVisitor extends MethodVisitor{ public InsertInitCodeBeforeReturnMethodVisitor(MethodVisitor mv) { super(Opcodes.ASM4, mv); } @Override public void visitInsn(int opcode) { //whenever we find a RETURN, we instert the code, here only crazy example code switch(opcode) { case Opcodes.IRETURN: case Opcodes.FRETURN: case Opcodes.ARETURN: case Opcodes.LRETURN: case Opcodes.DRETURN: case Opcodes.RETURN: mv.visitVarInsn(Opcodes.ALOAD, 42); break; default: // do nothing } super.visitInsn(opcode); } } 

2. Use the onMethodExit(int opcode) method in the AdviceAdapter at org.objectweb.asm.commons :

 //this is the custom method visitor private class InsertInitCodeBeforeReturnMethodVisitor extends AdviceAdapter{ public InsertInitCodeBeforeReturnMethodVisitor(MethodVisitor mv, int access, String name, String desc) { super(Opcodes.ASM4, mv, access, name, desc); } @Override protected void onMethodExit(int opcode) { if(opcode != Opcdoes.ATHROW) { mv.visitVarInsn(Opcodes.ALOAD, 42); } } } 

I personally like the AdviceAdapter better because it eliminates the headache associated with actually calling the original return command, as well as with the first solution (e.g. super.visitInsn(opcode); ). And secondly, it provides a good abstraction specifically for visits to RETURN (and ATHORW ) ATHORW ; which does not match the visitInsn(int opcode) method in vanilla MethodVisitor , where you need to find visits to RETURN commands among many others, such as DUP s, ICONST_0 , etc., that might or might not be relevant to the problem.

But it again depends on the problem. If this is the only tool that runs, I will stick with the AdviceAdapter . If there are other things you would like to do in conjunction with the RETURN instructions, I could stay with a simple MethodVisitor , as this could give me more flexibility. This suggests that I used the AdviceAdapter little over a year for a heavy tool with managed tools, it has been developed so far!


Edit:

visitor method application

It’s often not clear how to use or apply the visitor / adapter method (at least for me), so I put together a quick code example here: gist.github.com/VijayKrishna/1ca807c952187a7d8c4d , which shows how to use the method adapter, through the corresponding visitor class / adapter class. In the sample code snippet, I changed the name of the method adapter from what I use in this answer, but they do the same. In addition, the code snippet shows a method adapter that extends the AdviceAdapter .

So, you first “call” the class adapter as follows:

 ClassReader cr = new ClassReader(in); ClassWriter cw = new ClassWriter(ClassReader.EXPAND_FRAMES); ReturnAdapter returnAdapter = new ReturnAdapter(cw, className); cr.accept(returnAdapter, 0); 

Then you execute it by adapting the methods as follows in the class-adapter visitMethod :

 MethodVisitor mv; mv = cv.visitMethod(access, name, desc, signature, exceptions); mv = new MethodReturnAdapter(Opcodes.ASM4, className, access, name, desc, mv); return mv; 
+7
source

It actually turned out to be easy, but I was looking in a completely wrong place. To convert the method body to arbitrary positions, you need to create your own subclass of MethodVisitor and pass the existing MethodVisitor through it in order to perform the transformations that you want to do. In my example, when the custom MethodVisitor method detects the REETURN operation code, it adds code, for example:

 public class ActorInterfaceTransformer extends ClassVisitor { public ActorInterfaceTransformer(ClassVisitor cv) { super(Opcodes.ASM4, cv); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { //if the method is the one we want to transform if(name.equals("<init>")){ //... then we pipe the method visitor MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); return new InsertInitCodeBeforeReturnMethodVisitor(mv); } return super.visitMethod(access, name, desc, signature, exceptions); } } //this is the custom method visitor private class InsertInitCodeBeforeReturnMethodVisitor extends MethodVisitor{ public InsertInitCodeBeforeReturnMethodVisitor(MethodVisitor mv) { super(Opcodes.ASM4, mv); } @Override public void visitInsn(int opcode) { //whenever we find a RETURN, we instert the code, here only crazy example code if(opcode==Opcodes.RETURN){ mv.visitVarInsn(Opcodes.ALOAD, 42); } super.visitInsn(opcode); } } 
+3
source

Source: https://habr.com/ru/post/943693/


All Articles