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

org.qbicc.plugin.reachability.ReachabilityRoots Maven / Gradle / Ivy

There is a newer version: 0.77.0
Show newest version
package org.qbicc.plugin.reachability;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.qbicc.context.AttachmentKey;
import org.qbicc.context.CompilationContext;
import org.qbicc.type.definition.LoadedTypeDefinition;
import org.qbicc.type.definition.element.ConstructorElement;
import org.qbicc.type.definition.element.ExecutableElement;
import org.qbicc.type.definition.element.FieldElement;
import org.qbicc.type.definition.element.MethodElement;
import org.qbicc.type.definition.element.StaticFieldElement;

/**
 * Tracks the Classes, Methods, Constructors, and Fields that
 * are not native Entrypoints, but need to be treated as-if they
 * were spontaneously callable for the purpose of ReachabilityAnalysis.
 * These program elements generally fall into two broad categories:
 *   1. Elements that are accessed reflectively
 *   2. Elements that are part of the qbicc runtime and will be
 *      accessed by code expansions that happen after the ADD phase.
 *
 * A key different between this class and ReachabilityInfo is that it
 * is not cleared between phases.  Thus, once a program element is
 * registered as being a ReachabilityRoot, it is guaranteed to be
 * considered reachable for the rest of the compilation.
 */
public class ReachabilityRoots {
    private static final AttachmentKey KEY = new AttachmentKey<>();

    private final CompilationContext ctxt;
    private final Set reflectiveClasses = ConcurrentHashMap.newKeySet();
    private final Set reflectiveMethods = ConcurrentHashMap.newKeySet();
    private final Set reflectiveFields = ConcurrentHashMap.newKeySet();
    private final Set autoQueuedMethods = ConcurrentHashMap.newKeySet();
    private final Set dispatchTableMethods = ConcurrentHashMap.newKeySet();

    private ReachabilityRoots(final CompilationContext ctxt) {
        this.ctxt = ctxt;
    }

    public static ReachabilityRoots get(CompilationContext ctxt) {
        ReachabilityRoots info = ctxt.getAttachment(KEY);
        if (info == null) {
            info = new ReachabilityRoots(ctxt);
            ReachabilityRoots appearing = ctxt.putAttachmentIfAbsent(KEY, info);
            if (appearing != null) {
                info = appearing;
            }
        }
        return info;
    }

    public void reportStats() {
        ReachabilityInfo.LOGGER.debugf("  Auto-queued methods:           %s", autoQueuedMethods.size());
        ReachabilityInfo.LOGGER.debugf("  Reflectively accessed classes: %s", reflectiveClasses.size());
        ReachabilityInfo.LOGGER.debugf("  Reflectively accessed methods: %s", reflectiveMethods.size());
        ReachabilityInfo.LOGGER.debugf("  Reflectively accessed fields:  %s", reflectiveFields.size());
    }

    public void registerReflectiveClass(LoadedTypeDefinition ltd) {
        reflectiveClasses.add(ltd);
    }

    public boolean registerReflectiveMethod(MethodElement e) {
        boolean added = reflectiveMethods.add(e);
        if (added) {
            ctxt.enqueue(e);
        }
        return added;
    }

    public boolean registerReflectiveConstructor(ConstructorElement e) {
        boolean added = reflectiveMethods.add(e);
        if (added) {
            ctxt.enqueue(e);
        }
        return added;
    }

    public boolean registerAutoQueuedElement(ExecutableElement e) {
        boolean added = autoQueuedMethods.add(e);
        if (added) {
            ctxt.enqueue(e);
        }
        return added;
    }

    public boolean registerDispatchTableEntry(ExecutableElement e) {
        return dispatchTableMethods.add(e);
    }

    public boolean registerReflectiveField(FieldElement f) {
        return reflectiveFields.add(f);
    }

    // During Analyze, we can allow reachability analysis to figure things out for us.
    public static void processRootsForAnalyze(CompilationContext ctxt) {
        ReachabilityRoots roots = get(ctxt);
        ReachabilityInfo info = ReachabilityInfo.get(ctxt);
        for (ExecutableElement e : roots.autoQueuedMethods) {
            info.processRootReachableElement(e);
        }
        for (LoadedTypeDefinition ltd : roots.reflectiveClasses) {
            ReachabilityInfo.LOGGER.debugf("Reflectively accessed type %s made reachable", ltd.toString());
            info.getAnalysis().processReachableType(ltd, null);
        }
        for (ExecutableElement e : roots.reflectiveMethods) {
            info.processRootReachableElement(e);
        }
        for (FieldElement f : roots.reflectiveFields) {
            if (f.isStatic()) {
                info.getAnalysis().processReachableStaticFieldAccess((StaticFieldElement) f, null);
            }
        }
    }

    // During Lower, we don't have to handle instance methods in the autoQueued or reflective sets.
    // These methods are either in the dispatchTable set, or reachability analysis has determined that
    // there cannot be an instantiated class that could invoke the method, and therefore it is not reachable.
    public static void processRootsForLower(CompilationContext ctxt) {
        ReachabilityRoots roots = get(ctxt);
        for (ExecutableElement e : roots.autoQueuedMethods) {
            if (e.isStatic()) {
                ctxt.enqueue(e);
            }
        }
        for (ExecutableElement e : roots.reflectiveMethods) {
            if (e.isStatic()) {
                ctxt.enqueue(e);
            }
        }
        for (ExecutableElement e : roots.dispatchTableMethods) {
            ctxt.enqueue(e);
        }
    }

    public Set getReflectiveClasses() {
        return new HashSet<>(reflectiveClasses);
    }

    public Set getReflectiveFields() {
        return new HashSet<>(reflectiveFields);
    }

    public Set getReflectiveMethods() {
        return new HashSet<>(reflectiveMethods);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy