diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index c0d835ef5fc28a..e184ddfe89ed37 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -161,7 +161,7 @@ protected virtual MethodInfo GetMethodImpl() IRuntimeMethodInfo method = FindMethodHandle(); RuntimeType? declaringType = RuntimeMethodHandle.GetDeclaringType(method); // need a proper declaring type instance method on a generic type - if (RuntimeTypeHandle.IsGenericTypeDefinition(declaringType) || RuntimeTypeHandle.HasInstantiation(declaringType)) + if (declaringType.IsGenericType) { bool isStatic = (RuntimeMethodHandle.GetAttributes(method) & MethodAttributes.Static) != (MethodAttributes)0; if (!isStatic) diff --git a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs index a32d004e89d6c6..bc6a24a4c23941 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs @@ -545,7 +545,7 @@ protected override MethodInfo GetMethodImpl() RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(method); // need a proper declaring type instance method on a generic type - if (RuntimeTypeHandle.IsGenericTypeDefinition(declaringType) || RuntimeTypeHandle.HasInstantiation(declaringType)) + if (declaringType.IsGenericType) { // we are returning the 'Invoke' method of this delegate so use this.GetType() for the exact type RuntimeType reflectedType = (RuntimeType)GetType(); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs index bc972ea7782cfd..4e0f0dc8f5d00c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs @@ -1036,7 +1036,7 @@ public int GetTokenFor(RuntimeMethodHandle method) if (!RuntimeMethodHandle.IsDynamicMethod(rmhi)) { RuntimeType type = RuntimeMethodHandle.GetDeclaringType(rmhi); - if ((type != null) && RuntimeTypeHandle.HasInstantiation(type)) + if (type.IsGenericType) { // Do we really need to retrieve this much info just to throw an exception? MethodBase m = RuntimeType.GetMethodBase(methodReal)!; diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 9fb736b48f9b0b..14c36da882f526 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -490,13 +490,20 @@ internal unsafe struct MethodTable public MethodTable** InterfaceMap; // WFLAGS_LOW_ENUM + private const uint enum_flag_GenericsMask = 0x00000030; + private const uint enum_flag_GenericsMask_NonGeneric = 0x00000000; // no instantiation + private const uint enum_flag_GenericsMask_GenericInst = 0x00000010; // regular instantiation, e.g. List + private const uint enum_flag_GenericsMask_SharedInst = 0x00000020; // shared instantiation, e.g. List<__Canon> or List> + private const uint enum_flag_GenericsMask_TypicalInst = 0x00000030; // the type instantiated at its formal parameters, e.g. List private const uint enum_flag_HasDefaultCtor = 0x00000200; // WFLAGS_HIGH_ENUM private const uint enum_flag_ContainsPointers = 0x01000000; private const uint enum_flag_HasComponentSize = 0x80000000; private const uint enum_flag_HasTypeEquivalence = 0x02000000; + private const uint enum_flag_Category_Mask = 0x000F0000; private const uint enum_flag_Category_ValueType = 0x00040000; + private const uint enum_flag_Category_Nullable = 0x00050000; private const uint enum_flag_Category_ValueType_Mask = 0x000C0000; // Types that require non-trivial interface cast have this bit set in the category private const uint enum_flag_NonTrivialInterfaceCast = 0x00080000 // enum_flag_Category_Array @@ -531,45 +538,15 @@ internal unsafe struct MethodTable private const int InterfaceMapOffset = 0x24 + DebugClassNamePtr; #endif - public bool HasComponentSize - { - get - { - return (Flags & enum_flag_HasComponentSize) != 0; - } - } + public bool HasComponentSize => (Flags & enum_flag_HasComponentSize) != 0; - public bool ContainsGCPointers - { - get - { - return (Flags & enum_flag_ContainsPointers) != 0; - } - } + public bool ContainsGCPointers => (Flags & enum_flag_ContainsPointers) != 0; - public bool NonTrivialInterfaceCast - { - get - { - return (Flags & enum_flag_NonTrivialInterfaceCast) != 0; - } - } + public bool NonTrivialInterfaceCast => (Flags & enum_flag_NonTrivialInterfaceCast) != 0; - public bool HasTypeEquivalence - { - get - { - return (Flags & enum_flag_HasTypeEquivalence) != 0; - } - } + public bool HasTypeEquivalence => (Flags & enum_flag_HasTypeEquivalence) != 0; - public bool HasDefaultConstructor - { - get - { - return ((HasComponentSize ? 0 : Flags) & enum_flag_HasDefaultCtor) != 0; - } - } + public bool HasDefaultConstructor => (Flags & (enum_flag_HasComponentSize | enum_flag_HasDefaultCtor)) == enum_flag_HasDefaultCtor; public bool IsMultiDimensionalArray { @@ -594,11 +571,20 @@ public int MultiDimensionalArrayRank } } - public bool IsValueType + public bool IsValueType => (Flags & enum_flag_Category_ValueType_Mask) == enum_flag_Category_ValueType; + + public bool IsNullable => (Flags & enum_flag_Category_Mask) == enum_flag_Category_Nullable; + + public bool HasInstantiation => (Flags & enum_flag_HasComponentSize) == 0 && (Flags & enum_flag_GenericsMask) != enum_flag_GenericsMask_NonGeneric; + + public bool IsGenericTypeDefinition => (Flags & (enum_flag_HasComponentSize | enum_flag_GenericsMask)) == enum_flag_GenericsMask_TypicalInst; + + public bool IsConstructedGenericType { get { - return (Flags & enum_flag_Category_ValueType_Mask) == enum_flag_Category_ValueType; + uint genericsFlags = Flags & (enum_flag_HasComponentSize | enum_flag_GenericsMask); + return genericsFlags == enum_flag_GenericsMask_GenericInst || genericsFlags == enum_flag_GenericsMask_SharedInst; } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 1959209bd7cc41..49d8e935d70102 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -124,7 +124,7 @@ internal static bool IsTypeDefinition(RuntimeType type) corElemType == CorElementType.ELEMENT_TYPE_OBJECT)) return false; - if (HasInstantiation(type) && !IsGenericTypeDefinition(type)) + if (type.IsConstructedGenericType) return false; return true; @@ -681,27 +681,8 @@ internal RuntimeType MakePointer() [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_IsCollectible")] internal static partial Interop.BOOL IsCollectible(QCallTypeHandle handle); - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool HasInstantiation(RuntimeType type); - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetGenericTypeDefinition")] - private static partial void GetGenericTypeDefinition(QCallTypeHandle type, ObjectHandleOnStack retType); - - internal static RuntimeType GetGenericTypeDefinition(RuntimeType type) - { - RuntimeType retType = type; - - if (HasInstantiation(retType) && !IsGenericTypeDefinition(retType)) - { - RuntimeTypeHandle nativeHandle = retType.TypeHandle; - GetGenericTypeDefinition(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref retType)); - } - - return retType; - } - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool IsGenericTypeDefinition(RuntimeType type); + internal static partial void GetGenericTypeDefinition(QCallTypeHandle type, ObjectHandleOnStack retType); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool IsGenericVariable(RuntimeType type); diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index fdfc88b419e4a0..5cc504d22b4b4c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -913,7 +913,7 @@ private unsafe void PopulateRtFields(Filter filter, Debug.Assert(declaringType != null); Debug.Assert(ReflectedType != null); - bool needsStaticFieldForGeneric = RuntimeTypeHandle.HasInstantiation(declaringType) && !RuntimeTypeHandle.ContainsGenericVariables(declaringType); + bool needsStaticFieldForGeneric = declaringType.IsGenericType && !RuntimeTypeHandle.ContainsGenericVariables(declaringType); bool isInherited = declaringType != ReflectedType; for (int i = 0; i < count; i++) @@ -1478,7 +1478,6 @@ internal T[] GetMemberList(MemberListType listType, string? name, CacheType cach private string? m_namespace; private readonly bool m_isGlobal; private bool m_bIsDomainInitialized; - private bool m_isNullableOfT; private MemberInfoCache? m_methodInfoCache; private MemberInfoCache? m_constructorInfoCache; private MemberInfoCache? m_fieldInfoCache; @@ -1489,8 +1488,13 @@ internal T[] GetMemberList(MemberListType listType, string? name, CacheType cach private static CerHashtable s_methodInstantiations; private static object? s_methodInstantiationsLock; private string? m_defaultMemberName; - private object? m_genericCache; // Generic cache for rare scenario specific data. It is used to cache Enum names and values. + // Generic cache for rare scenario specific data. Used for: + // - Enum names and values (EnumInfo) + // - Activator.CreateInstance (ActivatorCache) + // - Array.Initialize (ArrayInitializeCache) + private object? m_genericCache; private object[]? _emptyArray; // Object array cache for Attribute.GetCustomAttributes() pathological no-result case. + private RuntimeType? _genericTypeDefinition; #endregion #region Constructor @@ -1499,7 +1503,6 @@ internal RuntimeTypeCache(RuntimeType runtimeType) m_typeCode = TypeCode.Empty; m_runtimeType = runtimeType; m_isGlobal = RuntimeTypeHandle.GetModule(runtimeType).RuntimeType == runtimeType; - m_isNullableOfT = Nullable.GetUnderlyingType(runtimeType) != null; } #endregion @@ -1613,8 +1616,6 @@ internal TypeCode TypeCode internal bool IsGlobal => m_isGlobal; - internal bool IsNullableOfT => m_isNullableOfT; - internal void InvalidateCachedNestedType() => m_nestedClassesCache = null; internal string? GetDefaultMemberName() @@ -1647,6 +1648,29 @@ internal TypeCode TypeCode } internal object[] GetEmptyArray() => _emptyArray ??= (object[])Array.CreateInstance(m_runtimeType, 0); + + internal RuntimeType GetGenericTypeDefinition() + { + Debug.Assert(m_runtimeType.IsGenericType); + + return _genericTypeDefinition ?? CacheGenericDefinition(); + + [MethodImpl(MethodImplOptions.NoInlining)] + RuntimeType CacheGenericDefinition() + { + RuntimeType genericDefinition = null!; + if (m_runtimeType.IsGenericTypeDefinition) + { + genericDefinition = m_runtimeType; + } + else + { + RuntimeType type = m_runtimeType; + RuntimeTypeHandle.GetGenericTypeDefinition(new QCallTypeHandle(ref type), ObjectHandleOnStack.Create(ref genericDefinition)); + } + return _genericTypeDefinition = genericDefinition; + } + } #endregion #region Caches Accessors @@ -3417,6 +3441,50 @@ internal unsafe bool IsDelegate() return isDelegate; } + public override unsafe bool IsConstructedGenericType + { + get + { + TypeHandle th = GetNativeTypeHandle(); + + bool isConstructedGenericType = !th.IsTypeDesc && th.AsMethodTable()->IsConstructedGenericType; + GC.KeepAlive(this); + return isConstructedGenericType; + } + } + + public override unsafe bool IsGenericType + { + get + { + TypeHandle th = GetNativeTypeHandle(); + + bool isGenericType = !th.IsTypeDesc && th.AsMethodTable()->HasInstantiation; + GC.KeepAlive(this); + return isGenericType; + } + } + + public override unsafe bool IsGenericTypeDefinition + { + get + { + TypeHandle th = GetNativeTypeHandle(); + + bool isGenericTypeDefinition = !th.IsTypeDesc && th.AsMethodTable()->IsGenericTypeDefinition; + GC.KeepAlive(this); + return isGenericTypeDefinition; + } + } + + public override Type GetGenericTypeDefinition() + { + if (!IsGenericType) + throw new InvalidOperationException(SR.InvalidOperation_NotGenericType); + + return Cache.GetGenericTypeDefinition(); + } + public override GenericParameterAttributes GenericParameterAttributes { get @@ -3552,7 +3620,17 @@ public override Type[] GetGenericParameterConstraints() #endregion #region Misc - internal bool IsNullableOfT => Cache.IsNullableOfT; + internal unsafe bool IsNullableOfT + { + get + { + TypeHandle th = GetNativeTypeHandle(); + + bool isNullable = !th.IsTypeDesc && th.AsMethodTable()->IsNullable; + GC.KeepAlive(this); + return isNullable; + } + } public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) => HasSameMetadataDefinitionAsCore(other); diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index f31e5256b6955c..9015de9e8a90ad 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -160,10 +160,8 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("IsInterface", RuntimeTypeHandle::IsInterface) FCFuncElement("IsByRefLike", RuntimeTypeHandle::IsByRefLike) FCFuncElement("CanCastTo", RuntimeTypeHandle::CanCastTo) - FCFuncElement("HasInstantiation", RuntimeTypeHandle::HasInstantiation) FCFuncElement("GetGenericVariableIndex", RuntimeTypeHandle::GetGenericVariableIndex) FCFuncElement("IsGenericVariable", RuntimeTypeHandle::IsGenericVariable) - FCFuncElement("IsGenericTypeDefinition", RuntimeTypeHandle::IsGenericTypeDefinition) FCFuncElement("ContainsGenericVariables", RuntimeTypeHandle::ContainsGenericVariables) FCFuncElement("SatisfiesConstraints", RuntimeTypeHandle::SatisfiesConstraints) #ifdef FEATURE_COMINTEROP diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 239b7ee0060342..0cbfa4835f0343 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1527,32 +1527,6 @@ FCIMPL2(FC_BOOL_RET, RuntimeTypeHandle::CompareCanonicalHandles, ReflectClassBas } FCIMPLEND -FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::HasInstantiation, PTR_ReflectClassBaseObject pTypeUNSAFE) -{ - FCALL_CONTRACT; - - REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - - if (refType == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - FC_RETURN_BOOL(refType->GetType().HasInstantiation()); -} -FCIMPLEND - -FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::IsGenericTypeDefinition, PTR_ReflectClassBaseObject pTypeUNSAFE) -{ - FCALL_CONTRACT; - - REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - - if (refType == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - FC_RETURN_BOOL(refType->GetType().IsGenericTypeDefinition()); -} -FCIMPLEND - FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::IsGenericVariable, PTR_ReflectClassBaseObject pTypeUNSAFE) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index 10c2b022acb5ad..2db8a56288fc37 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -143,12 +143,6 @@ class RuntimeTypeHandle { static FCDECL6(FC_BOOL_RET, SatisfiesConstraints, PTR_ReflectClassBaseObject pGenericParameter, TypeHandle *typeContextArgs, INT32 typeContextCount, TypeHandle *methodContextArgs, INT32 methodContextCount, PTR_ReflectClassBaseObject pGenericArgument); - static - FCDECL1(FC_BOOL_RET, HasInstantiation, PTR_ReflectClassBaseObject pType); - - static - FCDECL1(FC_BOOL_RET, IsGenericTypeDefinition, PTR_ReflectClassBaseObject pType); - static FCDECL1(FC_BOOL_RET, IsGenericVariable, PTR_ReflectClassBaseObject pType); diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 7472df80e998e7..8dcc2d7bced379 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -15,9 +15,6 @@ internal sealed partial class RuntimeType : TypeInfo, ICloneable public override Assembly Assembly => RuntimeTypeHandle.GetAssembly(this); public override Type? BaseType => GetBaseType(); public override bool IsByRefLike => RuntimeTypeHandle.IsByRefLike(this); - public override bool IsConstructedGenericType => IsGenericType && !IsGenericTypeDefinition; - public override bool IsGenericType => RuntimeTypeHandle.HasInstantiation(this); - public override bool IsGenericTypeDefinition => RuntimeTypeHandle.IsGenericTypeDefinition(this); public override bool IsGenericParameter => RuntimeTypeHandle.IsGenericVariable(this); public override bool IsTypeDefinition => RuntimeTypeHandle.IsTypeDefinition(this); public override bool IsSecurityCritical => true; @@ -248,14 +245,6 @@ public override Type GetEnumUnderlyingType() return Enum.InternalGetUnderlyingType(this); } - public override Type GetGenericTypeDefinition() - { - if (!IsGenericType) - throw new InvalidOperationException(SR.InvalidOperation_NotGenericType); - - return RuntimeTypeHandle.GetGenericTypeDefinition(this); - } - public override int GetHashCode() => RuntimeHelpers.GetHashCode(this); internal RuntimeModule GetRuntimeModule() => RuntimeTypeHandle.GetModule(this); diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index cbedc793bb2e7e..ed82746525fdb2 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -1279,6 +1279,18 @@ protected override bool IsValueTypeImpl() // Returns true for actual enum types only. internal bool IsActualEnum => !IsGenericParameter && RuntimeTypeHandle.GetBaseType(this) == EnumType; + public override bool IsConstructedGenericType => IsGenericType && !IsGenericTypeDefinition; + public override bool IsGenericType => RuntimeTypeHandle.HasInstantiation(this); + public override bool IsGenericTypeDefinition => RuntimeTypeHandle.IsGenericTypeDefinition(this); + + public override Type GetGenericTypeDefinition() + { + if (!IsGenericType) + throw new InvalidOperationException(SR.InvalidOperation_NotGenericType); + + return RuntimeTypeHandle.GetGenericTypeDefinition(this); + } + public override GenericParameterAttributes GenericParameterAttributes { get