File: parent\parent\Common\TypeSystem\Canon\CanonTypes.cs
Web Access
Project: ILCompiler.TypeSystem.csproj (ILCompiler.TypeSystem)
// 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 Internal.NativeFormat;
using Internal.Text;

using Debug = System.Diagnostics.Debug;

#if TYPE_LOADER_IMPLEMENTATION
using MetadataType = Internal.TypeSystem.DefType;
#endif

namespace Internal.TypeSystem
{
    /// <summary>
    /// Type of canonicalization applied to a type
    /// </summary>
    public enum CanonicalFormKind
    {
        /// <summary>
        /// Optimized for a particular set of instantiations (such as reference types)
        /// </summary>
        Specific,

        /// <summary>
        /// Canonicalization that works for any type
        /// </summary>
        Universal,

        /// <summary>
        /// Value used for lookup for Specific or Universal. Must not be used for canonicalizing.
        /// </summary>
        Any,
    }

    /// <summary>
    /// Base class for specialized and universal canon types
    /// </summary>
    public abstract partial class CanonBaseType
    {
        private TypeSystemContext _context;

        public CanonBaseType(TypeSystemContext context)
        {
            _context = context;
        }

        public sealed override TypeSystemContext Context
        {
            get
            {
                return _context;
            }
        }

        public override MetadataType ContainingType => null;
    }

    /// <summary>
    /// Type used for specific canonicalization (e.g. for reference types)
    /// </summary>
    internal sealed partial class CanonType : CanonBaseType
    {
        private int _hashcode;

        public override Utf8Span Namespace
        {
            get
            {
                return "System"u8;
            }
        }

        public override Utf8Span Name
        {
            get
            {
                return "__Canon"u8;
            }
        }

        public CanonType(TypeSystemContext context)
            : base(context)
        {
            Initialize();
        }

        // Provides an extensibility hook for type system consumers that need to perform
        // consumer-specific initialization.
        partial void Initialize();

        public override MetadataType BaseType
        {
            get
            {
                return (MetadataType)Context.GetWellKnownType(WellKnownType.Object);
            }
        }

        public override bool IsCanonicalSubtype(CanonicalFormKind policy)
        {
            return policy == CanonicalFormKind.Specific ||
                policy == CanonicalFormKind.Any;
        }

        protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind)
        {
            Debug.Assert(kind == CanonicalFormKind.Specific);
            return this;
        }

        protected override TypeFlags ComputeTypeFlags(TypeFlags mask)
        {
            TypeFlags flags = 0;

            if ((mask & TypeFlags.CategoryMask) != 0)
            {
                flags |= TypeFlags.Class;
            }

            if ((mask & TypeFlags.HasGenericVarianceComputed) != 0)
            {
                flags |= TypeFlags.HasGenericVarianceComputed;
            }

            flags |= TypeFlags.HasFinalizerComputed;
            flags |= TypeFlags.AttributeCacheComputed;

            return flags;
        }

        public override int GetHashCode()
        {
            if (_hashcode == 0)
            {
                _hashcode = VersionResilientHashCode.NameHashCode(Namespace, Name);
            }

            return _hashcode;
        }
    }

    /// <summary>
    /// Type that can be used for canonicalization of any type (including value types of unknown size)
    /// </summary>
    internal sealed partial class UniversalCanonType : CanonBaseType
    {
        private int _hashcode;

        public override Utf8Span Namespace
        {
            get
            {
                return "System"u8;
            }
        }

        public override Utf8Span Name
        {
            get
            {
                return "__UniversalCanon"u8;
            }
        }

        public UniversalCanonType(TypeSystemContext context)
            : base(context)
        {
            Initialize();
        }

        // Provides an extensibility hook for type system consumers that need to perform
        // consumer-specific initialization.
        partial void Initialize();

        public override MetadataType BaseType
        {
            get
            {
                // UniversalCanon is "a struct of indeterminate size and GC layout"
                return (MetadataType)Context.GetWellKnownType(WellKnownType.ValueType);
            }
        }

        public override bool IsCanonicalSubtype(CanonicalFormKind policy)
        {
            return policy == CanonicalFormKind.Universal ||
                policy == CanonicalFormKind.Any;
        }

        protected override TypeDesc ConvertToCanonFormImpl(CanonicalFormKind kind)
        {
            return this;
        }

        protected override TypeFlags ComputeTypeFlags(TypeFlags mask)
        {
            TypeFlags flags = 0;

            if ((mask & TypeFlags.CategoryMask) != 0)
            {
                // Universally canonical type is reported as a variable-sized struct.
                // It's the closest logical thing and avoids special casing around it.
                flags |= TypeFlags.ValueType;
            }

            flags |= TypeFlags.HasFinalizerComputed;
            flags |= TypeFlags.AttributeCacheComputed;
            flags |= TypeFlags.HasGenericVarianceComputed;

            return flags;
        }

        public override int GetHashCode()
        {
            if (_hashcode == 0)
            {
                _hashcode = VersionResilientHashCode.NameHashCode(Namespace, Name);
            }

            return _hashcode;
        }
    }
}