File: Linker.Steps\MarkSubStepsDispatcher.cs
Web Access
Project: src\src\tools\illink\src\linker\Mono.Linker.csproj (illink)
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
using System.Collections.Generic;
using System.Diagnostics;
 
using Mono.Cecil;
using Mono.Collections.Generic;
 
namespace Mono.Linker.Steps
{
    //
    // Dispatcher for SubSteps which only need to run on marked assemblies.
    // This simplifies the implementation of ILLink custom steps, in the same
    // way that SubStepsDispatcher does, but it implements IMarkHandler
    // and registers a callback that gets invoked during MarkStep when an
    // assembly gets marked.
    //
    public class MarkSubStepsDispatcher : IMarkHandler
    {
        readonly List<ISubStep> substeps;
 
        CategorizedSubSteps? categorized;
        CategorizedSubSteps Categorized
        {
            get
            {
                Debug.Assert(categorized.HasValue);
                return categorized.Value;
            }
        }
 
        public MarkSubStepsDispatcher(IEnumerable<ISubStep> subSteps)
        {
            substeps = new List<ISubStep>(subSteps);
        }
 
        public virtual void Initialize(LinkContext context, MarkContext markContext)
        {
            InitializeSubSteps(context);
            markContext.RegisterMarkAssemblyAction(BrowseAssembly);
        }
 
        static bool HasSubSteps(List<ISubStep> substeps) => substeps?.Count > 0;
 
        void BrowseAssembly(AssemblyDefinition assembly)
        {
            CategorizeSubSteps(assembly);
 
            if (HasSubSteps(Categorized.on_assemblies))
                DispatchAssembly(assembly);
 
            if (!ShouldDispatchTypes())
                return;
 
            BrowseTypes(assembly.MainModule.Types);
        }
 
        bool ShouldDispatchTypes()
        {
            return HasSubSteps(Categorized.on_types)
                || HasSubSteps(Categorized.on_fields)
                || HasSubSteps(Categorized.on_methods)
                || HasSubSteps(Categorized.on_properties)
                || HasSubSteps(Categorized.on_events);
        }
 
        void BrowseTypes(Collection<TypeDefinition> types)
        {
            foreach (TypeDefinition type in types)
            {
                DispatchType(type);
 
                if (type.HasFields && HasSubSteps(Categorized.on_fields))
                {
                    foreach (FieldDefinition field in type.Fields)
                        DispatchField(field);
                }
 
                if (type.HasMethods && HasSubSteps(Categorized.on_methods))
                {
                    foreach (MethodDefinition method in type.Methods)
                        DispatchMethod(method);
                }
 
                if (type.HasProperties && HasSubSteps(Categorized.on_properties))
                {
                    foreach (PropertyDefinition property in type.Properties)
                        DispatchProperty(property);
                }
 
                if (type.HasEvents && HasSubSteps(Categorized.on_events))
                {
                    foreach (EventDefinition @event in type.Events)
                        DispatchEvent(@event);
                }
 
                if (type.HasNestedTypes)
                    BrowseTypes(type.NestedTypes);
            }
        }
 
        void DispatchAssembly(AssemblyDefinition assembly)
        {
            foreach (var substep in Categorized.on_assemblies)
            {
                substep.ProcessAssembly(assembly);
            }
        }
 
        void DispatchType(TypeDefinition type)
        {
            foreach (var substep in Categorized.on_types)
            {
                substep.ProcessType(type);
            }
        }
 
        void DispatchField(FieldDefinition field)
        {
            foreach (var substep in Categorized.on_fields)
            {
                substep.ProcessField(field);
            }
        }
 
        void DispatchMethod(MethodDefinition method)
        {
            foreach (var substep in Categorized.on_methods)
            {
                substep.ProcessMethod(method);
            }
        }
 
        void DispatchProperty(PropertyDefinition property)
        {
            foreach (var substep in Categorized.on_properties)
            {
                substep.ProcessProperty(property);
            }
        }
 
        void DispatchEvent(EventDefinition @event)
        {
            foreach (var substep in Categorized.on_events)
            {
                substep.ProcessEvent(@event);
            }
        }
 
        void InitializeSubSteps(LinkContext context)
        {
            foreach (var substep in substeps)
                substep.Initialize(context);
        }
 
        void CategorizeSubSteps(AssemblyDefinition assembly)
        {
            categorized = new CategorizedSubSteps
            {
                on_assemblies = new List<ISubStep>(),
                on_types = new List<ISubStep>(),
                on_fields = new List<ISubStep>(),
                on_methods = new List<ISubStep>(),
                on_properties = new List<ISubStep>(),
                on_events = new List<ISubStep>()
            };
 
            foreach (var substep in substeps)
                CategorizeSubStep(substep, assembly);
        }
 
        void CategorizeSubStep(ISubStep substep, AssemblyDefinition assembly)
        {
            if (!substep.IsActiveFor(assembly))
                return;
 
            CategorizeTarget(substep, SubStepTargets.Assembly, Categorized.on_assemblies);
            CategorizeTarget(substep, SubStepTargets.Type, Categorized.on_types);
            CategorizeTarget(substep, SubStepTargets.Field, Categorized.on_fields);
            CategorizeTarget(substep, SubStepTargets.Method, Categorized.on_methods);
            CategorizeTarget(substep, SubStepTargets.Property, Categorized.on_properties);
            CategorizeTarget(substep, SubStepTargets.Event, Categorized.on_events);
        }
 
        static void CategorizeTarget(ISubStep substep, SubStepTargets target, List<ISubStep> list)
        {
            if (!Targets(substep, target))
                return;
 
            list.Add(substep);
        }
 
        static bool Targets(ISubStep substep, SubStepTargets target) => (substep.Targets & target) == target;
    }
}