//
you're reading...
General, Java BCI

HOW TO: BCI method calls into java methods

In the earlier HOW TO, we stereotyped the performance statics related methods into a class. This will not be of use unless we can call the start and the end methods at the beginning and end of all the methods we want to profile. In this HOW TO, we will see how we can profile the entry and exit of methods to call a function. In our case we will extend the earlier example to call the start and end at the beginning and end of all methods in a class.

To do this, we need to do the following steps:

  • Create a custom MethodVisitor that BCI’s method enter and exit
  • Override the visitMethod function in the ClassVisitor and return the custom method visitor.
  • Use this ClassVisitor to modify the bytes as described in HOW To BCI.

Create a custom MethodVisitor

To BCI entry and exit of methods, we can derive a MethodVisitor from AdviceAdapter and override the onMethodEnter and onMethodExit functions. So we write a MethodVisitor as below:

    public class PerfMethod extends AdviceAdapter
    {
        private String name; 
        private String _clsName;

        public PerfMethod(MethodVisitor mv, int acc, String name, String desc, String cls) 
        { 
            super(2, mv, acc, name, desc); 
            this.name = name; 
            this._clsName = cls;
            _latestVar = -1;
        } 

        protected void onMethodEnter() 
        {
            We need to add code here
        }

        protected void onMethodExit(int opcode)
        {
            We need to add code here
        }

        public void visitMaxs(int stack, int locals) 
        { 
            super.visitMaxs(stack, locals); 
        }
    }

In the above we have the skeleton of how the MethodVisitor will look like. Let’s see how we can call the method in the functions onEnter and onExit. We need to know what are the instructions that have to be executed to call the start and end methods. We can do this using the ASMifier class provided. This takes as an input a class and dumps out the set of instructions that if called will create the class. We will create a class SampleASMify as below:

public class SampleASMify
{
    public SampleASMify()
    {
    }

    public void profile()
    {
        start("val");
        int i = 0;
        end();
    }

    public void start(String nm)
    {
    }

    public void end()
    {
    }
}

In the above class if you notice, we have two dummy functions start and end with signatures as we will have in the PerfTemplate. We call this in the function profile at the start and end of the method. We now can run ASMifier as below:

java -cp 
    asm-util-4.0_RC2.jar:asm-commons-4.0_RC2.jar:
    asm-tree-4.0_RC2.jar:asm-4.0_RC2.jar:
    asm-analysis-4.0_RC2.jar:asm-xml-4.0_RC2.jar:. 
org.objectweb.asm.util.ASMifier SampleASMify.class

This will generate an output for all functions as below. We will ignore all the functions except the profile, because this is what is important to us. The profile function output is shown below.

{
mv = cw.visitMethod(ACC_PUBLIC, "profile", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitLdcInsn("val");
mv.visitMethodInsn(INVOKEVIRTUAL, "SampleASMify", "start", "(Ljava/lang/String;)V");
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 1);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "SampleASMify", "end", "()V");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}

I have marked the instructions that are the calls to start and end. This indicates what are the instructions that have to be called to call start or end function for the signature we have in PerfTemplate. So, now we can write the onEnter method with the instructions required to call start as shown above. So, onEnter in the class PerfMethod becomes:

        protected void onMethodEnter() 
        { 
            super.visitVarInsn(ALOAD, 0);
            super.visitLdcInsn(name);
            super.visitMethodInsn(INVOKESPECIAL, _clsName, "start", "(Ljava/lang/String;)V");
        }

I have replaced the constants that we had in the previous output with the parameters I need to pass to the method. We can the onExit method with the “end” call instructions from above as this:

        protected void onMethodExit(int opcode)
        {
            if (!name.equals("toString"))
            {
                super.visitVarInsn(ALOAD, 0);
                super.visitMethodInsn(INVOKESPECIAL, _clsName, "end", "()V");
            }
        }

Here again we have replace the parameters appropriately. In here we are preventing the performance to be added to the toString method. This type of check can be used to conditionally profile only the required methods. Now we have a complete MethodVisitor that will BCI to call the start and end method for performance.

Override the visitMethod function in the ClassVisitor

Now we have to override our visitMethod in the ClassVisitor to return the above visitor. We can do this as below:

        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
        {
            MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
            if (name.equals("") || (name.equals("main")))
            {
                return mv; //don't modify the constructor
            }
            PerfMethod p = new PerfMethod(mv, access, name, desc, _name);
            return p;
        }

In the above I have prevented the constructor from being profiled. Please note, profiling a constructor in this way will be a problem, since the first line has to be the super call. This helps create an easy profiler as an AOP that can be turned on or off when required and need not be coded into the real production code.

Now we are all set to try the code. The code for this can be downloaded and tried from here.

Advertisements

Discussion

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: