File: Compiler\RuntimeDeterminedTypeHelper.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 System.Diagnostics;

using Internal.JitInterface;
using Internal.TypeSystem;
using Internal.Text;

namespace ILCompiler
{
    /// <summary>
    /// Helper class used to collapse runtime determined types
    /// based on their kind and index as we otherwise don't need
    /// to distinguish among them for the purpose of emitting
    /// signatures and generic lookups.
    /// </summary>
    public static class RuntimeDeterminedTypeHelper
    {
        public static bool Equals(Instantiation instantiation1, Instantiation instantiation2)
        {
            if (instantiation1.Length != instantiation2.Length)
            {
                return false;
            }
            for (int argIndex = 0; argIndex < instantiation1.Length; argIndex++)
            {
                if (!Equals(instantiation1[argIndex], instantiation2[argIndex]))
                {
                    return false;
                }
            }
            return true;
        }

        public static bool Equals(TypeDesc type1, TypeDesc type2)
        {
            if (type1 == type2)
            {
                return true;
            }

            if (type1 == null || type2 == null)
            {
                return false;
            }

            RuntimeDeterminedType runtimeDeterminedType1 = type1 as RuntimeDeterminedType;
            RuntimeDeterminedType runtimeDeterminedType2 = type2 as RuntimeDeterminedType;
            if (runtimeDeterminedType1 != null || runtimeDeterminedType2 != null)
            {
                if (runtimeDeterminedType1 == null || runtimeDeterminedType2 == null)
                {
                    return false;
                }
                return runtimeDeterminedType1.RuntimeDeterminedDetailsType.Index == runtimeDeterminedType2.RuntimeDeterminedDetailsType.Index &&
                    runtimeDeterminedType1.RuntimeDeterminedDetailsType.Kind == runtimeDeterminedType2.RuntimeDeterminedDetailsType.Kind;
            }

            ArrayType arrayType1 = type1 as ArrayType;
            ArrayType arrayType2 = type2 as ArrayType;
            if (arrayType1 != null || arrayType2 != null)
            {
                if (arrayType1 == null || arrayType2 == null)
                {
                    return false;
                }
                return arrayType1.Rank == arrayType2.Rank &&
                    arrayType1.IsSzArray == arrayType2.IsSzArray &&
                    Equals(arrayType1.ElementType, arrayType2.ElementType);
            }

            ByRefType byRefType1 = type1 as ByRefType;
            ByRefType byRefType2 = type2 as ByRefType;
            if (byRefType1 != null || byRefType2 != null)
            {
                if (byRefType1 == null || byRefType2 == null)
                {
                    return false;
                }
                return Equals(byRefType1.ParameterType, byRefType2.ParameterType);
            }

            if (type1.GetTypeDefinition() != type2.GetTypeDefinition() ||
                !Equals(type1.Instantiation, type2.Instantiation))
            {
                return false;
            }

            return true;
        }

        public static bool Equals(MethodDesc method1, MethodDesc method2)
        {
            if (method1 == method2)
            {
                return true;
            }
            if (method1 == null || method2 == null)
            {
                return false;
            }

            if (!Equals(method1.OwningType, method2.OwningType) ||
                method1.Signature.Length != method2.Signature.Length ||
                !Equals(method1.Instantiation, method2.Instantiation) ||
                !Equals(method1.Signature.ReturnType, method2.Signature.ReturnType))
            {
                return false;
            }
            for (int argIndex = 0; argIndex < method1.Signature.Length; argIndex++)
            {
                if (!Equals(method1.Signature[argIndex], method2.Signature[argIndex]))
                {
                    return false;
                }
            }
            return true;
        }

        public static bool Equals(MethodWithToken methodWithToken1, MethodWithToken methodWithToken2)
        {
            if (methodWithToken1 == methodWithToken2)
            {
                return true;
            }
            if (methodWithToken1 == null || methodWithToken2 == null)
            {
                return false;
            }
            return Equals(methodWithToken1.Method, methodWithToken2.Method)
                && Equals(methodWithToken1.OwningType, methodWithToken2.OwningType)
                && Equals(methodWithToken1.ConstrainedType, methodWithToken2.ConstrainedType)
                && Equals(methodWithToken1.Token.Module, methodWithToken2.Token.Module)
                && methodWithToken1.Unboxing == methodWithToken2.Unboxing;
        }

        public static bool Equals(FieldDesc field1, FieldDesc field2)
        {
            if (field1 == null || field2 == null)
            {
                return field1 == null && field2 == null;
            }
            return field1.Name.SequenceEqual(field2.Name) &&
                RuntimeDeterminedTypeHelper.Equals(field1.OwningType, field2.OwningType) &&
                RuntimeDeterminedTypeHelper.Equals(field1.FieldType, field2.FieldType);
        }

        public static bool Equals(FieldWithToken field1, FieldWithToken field2)
        {
            if (field1 == null || field2 == null)
            {
                return field1 == null && field2 == null;
            }
            return RuntimeDeterminedTypeHelper.Equals(field1.Field, field2.Field) &&
                Equals(field1.Token.Module, field2.Token.Module);
        }

        public static int GetHashCode(Instantiation instantiation)
        {
            int hashcode = unchecked(instantiation.Length << 24);
            for (int typeArgIndex = 0; typeArgIndex < instantiation.Length; typeArgIndex++)
            {
                hashcode = unchecked(hashcode * 73 + GetHashCode(instantiation[typeArgIndex]));
            }
            return hashcode;

        }

        public static int GetHashCode(TypeDesc type)
        {
            if (type == null)
            {
                return 0;
            }
            if (type is RuntimeDeterminedType runtimeDeterminedType)
            {
                return runtimeDeterminedType.RuntimeDeterminedDetailsType.Index ^
                    ((int)runtimeDeterminedType.RuntimeDeterminedDetailsType.Kind << 30);
            }
            return type.GetTypeDefinition().GetHashCode() ^ GetHashCode(type.Instantiation);
        }

        public static int GetHashCode(MethodDesc method)
        {
            if (method == null)
            {
                return 0;
            }
            return unchecked(GetHashCode(method.OwningType) + 97 * (
                method.GetTypicalMethodDefinition().GetHashCode() + 31 * GetHashCode(method.Instantiation)));
        }

        public static int GetHashCode(MethodWithToken method)
        {
            if (method == null)
            {
                return 0;
            }
            return unchecked(GetHashCode(method.Method) + 31 * GetHashCode(method.OwningType) + 97 * GetHashCode(method.ConstrainedType));
        }

        public static int GetHashCode(FieldDesc field)
        {
            if (field == null)
            {
                return 0;
            }
            return unchecked(GetHashCode(field.OwningType) + 97 * GetHashCode(field.FieldType) + 31 * field.GetName().GetHashCode());
        }

        public static int GetHashCode(FieldWithToken field)
        {
            if (field == null)
            {
                return 0;
            }
            return GetHashCode(field.Field);
        }
    }
}