All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.agent.weaving.PointcutClassVisitor Maven / Gradle / Ivy

There is a newer version: 0.14.0-beta.3
Show newest version
/*
 * Copyright 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.glowroot.agent.weaving;

import org.glowroot.agent.shaded.org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.glowroot.agent.shaded.org.checkerframework.checker.nullness.qual.Nullable;
import org.glowroot.agent.shaded.org.objectweb.asm.AnnotationVisitor;
import org.glowroot.agent.shaded.org.objectweb.asm.ClassVisitor;
import org.glowroot.agent.shaded.org.objectweb.asm.ClassWriter;
import org.glowroot.agent.shaded.org.objectweb.asm.Label;
import org.glowroot.agent.shaded.org.objectweb.asm.MethodVisitor;
import org.glowroot.agent.shaded.org.objectweb.asm.Type;
import org.glowroot.agent.shaded.org.objectweb.asm.commons.GeneratorAdapter;

import static org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.base.Preconditions.checkNotNull;
import static org.glowroot.agent.shaded.org.objectweb.asm.Opcodes.ASM7;
import static org.glowroot.agent.shaded.org.objectweb.asm.Opcodes.F_NEW;
import static org.glowroot.agent.shaded.org.objectweb.asm.Opcodes.IFEQ;
import static org.glowroot.agent.shaded.org.objectweb.asm.Opcodes.ILOAD;
import static org.glowroot.agent.shaded.org.objectweb.asm.Opcodes.INVOKESTATIC;

class PointcutClassVisitor extends ClassVisitor {

    private final ClassWriter cw;
    private @Nullable String className;
    private @MonotonicNonNull PointcutMethodVisitor onBeforeMethodVisitor;

    private boolean constructorPointcut;

    PointcutClassVisitor(ClassWriter cw) {
        super(ASM7, cw);
        this.cw = cw;
    }

    boolean isConstructorPointcut() {
        return constructorPointcut;
    }

    boolean hasOnBeforeMethod() {
        return onBeforeMethodVisitor != null;
    }

    @Override
    public void visit(int version, int access, String name, @Nullable String signature,
            @Nullable String superName, String /*@Nullable*/ [] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces);
        this.className = name;
    }

    @Override
    public @Nullable AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
        AnnotationVisitor av = cw.visitAnnotation(descriptor, visible);
        if (descriptor.equals("Lorg/glowroot/agent/plugin/api/weaving/Pointcut;")) {
            return new PointcutAnnotationVisitor(av);
        } else {
            return av;
        }
    }

    @Override
    public @Nullable MethodVisitor visitMethod(int access, String name, String descriptor,
            @Nullable String signature, String /*@Nullable*/ [] exceptions) {
        if (constructorPointcut) {
            return new PointcutMethodVisitor(
                    cw.visitMethod(access, name, descriptor, signature, exceptions), access, name,
                    descriptor, signature, exceptions);
        } else {
            // shortcut, no need to further analyze this class
            return null;
        }
    }

    @Override
    public void visitEnd() {
        if (onBeforeMethodVisitor != null) {
            int access = onBeforeMethodVisitor.access;
            String name = onBeforeMethodVisitor.name;
            String descriptor = "(Z" + onBeforeMethodVisitor.descriptor.substring(1);
            String signature = onBeforeMethodVisitor.signature;
            String[] exceptions = onBeforeMethodVisitor.exceptions;
            GeneratorAdapter mv = new GeneratorAdapter(
                    cw.visitMethod(access, name, descriptor, signature, exceptions), access, name,
                    descriptor);
            mv.visitCode();
            mv.visitVarInsn(ILOAD, 0);
            Label endWithDefaultLabel = new Label();
            mv.visitJumpInsn(IFEQ, endWithDefaultLabel);
            mv.loadArgs(1, mv.getArgumentTypes().length - 1);
            mv.visitMethodInsn(INVOKESTATIC, checkNotNull(className), name,
                    onBeforeMethodVisitor.descriptor, false);
            mv.returnValue();

            mv.visitLabel(endWithDefaultLabel);
            mv.visitFrame(F_NEW, 0, new Object[0], 0, new Object[0]);
            if (mv.getReturnType().getSort() != Type.VOID) {
                // return value will be ignored when !enabled, but need to return something
                WeavingMethodVisitor.pushDefault(mv, mv.getReturnType());
            }
            mv.returnValue();
            mv.endMethod();
        }
        super.visitEnd();
    }

    private class PointcutAnnotationVisitor extends AnnotationVisitor {

        private PointcutAnnotationVisitor(AnnotationVisitor av) {
            super(ASM7, av);
        }

        @Override
        public void visit(@Nullable String name, Object value) {
            if ("methodName".equals(name) && "".equals(value)) {
                constructorPointcut = true;
            }
            super.visit(name, value);
        }
    }

    private class PointcutMethodVisitor extends MethodVisitor {

        private final int access;
        private final String name;
        private final String descriptor;
        private final @Nullable String signature;
        private final String /*@Nullable*/ [] exceptions;

        private PointcutMethodVisitor(MethodVisitor mv, int access, String name,
                String descriptor, @Nullable String signature, String /*@Nullable*/ [] exceptions) {
            super(ASM7, mv);
            this.access = access;
            this.name = name;
            this.descriptor = descriptor;
            this.signature = signature;
            this.exceptions = exceptions;
        }

        @Override
        public @Nullable AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
            if (descriptor.equals("Lorg/glowroot/agent/plugin/api/weaving/OnBefore;")) {
                onBeforeMethodVisitor = this;
            }
            return super.visitAnnotation(descriptor, visible);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy