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

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

There is a newer version: 0.14.0-beta.3
Show newest version
/*
 * Copyright 2014-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 java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.Lists;
import org.glowroot.agent.shaded.org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.glowroot.agent.shaded.org.objectweb.asm.Type;

import org.glowroot.agent.bytecode.api.Util;
import org.glowroot.agent.plugin.api.ClassInfo;
import org.glowroot.agent.plugin.api.MethodInfo;

import static org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.base.Preconditions.checkNotNull;

// can't generate classes in bootstrap class loader, so this is needed for storing meta holders
// similar technique is not good for non-bootstrap class loaders anyways since then weak references
// would need to be used to prevent retention of meta holders
public class BootstrapMetaHolders {

    private static final Map classMetaHolderIndexes =
            new ConcurrentHashMap();
    private static final Map methodMetaHolderIndexes =
            new ConcurrentHashMap();
    private static final List classMetaHolders =
            Lists.newCopyOnWriteArrayList();
    private static final List methodMetaHolders =
            Lists.newCopyOnWriteArrayList();

    private BootstrapMetaHolders() {}

    static int reserveClassMetaHolderIndex(String metaHolderInternalName,
            String classMetaFieldName) {
        synchronized (classMetaHolders) {
            String key = metaHolderInternalName + '.' + classMetaFieldName;
            Integer index = classMetaHolderIndexes.get(key);
            if (index == null) {
                classMetaHolders.add(null);
                index = classMetaHolders.size() - 1;
                classMetaHolderIndexes.put(key, index);
            }
            return index;
        }
    }

    static int reserveMethodMetaHolderIndex(String metaHolderInternalName,
            String methodMetaFieldName) {
        synchronized (methodMetaHolders) {
            methodMetaHolders.add(null);
            int index = methodMetaHolders.size() - 1;
            methodMetaHolderIndexes.put(metaHolderInternalName + '.' + methodMetaFieldName, index);
            return index;
        }
    }

    static void createClassMetaHolder(String metaHolderInternalName,
            String classMetaFieldName, Type classMetaType, Type type) {
        String key = metaHolderInternalName + '.' + classMetaFieldName;
        Integer index = classMetaHolderIndexes.get(key);
        checkNotNull(index, "ClassMetaHolder was not reserved for key: " + key);
        ClassMetaHolder classMetaHolder = new ClassMetaHolder(classMetaType, type);
        classMetaHolders.set(index, classMetaHolder);
    }

    static void createMethodMetaHolder(String metaHolderInternalName,
            String methodMetaFieldName, Type methodMetaType, Type methodOwnerType,
            String methodName, Type methodReturnType, List methodParameterTypes) {
        String key = metaHolderInternalName + '.' + methodMetaFieldName;
        Integer index = methodMetaHolderIndexes.get(key);
        checkNotNull(index, "MethodMetaHolder was not reserved for key: " + key);
        MethodMetaHolder methodMetaHolder = new MethodMetaHolder(methodMetaType, methodOwnerType,
                methodName, methodReturnType, methodParameterTypes);
        methodMetaHolders.set(index, methodMetaHolder);
    }

    public static Object getClassMeta(int index) throws Exception {
        ClassMetaHolder classMetaHolder = classMetaHolders.get(index);
        checkNotNull(classMetaHolder, "ClassMetaHolder was not instantiated for index: " + index);
        return classMetaHolder.getClassMeta();
    }

    public static Object getMethodMeta(int index) throws Exception {
        MethodMetaHolder methodMetaHolder = methodMetaHolders.get(index);
        checkNotNull(methodMetaHolder, "MethodMetaHolder was not instantiated for index: " + index);
        return methodMetaHolder.getMethodMeta();
    }

    private static Class getType(Type type) throws ClassNotFoundException {
        switch (type.getSort()) {
            case Type.VOID:
                return void.class;
            case Type.BOOLEAN:
                return boolean.class;
            case Type.CHAR:
                return char.class;
            case Type.BYTE:
                return byte.class;
            case Type.SHORT:
                return short.class;
            case Type.INT:
                return int.class;
            case Type.FLOAT:
                return float.class;
            case Type.LONG:
                return long.class;
            case Type.DOUBLE:
                return double.class;
            case Type.ARRAY:
                return Util.getArrayClass(getType(type.getElementType()),
                        type.getDimensions());
            default:
                return Class.forName(type.getClassName(), false, null);
        }
    }

    private static class ClassMetaHolder {

        private final Type classMetaType;
        private final Type type;
        private volatile @MonotonicNonNull Object classMeta;

        private ClassMetaHolder(Type classMetaType, Type type) {
            this.classMetaType = classMetaType;
            this.type = type;
        }

        private Object getClassMeta() throws Exception {
            Object classMetaLocal = classMeta;
            if (classMetaLocal != null) {
                return classMetaLocal;
            }
            synchronized (this) {
                if (classMeta == null) {
                    ClassInfo classInfo = new ClassInfoImpl(type.getClassName(), null);
                    classMeta = getType(classMetaType).getConstructor(ClassInfo.class)
                            .newInstance(classInfo);
                }
            }
            return classMeta;
        }
    }

    private static class MethodMetaHolder {

        private final Type methodMetaType;
        private final Type methodOwnerType;
        private final String methodName;
        private final Type methodReturnType;
        private final List methodParameterTypes;
        private volatile @MonotonicNonNull Object methodMeta;

        private MethodMetaHolder(Type methodMetaType, Type methodOwnerType, String methodName,
                Type methodReturnType, List methodParameterTypes) {
            this.methodMetaType = methodMetaType;
            this.methodOwnerType = methodOwnerType;
            this.methodName = methodName;
            this.methodReturnType = methodReturnType;
            this.methodParameterTypes = methodParameterTypes;
        }

        private Object getMethodMeta() throws Exception {
            Object methodMetaLocal = methodMeta;
            if (methodMetaLocal != null) {
                return methodMetaLocal;
            }
            synchronized (this) {
                if (methodMeta == null) {
                    List> methodParameterClasses =
                            Lists.newArrayListWithCapacity(methodParameterTypes.size());
                    for (Type methodParameterType : methodParameterTypes) {
                        methodParameterClasses.add(getType(methodParameterType));
                    }
                    MethodInfo methodInfo =
                            new MethodInfoImpl(methodName, getType(methodReturnType),
                                    methodParameterClasses, methodOwnerType.getClassName(), null);
                    methodMeta = getType(methodMetaType).getConstructor(MethodInfo.class)
                            .newInstance(methodInfo);
                }
            }
            return methodMeta;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy