com.google.code.jtracert.instrument.impl.asm.JTracertSystemMethodAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.google.code.jtracert.instrument.impl.asm.JTracertSystemMethodAdapter.java

Source

package com.google.code.jtracert.instrument.impl.asm;

import org.objectweb.asm.*;
import org.objectweb.asm.commons.AdviceAdapter;
import com.google.code.jtracert.config.InstrumentationProperties;
import com.google.code.jtracert.util.ClassUtils;

import java.lang.reflect.Method;

/**
 * Distributed under GNU GENERAL PUBLIC LICENSE Version 3
 *
 * @author Dmitry.Bedrin@gmail.com
 */
public class JTracertSystemMethodAdapter extends AdviceAdapter implements Opcodes {

    private final String className;
    private final String methodName;
    private final boolean isConstructor;

    private final Label startFinallyLabel = new Label();

    public JTracertSystemMethodAdapter(MethodVisitor mv, int access, String name, String desc, String className) {
        super(mv, access, name, desc);
        this.className = className;
        this.methodName = name;
        this.isConstructor = name.equals(ClassUtils.CONSTRUCTOR_METHOD_NAME);
    }

    /**
     *
     */
    @Override
    public void visitCode() {
        super.visitCode();
        mv.visitLabel(startFinallyLabel);
    }

    /**
     * @param maxStack
     * @param maxLocals
     */
    @Override
    public void visitMaxs(int maxStack, int maxLocals) {
        Label endFinallyLabel = new Label();
        mv.visitTryCatchBlock(startFinallyLabel, endFinallyLabel, endFinallyLabel, null);
        mv.visitLabel(endFinallyLabel);
        onFinally(ATHROW);
        mv.visitInsn(ATHROW);
        mv.visitMaxs(maxStack, maxLocals);
    }

    /**
     * @param opcode
     */
    @Override
    protected void onMethodExit(int opcode) {
        if (opcode != ATHROW) {
            onFinally(opcode);
        }
    }

    /**
     * @param opcode
     */
    private void onFinally(int opcode) {

        mv.visitMethodInsn(INVOKESTATIC, "java/lang/ClassLoader", "getSystemClassLoader",
                "()Ljava/lang/ClassLoader;");
        super.visitLdcInsn("com.google.code.jtracert.traceBuilder.MethodCallTraceBuilderFactory");
        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassLoader", "loadClass",
                "(Ljava/lang/String;)Ljava/lang/Class;");
        super.visitLdcInsn("getMethodCallTraceBuilder");
        super.visitInsn(ACONST_NULL);
        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod",
                "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
        super.visitInsn(ACONST_NULL);
        super.visitInsn(ACONST_NULL);
        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
                "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");

        int methodCallTraceBuilder = newLocal(Type.getType(Method.class));
        super.visitVarInsn(ASTORE, methodCallTraceBuilder);

        super.visitMethodInsn(INVOKESTATIC, "java/lang/ClassLoader", "getSystemClassLoader",
                "()Ljava/lang/ClassLoader;");
        super.visitLdcInsn("com.google.code.jtracert.traceBuilder.MethodCallTraceBuilder");
        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassLoader", "loadClass",
                "(Ljava/lang/String;)Ljava/lang/Class;");
        super.visitLdcInsn("leave");
        super.visitInsn(ACONST_NULL);
        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod",
                "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
        super.visitVarInsn(ALOAD, methodCallTraceBuilder);
        super.visitInsn(ICONST_0);
        super.visitTypeInsn(ANEWARRAY, "java/lang/Object");
        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
                "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
        super.visitInsn(POP);

    }

    @Override
    protected void onMethodEnter() {

        try {

            super.visitMethodInsn(INVOKESTATIC, "java/lang/ClassLoader", "getSystemClassLoader",
                    "()Ljava/lang/ClassLoader;");
            super.visitLdcInsn("com.google.code.jtracert.traceBuilder.MethodCallTraceBuilderFactory");
            super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassLoader", "loadClass",
                    "(Ljava/lang/String;)Ljava/lang/Class;");

            int classVar = newLocal(Type.getType(Class.class));

            super.visitInsn(DUP);
            super.visitVarInsn(ASTORE, classVar);

            super.visitLdcInsn("instrumenting");
            super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getField",
                    "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
            super.visitInsn(ACONST_NULL);
            super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "get",
                    "(Ljava/lang/Object;)Ljava/lang/Object;");
            super.visitTypeInsn(CHECKCAST, "java/lang/ThreadLocal");

            int booleanThreadLocalVar = newLocal(Type.getType(ThreadLocal.class));

            super.visitInsn(DUP);
            super.visitVarInsn(ASTORE, booleanThreadLocalVar);

            super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ThreadLocal", "get", "()Ljava/lang/Object;");
            super.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
            super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");

            Label buildingTraceLabel = new Label();

            super.visitJumpInsn(IFNE, buildingTraceLabel);

            super.visitVarInsn(ALOAD, booleanThreadLocalVar);
            super.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
            super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ThreadLocal", "set", "(Ljava/lang/Object;)V");

            onMethodEnterInternal(classVar);

            super.visitVarInsn(ALOAD, booleanThreadLocalVar);
            super.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
            super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ThreadLocal", "set", "(Ljava/lang/Object;)V");

            super.visitLabel(buildingTraceLabel);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void onMethodEnterInternal(int methodCallTraceBuilderFactoryClass) {
        super.visitVarInsn(ALOAD, methodCallTraceBuilderFactoryClass);
        super.visitLdcInsn("getMethodCallTraceBuilder");
        super.visitInsn(ICONST_0);
        super.visitTypeInsn(ANEWARRAY, "java/lang/Class");
        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod",
                "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
        super.visitInsn(ACONST_NULL);
        super.visitInsn(ICONST_0);
        super.visitTypeInsn(ANEWARRAY, "java/lang/Object");
        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
                "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");

        // MethodCallTraceBuilder instance is on stack

        int methodCallTraceBuilderLocalVar = newLocal(Type.getType(Object.class));
        super.visitVarInsn(ASTORE, methodCallTraceBuilderLocalVar);

        try {

            if ((ACC_STATIC & methodAccess) == 0) {

                super.visitMethodInsn(INVOKESTATIC, "java/lang/ClassLoader", "getSystemClassLoader",
                        "()Ljava/lang/ClassLoader;");
                super.visitLdcInsn("com.google.code.jtracert.traceBuilder.MethodCallTraceBuilder");
                super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassLoader", "loadClass",
                        "(Ljava/lang/String;)Ljava/lang/Class;");

                super.visitLdcInsn("enter");
                super.visitInsn(ICONST_4);
                super.visitTypeInsn(ANEWARRAY, "java/lang/Class");
                super.visitInsn(DUP);
                super.visitInsn(ICONST_0);
                super.visitLdcInsn(Type.getType("Ljava/lang/String;"));
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_1);
                super.visitLdcInsn(Type.getType("Ljava/lang/String;"));
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_2);
                super.visitLdcInsn(Type.getType("Ljava/lang/String;"));
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_3);
                super.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
                super.visitInsn(AASTORE);

                super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod",
                        "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");

                super.visitVarInsn(ALOAD, methodCallTraceBuilderLocalVar);

                super.visitInsn(ICONST_4);
                super.visitTypeInsn(ANEWARRAY, "java/lang/Object");
                super.visitInsn(DUP);
                super.visitInsn(ICONST_0);
                super.visitLdcInsn(getClassName());
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_1);
                super.visitLdcInsn(getMethodName());
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_2);
                super.visitLdcInsn(getMethodDescriptor());
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_3);
                super.visitVarInsn(ALOAD, 0);
                super.visitInsn(AASTORE);

                super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
                        "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
                super.visitInsn(POP);

            } else {

                super.visitMethodInsn(INVOKESTATIC, "java/lang/ClassLoader", "getSystemClassLoader",
                        "()Ljava/lang/ClassLoader;");
                super.visitLdcInsn("com.google.code.jtracert.traceBuilder.MethodCallTraceBuilder");
                super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassLoader", "loadClass",
                        "(Ljava/lang/String;)Ljava/lang/Class;");

                super.visitLdcInsn("enter");
                super.visitInsn(ICONST_4);
                super.visitTypeInsn(ANEWARRAY, "java/lang/Class");
                super.visitInsn(DUP);
                super.visitInsn(ICONST_0);
                super.visitLdcInsn(Type.getType("Ljava/lang/String;"));
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_1);
                super.visitLdcInsn(Type.getType("Ljava/lang/String;"));
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_2);
                super.visitLdcInsn(Type.getType("Ljava/lang/String;"));
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_3);
                super.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
                super.visitInsn(AASTORE);

                super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod",
                        "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");

                super.visitVarInsn(ALOAD, methodCallTraceBuilderLocalVar);

                super.visitInsn(ICONST_4);
                super.visitTypeInsn(ANEWARRAY, "java/lang/Object");
                super.visitInsn(DUP);
                super.visitInsn(ICONST_0);
                super.visitLdcInsn(getClassName());
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_1);
                super.visitLdcInsn(getMethodName());
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_2);
                super.visitLdcInsn(getMethodDescriptor());
                super.visitInsn(AASTORE);
                super.visitInsn(DUP);
                super.visitInsn(ICONST_3);
                super.visitInsn(ACONST_NULL);
                super.visitInsn(AASTORE);

                super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
                        "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
                super.visitInsn(POP);

            }
        } catch (Throwable e) {
            e.printStackTrace();
        }

    }

    /**
     * @return
     */
    private String getClassName() {
        return this.className;
    }

    /**
     * @return
     */
    private String getMethodName() {
        return this.methodName;
    }

    /**
     * @return
     */
    private String getMethodDescriptor() {
        return super.methodDesc;
    }

    /**
     * @param argIndex
     * @return
     */
    private int generateArgumentsArray(int argIndex) {

        Type[] argumentTypes = Type.getArgumentTypes(getMethodDescriptor());

        super.visitIntInsn(BIPUSH, argumentTypes.length);
        super.visitTypeInsn(ANEWARRAY, "java/lang/Object");

        for (int i = 0; i < argumentTypes.length; i++) {
            Type argumentType = argumentTypes[i];

            super.visitInsn(DUP);
            super.visitIntInsn(BIPUSH, i);
            super.visitVarInsn(argumentType.getOpcode(ILOAD), argIndex);

            // boxing start

            switch (argumentType.getSort()) {
            case Type.BYTE:
                super.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
                break;
            case Type.BOOLEAN:
                super.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
                break;
            case Type.SHORT:
                super.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
                break;
            case Type.CHAR:
                super.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
                break;
            case Type.INT:
                super.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
                break;
            case Type.FLOAT:
                super.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
                break;
            case Type.LONG:
                super.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
                break;
            case Type.DOUBLE:
                super.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
                break;
            }

            // boxing end

            super.visitInsn(AASTORE);

            argIndex += argumentType.getSize();
        }

        super.visitVarInsn(ASTORE, argIndex);
        return argIndex;
    }

}