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