| File: Compiler\CompilerTypeSystemContext.Aot.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; using System.Diagnostics; using System.Collections.Generic; using System.Runtime.CompilerServices; using Internal.TypeSystem; using Internal.IL; using Interlocked = System.Threading.Interlocked; namespace ILCompiler { public partial class CompilerTypeSystemContext { // Chosen rather arbitrarily. For the app that I was looking at, cutoff point of 7 compiled // more than 10 minutes on a release build of the compiler, and I lost patience. // Cutoff point of 5 produced an 1.7 GB object file. // Cutoff point of 4 produced an 830 MB object file. // Cutoff point of 3 produced an 470 MB object file. // We want this to be high enough so that it doesn't cut off too early. But also not too // high because things that are recursive often end up expanding laterally as well // through various other generic code the deep code calls into. public const int DefaultGenericCycleDepthCutoff = 4; public const int DefaultGenericCycleBreadthCutoff = 10; public SharedGenericsConfiguration GenericsConfig { get; } private readonly MetadataFieldLayoutAlgorithm _metadataFieldLayoutAlgorithm = new CompilerMetadataFieldLayoutAlgorithm(); private readonly RuntimeDeterminedFieldLayoutAlgorithm _runtimeDeterminedFieldLayoutAlgorithm = new RuntimeDeterminedFieldLayoutAlgorithm(); private readonly VectorOfTFieldLayoutAlgorithm _vectorOfTFieldLayoutAlgorithm; private readonly VectorFieldLayoutAlgorithm _vectorFieldLayoutAlgorithm; private readonly Int128FieldLayoutAlgorithm _int128FieldLayoutAlgorithm; private readonly TypeWithRepeatedFieldsFieldLayoutAlgorithm _typeWithRepeatedFieldsFieldLayoutAlgorithm; private TypeDesc[] _arrayOfTInterfaces; private TypeDesc[] _arrayEnumeratorOfTInterfaces; private ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; private MetadataType _arrayOfTType; private MetadataType _arrayOfTEnumeratorType; private MetadataType _attributeType; public CompilerTypeSystemContext(TargetDetails details, SharedGenericsMode genericsMode, DelegateFeature delegateFeatures, int genericCycleDepthCutoff = DefaultGenericCycleDepthCutoff, int genericCycleBreadthCutoff = DefaultGenericCycleBreadthCutoff) : base(details) { _genericsMode = genericsMode; _virtualMethodAlgorithm = new AsyncAwareVirtualMethodResolutionAlgorithm(this); _vectorOfTFieldLayoutAlgorithm = new VectorOfTFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm); _vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm); _int128FieldLayoutAlgorithm = new Int128FieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm); _typeWithRepeatedFieldsFieldLayoutAlgorithm = new TypeWithRepeatedFieldsFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm); _delegateInfoHashtable = new DelegateInfoHashtable(delegateFeatures); _continuationTypeHashtable = new ContinuationTypeHashtable(this); _genericCycleDetector = new LazyGenericsSupport.GenericCycleDetector(genericCycleDepthCutoff, genericCycleBreadthCutoff); GenericsConfig = new SharedGenericsConfiguration(); } public MetadataType ArrayOfTEnumeratorType { get { // This type is optional, but it's fine for this cache to be ineffective if that happens. // Those scenarios are rare and typically deal with small compilations. return _arrayOfTEnumeratorType ??= SystemModule.GetType("System"u8, "SZGenericArrayEnumerator`1"u8, throwIfNotFound: false); } } public bool IsArrayVariantCastable(TypeDesc type) { // Arrays and array enumerators have weird casting rules due to array covariance // (string[] castable to object[], or int[] castable to uint[], or int[] castable // to IList<SomeIntEnum>). if (type.IsSzArray || type.GetTypeDefinition() == ArrayOfTEnumeratorType || IsGenericArrayInterfaceType(type) || IsGenericArrayEnumeratorInterfaceType(type)) { TypeDesc elementType = type.IsSzArray ? ((ArrayType)type).ElementType : type.Instantiation[0]; if (CastingHelper.IsArrayElementTypeCastableBySize(elementType) || (elementType.IsDefType && !elementType.IsValueType)) { return true; } } return false; } protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) { _arrayOfTRuntimeInterfacesAlgorithm ??= new ArrayOfTRuntimeInterfacesAlgorithm(SystemModule.GetKnownType("System"u8, "Array`1"u8)); return _arrayOfTRuntimeInterfacesAlgorithm; } public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) { if (type.IsRuntimeDeterminedType) return _runtimeDeterminedFieldLayoutAlgorithm; else if (VectorOfTFieldLayoutAlgorithm.IsVectorOfTType(type)) return _vectorOfTFieldLayoutAlgorithm; else if (VectorFieldLayoutAlgorithm.IsVectorType(type)) return _vectorFieldLayoutAlgorithm; else if (Int128FieldLayoutAlgorithm.IsIntegerType(type)) return _int128FieldLayoutAlgorithm; else if (type is TypeWithRepeatedFields) return _typeWithRepeatedFieldsFieldLayoutAlgorithm; else return _metadataFieldLayoutAlgorithm; } protected override bool ComputeHasGCStaticBase(FieldDesc field) { Debug.Assert(field.IsStatic); if (field.IsThreadStatic) return true; TypeDesc fieldType = field.FieldType; if (fieldType.IsValueType) return ((DefType)fieldType).ContainsGCPointers; else return fieldType.IsGCPointer; } /// <summary> /// Returns true if <paramref name="type"/> is a generic interface type implemented by arrays. /// </summary> public bool IsGenericArrayInterfaceType(TypeDesc type) { // Hardcode the fact that all generic interfaces on array types have arity 1 if (!type.IsInterface || type.Instantiation.Length != 1) return false; if (_arrayOfTInterfaces == null) { DefType[] implementedInterfaces = SystemModule.GetKnownType("System"u8, "Array`1"u8).ExplicitlyImplementedInterfaces; TypeDesc[] interfaceDefinitions = new TypeDesc[implementedInterfaces.Length]; for (int i = 0; i < interfaceDefinitions.Length; i++) interfaceDefinitions[i] = implementedInterfaces[i].GetTypeDefinition(); Interlocked.CompareExchange(ref _arrayOfTInterfaces, interfaceDefinitions, null); } TypeDesc interfaceDefinition = type.GetTypeDefinition(); foreach (var arrayInterfaceDefinition in _arrayOfTInterfaces) { if (interfaceDefinition == arrayInterfaceDefinition) return true; } return false; } public bool IsGenericArrayEnumeratorInterfaceType(TypeDesc type) { // Hardcode the fact that all generic interfaces on array enumerator have arity 1 if (!type.IsInterface || type.Instantiation.Length != 1) return false; if (_arrayEnumeratorOfTInterfaces == null) { DefType[] implementedInterfaces = ArrayOfTEnumeratorType?.ExplicitlyImplementedInterfaces; ArrayBuilder<TypeDesc> definitions = default; if (implementedInterfaces != null) { foreach (DefType interfaceType in implementedInterfaces) { if (interfaceType.HasInstantiation) definitions.Add(interfaceType.GetTypeDefinition()); } } Interlocked.CompareExchange(ref _arrayEnumeratorOfTInterfaces, definitions.ToArray(), null); } TypeDesc interfaceDefinition = type.GetTypeDefinition(); return Array.IndexOf(_arrayEnumeratorOfTInterfaces, interfaceDefinition) >= 0; } protected override IEnumerable<MethodDesc> GetAllMethods(TypeDesc type) { return GetAllMethods(type, virtualOnly: false); } protected override IEnumerable<MethodDesc> GetAllVirtualMethods(TypeDesc type) { return GetAllMethods(type, virtualOnly: true); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private IEnumerable<MethodDesc> GetAllMethods(TypeDesc type, bool virtualOnly) { MetadataType attributeType = _attributeType ??= SystemModule.GetType("System"u8, "Attribute"u8); if (type.IsDelegate) { return GetAllMethodsForDelegate(type, virtualOnly); } else if (type.IsValueType) { return GetAllMethodsForValueType(type, virtualOnly); } else if (type.CanCastTo(attributeType)) { return GetAllMethodsForAttribute(type, virtualOnly); } return virtualOnly ? type.GetVirtualMethods() : type.GetMethods(); } protected virtual IEnumerable<MethodDesc> GetAllMethodsForDelegate(TypeDesc type, bool virtualOnly) { // Inject the synthetic methods that support the implementation of the delegate. InstantiatedType instantiatedType = type as InstantiatedType; if (instantiatedType != null) { DelegateInfo info = GetDelegateInfo(type.GetTypeDefinition()); foreach (MethodDesc syntheticMethod in info.Methods) { if (!virtualOnly || syntheticMethod.IsVirtual) yield return GetMethodForInstantiatedType(syntheticMethod, instantiatedType); } } else { DelegateInfo info = GetDelegateInfo(type); foreach (MethodDesc syntheticMethod in info.Methods) { if (!virtualOnly || syntheticMethod.IsVirtual) yield return syntheticMethod; } } // Append all the methods defined in metadata IEnumerable<MethodDesc> metadataMethods = virtualOnly ? type.GetVirtualMethods() : type.GetMethods(); foreach (var m in metadataMethods) yield return m; } internal DefType GetClosestDefType(TypeDesc type) { if (type.IsArray) { if (!type.IsArrayTypeWithoutGenericInterfaces()) { MetadataType arrayShadowType = _arrayOfTType ??= SystemModule.GetType("System"u8, "Array`1"u8); return arrayShadowType.MakeInstantiatedType(((ArrayType)type).ElementType); } return GetWellKnownType(WellKnownType.Array); } Debug.Assert(type is DefType); return (DefType)type; } private readonly LazyGenericsSupport.GenericCycleDetector _genericCycleDetector; public void DetectGenericCycles(TypeSystemEntity owner, TypeSystemEntity referent) { _genericCycleDetector.DetectCycle(owner, referent); } public void LogWarnings(Logger logger) { _genericCycleDetector.LogWarnings(logger); } } public class SharedGenericsConfiguration { // To avoid infinite generic recursion issues during debug type record generation, attempt to // use canonical form for types with high generic complexity. public long MaxGenericDepthOfDebugRecord { get; } public SharedGenericsConfiguration() { MaxGenericDepthOfDebugRecord = 15; } } }