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

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

The newest version!
/*
 * Copyright 2014-2015 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.weaving;

import java.lang.reflect.Constructor;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

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

import org.glowroot.common.Reflections;
import org.glowroot.markers.UsedByGeneratedBytecode;

import static org.glowroot.shaded.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
@UsedByGeneratedBytecode
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() {}

    public 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;
        }
    }

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

    public 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);
    }

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

    @UsedByGeneratedBytecode
    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();
    }

    @UsedByGeneratedBytecode
    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 GeneratedBytecodeUtil.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) {
                    Class classMetaClass = getType(classMetaType);
                    Class wovenClass = getType(type);
                    Constructor constructor =
                            Reflections.getConstructor(classMetaClass, Class.class);
                    classMeta = Reflections.invoke(constructor, wovenClass);
                }
            }
            return classMeta;
        }
    }

    private static class MethodMetaHolder {

        private final Type methodMetaType;
        private final Type type;
        private final Type returnType;
        private final List parameterTypes;
        private volatile @MonotonicNonNull Object methodMeta;

        private MethodMetaHolder(Type methodMetaType, Type type, Type returnType,
                List parameterTypes) {
            this.methodMetaType = methodMetaType;
            this.type = type;
            this.returnType = returnType;
            this.parameterTypes = parameterTypes;
        }

        private Object getMethodMeta() throws Exception {
            Object methodMetaLocal = methodMeta;
            if (methodMetaLocal != null) {
                return methodMetaLocal;
            }
            synchronized (this) {
                if (methodMeta == null) {
                    Class classMetaClass = getType(methodMetaType);
                    Class wovenClass = getType(type);
                    Class returnClass = getType(returnType);
                    Class[] parameterClasses = new Class[parameterTypes.size()];
                    for (int i = 0; i < parameterTypes.size(); i++) {
                        parameterClasses[i] = getType(parameterTypes.get(i));
                    }
                    Constructor constructor = Reflections.getConstructor(classMetaClass,
                            Class.class, Class.class, Class[].class);
                    methodMeta = Reflections.invoke(constructor, wovenClass, returnClass,
                            parameterClasses);
                }
            }
            return methodMeta;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy