File: Compiler\DependencyAnalysis\ProxyTypeMapNode.cs
Web Access
Project: src\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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
using Internal.NativeFormat;
using Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis
{
    internal sealed class ProxyTypeMapNode : SortableDependencyNode, IProxyTypeMapNode
    {
        private readonly IEnumerable<KeyValuePair<TypeDesc, TypeDesc>> _mapEntries;

        public ProxyTypeMapNode(TypeDesc typeMapGroup, IEnumerable<KeyValuePair<TypeDesc, TypeDesc>> mapEntries)
        {
            _mapEntries = mapEntries;
            TypeMapGroup = typeMapGroup;
        }

        public TypeDesc TypeMapGroup { get; }

        public IEnumerable<KeyValuePair<TypeDesc, TypeDesc>> MapEntries => _mapEntries;
        public override bool InterestingForDynamicDependencyAnalysis => false;

        public override bool HasDynamicDependencies => false;

        public override bool HasConditionalStaticDependencies => true;

        public override bool StaticDependenciesAreComputed => true;

        public override int ClassCode => 779513676;

        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) => comparer.Compare(TypeMapGroup, ((ProxyTypeMapNode)other).TypeMapGroup);

        public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context)
        {
            foreach (var (key, value) in _mapEntries)
            {
                yield return new CombinedDependencyListEntry(
                    context.MetadataTypeSymbol(value),
                    context.MaximallyConstructableType(key),
                    "Proxy type map entry");

                // If the key type has a canonical form, it could be created at runtime by the type loader.
                // If there is a type loader template for it, create the generic type instantiation eagerly.
                TypeDesc canonKey = key.ConvertToCanonForm(CanonicalFormKind.Specific);
                if (canonKey != key && GenericTypesTemplateMap.IsEligibleToHaveATemplate(canonKey))
                {
                    yield return new CombinedDependencyListEntry(
                        context.MaximallyConstructableType(key),
                        context.NativeLayout.TemplateTypeLayout(canonKey),
                        "Proxy map entry that could be loaded at runtime");
                }
            }
        }

        public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context) => Array.Empty<DependencyListEntry>();
        public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) => Array.Empty<CombinedDependencyListEntry>();
        protected override string GetName(NodeFactory context) => $"Proxy type map: {TypeMapGroup}";

        private IEnumerable<(IEETypeNode key, IEETypeNode value)> GetMarkedEntries(NodeFactory factory)
        {
            foreach (var (key, value) in MapEntries)
            {
                IEETypeNode keyNode = factory.MaximallyConstructableType(key);
                if (keyNode.Marked)
                {
                    IEETypeNode valueNode = factory.MetadataTypeSymbol(value);
                    Debug.Assert(valueNode.Marked);
                    yield return (keyNode, valueNode);
                }
            }
        }

        public Vertex CreateTypeMap(NodeFactory factory, NativeWriter writer, Section section, INativeFormatTypeReferenceProvider externalReferences)
        {
            VertexHashtable typeMapHashTable = new VertexHashtable();

            foreach ((IEETypeNode keyNode, IEETypeNode valueNode) in GetMarkedEntries(factory))
            {
                Vertex keyVertex = externalReferences.EncodeReferenceToType(writer, keyNode.Type);
                Vertex valueVertex = externalReferences.EncodeReferenceToType(writer, valueNode.Type);
                Vertex entry = writer.GetTuple(keyVertex, valueVertex);
                typeMapHashTable.Append((uint)keyNode.Type.GetHashCode(), section.Place(entry));
            }

            Vertex typeMapStateVertex = writer.GetUnsignedConstant(1); // Valid type map state
            Vertex typeMapGroupVertex = externalReferences.EncodeReferenceToType(writer, TypeMapGroup);
            Vertex tuple = writer.GetTuple(typeMapGroupVertex, typeMapStateVertex, typeMapHashTable);
            return section.Place(tuple);
        }

        public IProxyTypeMapNode ToAnalysisBasedNode(NodeFactory factory)
            => new AnalyzedProxyTypeMapNode(
                TypeMapGroup,
                GetMarkedEntries(factory)
                .ToImmutableDictionary(p => p.key.Type, p => p.value.Type));
    }
}