File: Compiler\DependencyAnalysis\ReadyToRun\EnclosingTypeMapNode.cs
Web Access
Project: src\src\runtime\src\coreclr\tools\aot\ILCompiler.ReadyToRun\ILCompiler.ReadyToRun.csproj (ILCompiler.ReadyToRun)
// 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 Internal.Text;
using Internal.TypeSystem.Ecma;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using Internal.ReadyToRunConstants;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
    public class EnclosingTypeMapNode : ModuleSpecificHeaderTableNode
    {
        private MetadataReader _metadata;

        public EnclosingTypeMapNode(EcmaModule module) : base(module)
        {
            _metadata = module.MetadataReader;
            // This map is only valid for assemblies with <= ReadyToRunEnclosingTypeMap.MaxTypeCount types defined within
            if (!IsSupported(_metadata))
                throw new InternalCompilerErrorException($"EnclosingTypeMap made for assembly with more than 0x{(uint)ReadyToRunEnclosingTypeMap.MaxTypeCount:x} types");
        }

        public static bool IsSupported(MetadataReader metadata)
        {
            // This map is only valid for assemblies with <= ReadyToRunEnclosingTypeMap.MaxTypeCount types defined within
            // and really shouldn't be generated for tiny assemblies, as the map provides very little to no value
            // in those situations
            int typeDefinitionCount = metadata.TypeDefinitions.Count;

            return ((typeDefinitionCount > 10) && (typeDefinitionCount <= (int)ReadyToRunEnclosingTypeMap.MaxTypeCount));
        }

        public override int ClassCode => 990540812;

        protected override string ModuleSpecificName => "__EnclosingTypeMap__";

        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
                return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });

            ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
            builder.AddSymbol(this);

            // This map is only valid for assemblies with <= ReadyToRunEnclosingTypeMap.MaxTypeCount types defined within
            Debug.Assert(_metadata.TypeDefinitions.Count <= (int)ReadyToRunEnclosingTypeMap.MaxTypeCount);
            builder.EmitUShort(checked((ushort)_metadata.TypeDefinitions.Count));

            foreach (var typeDefinitionHandle in _metadata.TypeDefinitions)
            {
                var typeDefinition = _metadata.GetTypeDefinition(typeDefinitionHandle);
                if (!typeDefinition.IsNested)
                {
                    builder.EmitUShort(0);
                }
                else
                {
                    builder.EmitUShort(checked((ushort)MetadataTokens.GetRowNumber(typeDefinition.GetDeclaringType())));
                }
            }

            return builder.ToObjectData();
        }
    }
}