File: Compiler\RuntimeConstructableTypeDependencies.cs
Web Access
Project: src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;

using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

namespace ILCompiler
{
    internal static class RuntimeConstructableTypeDependencies
    {
        public static IEETypeNode GetEffectiveTrimTargetType(NodeFactory factory, TypeDesc trimmingTargetType, bool conditionConstructed)
        {
            bool unwrapped = false;

            // Many parameterized types can be created at runtime using the type loader.
            // Pointers and byrefs can be made out of thin air since there's no code for them.
            // Arrays have some rules so we may still be able to condition on the array.
            while (trimmingTargetType.IsParameterizedType)
            {
                if (GenericTypesTemplateMap.IsArrayTypeEligibleForTemplate(trimmingTargetType)
                    // The template shouldn't be __Canon[]
                    && !trimmingTargetType.ConvertToCanonForm(CanonicalFormKind.Specific).GetParameterType().IsCanonicalDefinitionType(CanonicalFormKind.Any))
                {
                    // We can condition on this type since we'd either need this type to be
                    // present in the compilation, or template for this type to be present.
                    //
                    // We specifically exclude the `__Canon[]` template because conditioning
                    // on the __Canon[] template would be strictly worse than conditioning on
                    // the element type in a normal app.
                    break;
                }

                // The type can be just MakeArrayType/MakePointerType at runtime, so drill into
                // the element type, we need to condition on that - can't condition on the
                // constructed type.
                trimmingTargetType = trimmingTargetType.GetParameterType();

                unwrapped = true;
            }

            if (!conditionConstructed)
                return factory.NecessaryTypeSymbol(trimmingTargetType);

            // If we're conditioning on the type being constructed but we unwrapped element type,
            // the condition is now only a metadata type symbol. This is because e.g.
            // `Array.CreateInstance(typeof(Element))` needs only the typeof-level type load
            // of the element type to create a constructed array type.
            return unwrapped
                ? factory.MetadataTypeSymbol(trimmingTargetType)
                : factory.MaximallyConstructableType(trimmingTargetType);
        }

        public static void AddTypeLoaderDependencies(
            List<DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry> dependencies,
            NodeFactory factory,
            IEETypeNode dependencyType,
            string reason)
        {
            TypeDesc type = dependencyType.Type;
            TypeDesc canonType = type.ConvertToCanonForm(CanonicalFormKind.Specific);
            if (canonType != type && GenericTypesTemplateMap.IsEligibleToHaveATemplate(canonType))
            {
                dependencies.Add(new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(
                    dependencyType,
                    factory.NativeLayout.TemplateTypeLayout(canonType),
                    reason));
            }
       }
    }
}