From 7d196a32661b98fc37c72b26ad51c232f673320c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 00:21:43 +0000 Subject: [PATCH 01/43] Remove verifier element type API and rename primitive-value-type category to enum Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/5e928e4d-026c-49f8-a093-001b6bf1d69c Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../RuntimeHelpers.CoreCLR.cs | 4 +- src/coreclr/vm/arraynative.cpp | 2 +- src/coreclr/vm/callingconvention.h | 2 +- src/coreclr/vm/class.cpp | 2 +- src/coreclr/vm/comdelegate.cpp | 2 +- src/coreclr/vm/customattribute.cpp | 2 +- src/coreclr/vm/invokeutil.cpp | 4 +- src/coreclr/vm/jitinterface.cpp | 12 ++-- src/coreclr/vm/marshalnative.cpp | 2 +- src/coreclr/vm/methodtable.cpp | 55 ++----------------- src/coreclr/vm/methodtable.h | 16 ++---- src/coreclr/vm/proftoeeinterfaceimpl.cpp | 2 +- src/coreclr/vm/reflectioninvocation.cpp | 2 +- src/coreclr/vm/typedesc.cpp | 4 +- src/coreclr/vm/typehandle.cpp | 20 +------ src/coreclr/vm/typehandle.h | 17 +----- 16 files changed, 35 insertions(+), 113 deletions(-) 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 935ae133272fe7..d6655cad15be91 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 @@ -850,7 +850,7 @@ internal unsafe struct MethodTable private const uint enum_flag_Category_ValueType = 0x00040000; private const uint enum_flag_Category_Nullable = 0x00050000; private const uint enum_flag_Category_IsPrimitiveMask = 0x000E0000; - private const uint enum_flag_Category_PrimitiveValueType = 0x00060000; // sub-category of ValueType, Enum or primitive value type + private const uint enum_flag_Category_Enum = 0x00060000; // sub-category of ValueType, Enum private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) private const uint enum_flag_Category_Array = 0x00080000; private const uint enum_flag_Category_Array_Mask = 0x000C0000; @@ -955,7 +955,7 @@ public int MultiDimensionalArrayRank public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike; // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. - public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_PrimitiveValueType; + public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Enum; public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_TruePrimitive; diff --git a/src/coreclr/vm/arraynative.cpp b/src/coreclr/vm/arraynative.cpp index c076c42ffa02c7..be42a36c0b764d 100644 --- a/src/coreclr/vm/arraynative.cpp +++ b/src/coreclr/vm/arraynative.cpp @@ -24,7 +24,7 @@ FCIMPL1(INT32, ArrayNative::GetCorElementTypeOfElementType, ArrayBase* arrayUNSA _ASSERTE(arrayUNSAFE != NULL); - return arrayUNSAFE->GetArrayElementTypeHandle().GetVerifierCorElementType(); + return arrayUNSAFE->GetArrayElementTypeHandle().GetInternalCorElementType(); } FCIMPLEND diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 746464ca77f2c0..e618e9e432ca28 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -2435,7 +2435,7 @@ inline BOOL HasRetBuffArgUnmanagedFixup(MetaSig * pSig) { WRAPPER_NO_CONTRACT; // We cannot just pSig->GetReturnType() here since it will return ELEMENT_TYPE_VALUETYPE for enums - CorElementType type = pSig->GetRetTypeHandleThrowing().GetVerifierCorElementType(); + CorElementType type = pSig->GetRetTypeHandleThrowing().GetInternalCorElementType(); return type == ELEMENT_TYPE_VALUETYPE; } #endif diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 1a37e2346b0dbe..d5cbd54c028dc4 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1318,7 +1318,7 @@ void ClassLoader::LoadExactParents(MethodTable* pMT) /*static*/ CorElementType ClassLoader::GetReducedTypeElementType(TypeHandle hType) { - CorElementType elemType = hType.GetVerifierCorElementType(); + CorElementType elemType = hType.GetInternalCorElementType(); switch (elemType) { case ELEMENT_TYPE_U1: diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index a4eb59dd72f4a0..24d4bf7140fb95 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2511,7 +2511,7 @@ static bool IsLocationAssignable(TypeHandle fromHandle, TypeHandle toHandle, boo else { // they are not compatible yet enums can go into each other if their underlying element type is the same - if (toHandle.GetVerifierCorElementType() == fromHandle.GetVerifierCorElementType() + if (toHandle.GetInternalCorElementType() == fromHandle.GetInternalCorElementType() && (toHandle.IsEnum() || fromHandle.IsEnum())) return true; diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index caf204b84cee19..59c3d87f73b3d2 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -52,7 +52,7 @@ static HRESULT ParseCaType( if (!th.IsNull() && th.IsEnum()) { - pCaType->enumType = (CorSerializationType)th.GetVerifierCorElementType(); + pCaType->enumType = (CorSerializationType)th.GetInternalCorElementType(); // The assembly qualified name of th might not equal pCaType->szEnumName. // e.g. th could be "MyEnum, MyAssembly, Version=4.0.0.0" while diff --git a/src/coreclr/vm/invokeutil.cpp b/src/coreclr/vm/invokeutil.cpp index ea289619bcf902..49186d28afc058 100644 --- a/src/coreclr/vm/invokeutil.cpp +++ b/src/coreclr/vm/invokeutil.cpp @@ -135,7 +135,7 @@ void InvokeUtil::CopyArg(TypeHandle th, PVOID argRef, ArgDestination *argDest) { CONTRACTL_END; void *pArgDst = argDest->GetDestinationAddress(); - CorElementType type = th.GetVerifierCorElementType(); + CorElementType type = th.GetInternalCorElementType(); switch (type) { #ifdef TARGET_RISCV64 @@ -500,7 +500,7 @@ void InvokeUtil::ValidField(TypeHandle th, OBJECTREF* value) if (th.IsEnum()) COMPlusThrow(kArgumentException,W("Arg_ObjObj")); - type = th.GetVerifierCorElementType(); + type = th.GetInternalCorElementType(); if (IsPrimitiveType(type)) { if (CanPrimitiveWiden(type, oType)) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index cb30fa87c3aaec..d313373bcfbec1 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -4067,7 +4067,7 @@ CorInfoType CEEInfo::getTypeForPrimitiveValueClass( TypeHandle th(clsHnd); _ASSERTE (!th.IsGenericVariable()); - CorElementType elementType = th.GetVerifierCorElementType(); + CorElementType elementType = th.GetInternalCorElementType(); if (CorIsPrimitiveType(elementType)) { result = asCorInfoType(elementType); @@ -4445,7 +4445,7 @@ static bool isExactTypeHelper(TypeHandle th) th = pMT->GetArrayElementTypeHandle(); // Arrays of primitives are interchangeable with arrays of enums of the same underlying type. - if (CorTypeInfo::IsPrimitiveType(th.GetVerifierCorElementType())) + if (CorTypeInfo::IsPrimitiveType(th.GetInternalCorElementType())) return false; } @@ -5052,7 +5052,7 @@ void CEEInfo::getCallInfo( if (pMD->GetSlot() == CoreLibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot()) { // Pretend this was a "constrained. UnderlyingType" instruction prefix - constrainedType = TypeHandle(CoreLibBinder::GetElementType(constrainedType.GetVerifierCorElementType())); + constrainedType = TypeHandle(CoreLibBinder::GetElementType(constrainedType.GetInternalCorElementType())); constrainedResolvedTokenCopy = *pConstrainedResolvedToken; pConstrainedResolvedToken = &constrainedResolvedTokenCopy; @@ -7232,7 +7232,7 @@ static bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn, } else { - CorElementType elementType = typeHandle.GetVerifierCorElementType(); + CorElementType elementType = typeHandle.GetInternalCorElementType(); if (!CorTypeInfo::IsPrimitiveType(elementType) || elementType == ELEMENT_TYPE_R4 || elementType == ELEMENT_TYPE_R8) @@ -7401,7 +7401,7 @@ static bool getILIntrinsicImplementationForRuntimeHelpers( Instantiation inst = ftn->GetMethodInstantiation(); _ASSERTE(inst.GetNumArgs() == 1); - CorElementType et = inst[0].GetVerifierCorElementType(); + CorElementType et = inst[0].GetInternalCorElementType(); if (et == ELEMENT_TYPE_I4 || et == ELEMENT_TYPE_U4 || et == ELEMENT_TYPE_I2 || @@ -7430,7 +7430,7 @@ static bool getILIntrinsicImplementationForRuntimeHelpers( Instantiation inst = ftn->GetMethodInstantiation(); _ASSERTE(inst.GetNumArgs() == 1); - CorElementType et = inst[0].GetVerifierCorElementType(); + CorElementType et = inst[0].GetInternalCorElementType(); if (et == ELEMENT_TYPE_I4 || et == ELEMENT_TYPE_U4 || et == ELEMENT_TYPE_I2 || diff --git a/src/coreclr/vm/marshalnative.cpp b/src/coreclr/vm/marshalnative.cpp index b9163b700bad00..b63144baf8f916 100644 --- a/src/coreclr/vm/marshalnative.cpp +++ b/src/coreclr/vm/marshalnative.cpp @@ -110,7 +110,7 @@ extern "C" BOOL QCALLTYPE MarshalNative_HasLayout(QCall::TypeHandle t, BOOL* pIs { // Enums don't have native layout info, but they marshal identically // to their underlying primitive type. - th = CoreLibBinder::GetElementType(th.GetVerifierCorElementType()); + th = CoreLibBinder::GetElementType(th.GetInternalCorElementType()); } if (th.HasLayout()) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 5a5a714a360edf..3026707c1d2b61 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -3087,7 +3087,7 @@ namespace STANDARD_VM_CONTRACT; PTR_MethodTable fieldType = pFieldDesc->GetFieldTypeHandleThrowing().GetMethodTable(); - CorElementType corType = fieldType->GetVerifierCorElementType(); + CorElementType corType = fieldType->GetInternalCorElementType(); if (corType == ELEMENT_TYPE_VALUETYPE) { @@ -4969,9 +4969,8 @@ CorElementType MethodTable::GetInternalCorElementType() ret = ELEMENT_TYPE_VALUETYPE; break; - case enum_flag_Category_PrimitiveValueType: - // This path should only be taken for the builtin CoreLib types - // and primitive valuetypes + case enum_flag_Category_Enum: + // This path should only be taken for enums and true primitive CoreLib types. ret = GetClass()->GetInternalCorElementType(); _ASSERTE((ret != ELEMENT_TYPE_CLASS) && (ret != ELEMENT_TYPE_VALUETYPE)); @@ -4994,48 +4993,6 @@ CorElementType MethodTable::GetInternalCorElementType() return ret; } -//========================================================================================== -CorElementType MethodTable::GetVerifierCorElementType() -{ - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - - // This should not touch the EEClass, at least not in the - // common cases of ELEMENT_TYPE_CLASS and ELEMENT_TYPE_VALUETYPE. - CorElementType ret; - - switch (GetFlag(enum_flag_Category_ElementTypeMask)) - { - case enum_flag_Category_Array: - ret = ELEMENT_TYPE_ARRAY; - break; - - case enum_flag_Category_Array | enum_flag_Category_IfArrayThenSzArray: - ret = ELEMENT_TYPE_SZARRAY; - break; - - case enum_flag_Category_ValueType: - ret = ELEMENT_TYPE_VALUETYPE; - break; - - case enum_flag_Category_PrimitiveValueType: - // - // This is the only difference from MethodTable::GetInternalCorElementType() - // - if (IsTruePrimitive() || IsEnum()) - ret = GetClass()->GetInternalCorElementType(); - else - ret = ELEMENT_TYPE_VALUETYPE; - break; - - default: - ret = ELEMENT_TYPE_CLASS; - break; - } - - return ret; -} - //========================================================================================== CorElementType MethodTable::GetSignatureCorElementType() { @@ -5058,7 +5015,7 @@ CorElementType MethodTable::GetSignatureCorElementType() case enum_flag_Category_ValueType: case enum_flag_Category_Nullable: - case enum_flag_Category_PrimitiveValueType: + case enum_flag_Category_Enum: ret = ELEMENT_TYPE_VALUETYPE; break; @@ -5092,8 +5049,8 @@ void MethodTable::SetInternalCorElementType (CorElementType _NormType) _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType); break; default: - SetFlag(enum_flag_Category_PrimitiveValueType); - _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_PrimitiveValueType); + SetFlag(enum_flag_Category_Enum); + _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Enum); break; } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 402b0cde9b15bd..b5106ab3321786 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2769,28 +2769,22 @@ class MethodTable // // #KindsOfElementTypes // GetInternalCorElementType() retrieves the internal representation of the type. It's not always - // appropriate to use this. For example, we treat enums as their underlying type or some structs are - // optimized to be ints. To get the signature type or the verifier type (same as signature except for - // enums are normalized to the primitive type that underlies them), use the APIs in Typehandle.h + // appropriate to use this. For example, we treat enums as their underlying type. To get the signature + // type, use the APIs in Typehandle.h. // // * code:TypeHandle.GetSignatureCorElementType() - // * code:TypeHandle.GetVerifierCorElementType() // * code:TypeHandle.GetInternalCorElementType() CorElementType GetInternalCorElementType(); void SetInternalCorElementType(CorElementType _NormType); - // See code:TypeHandle::GetVerifierCorElementType for description - CorElementType GetVerifierCorElementType(); - // See code:TypeHandle::GetSignatureCorElementType for description CorElementType GetSignatureCorElementType(); - // A true primitive is one who's GetVerifierCorElementType() == + // A true primitive is one whose GetInternalCorElementType() == // ELEMENT_TYPE_I, // ELEMENT_TYPE_I4, // ELEMENT_TYPE_TYPEDBYREF etc. - // Note that GetIntenalCorElementType might return these same values for some additional - // types such as Enums and some structs. + // Note that GetInternalCorElementType might return these same values for enums. BOOL IsTruePrimitive(); void SetIsTruePrimitive(); @@ -3793,7 +3787,7 @@ public : enum_flag_Category_ValueType = 0x00040000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_Enum = 0x00060000, // sub-category of ValueType, Enum. [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index 8869fd4f0397a4..9a88fbfe9380ce 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -1777,7 +1777,7 @@ HRESULT ProfToEEInterfaceImpl::IsArrayClass( // Fill in the type if they want it if (pBaseElemType != NULL) { - *pBaseElemType = th.GetArrayElementTypeHandle().GetVerifierCorElementType(); + *pBaseElemType = th.GetArrayElementTypeHandle().GetInternalCorElementType(); } // If this is an array of classes and they wish to have the base type diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index 37343b4fcb9cc2..ee1ed1ac38d4f8 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -63,7 +63,7 @@ extern "C" void QCALLTYPE RuntimeFieldHandle_SetValue(FieldDesc* fieldDesc, QCal GCPROTECT_BEGIN(gc); TypeHandle fieldTypeHandle = fieldType.AsTypeHandle(); - InvokeUtil::SetValidField(fieldTypeHandle.GetVerifierCorElementType(), fieldTypeHandle, fieldDesc, &gc.target, &gc.value, declaringType.AsTypeHandle(), pIsClassInitialized); + InvokeUtil::SetValidField(fieldTypeHandle.GetInternalCorElementType(), fieldTypeHandle, fieldDesc, &gc.target, &gc.value, declaringType.AsTypeHandle(), pIsClassInitialized); GCPROTECT_END(); END_QCALL; diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index 09598f362c7452..5b5c6f807c9c2c 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -401,7 +401,7 @@ BOOL TypeDesc::CanCastParam(TypeHandle fromParam, TypeHandle toParam, TypeHandle return TRUE; // Object parameters dont need an exact match but only inheritance, check for that - CorElementType fromParamCorType = fromParam.GetVerifierCorElementType(); + CorElementType fromParamCorType = fromParam.GetInternalCorElementType(); if (CorTypeInfo::IsObjRef(fromParamCorType)) { return fromParam.CanCastTo(toParam, pVisited); @@ -420,7 +420,7 @@ BOOL TypeDesc::CanCastParam(TypeHandle fromParam, TypeHandle toParam, TypeHandle } else if(CorTypeInfo::IsPrimitiveType(fromParamCorType)) { - CorElementType toParamCorType = toParam.GetVerifierCorElementType(); + CorElementType toParamCorType = toParam.GetInternalCorElementType(); if(CorTypeInfo::IsPrimitiveType(toParamCorType)) { if (GetNormalizedIntegralArrayElementType(toParamCorType) == GetNormalizedIntegralArrayElementType(fromParamCorType)) diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index 5dd7d4e85d468a..a1ddb5fca11010 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -592,7 +592,7 @@ BOOL TypeHandle::IsBoxedAndCanCastTo(TypeHandle type, TypeHandlePairList *pPairL CONTRACTL_END - CorElementType fromParamCorType = GetVerifierCorElementType(); + CorElementType fromParamCorType = GetInternalCorElementType(); if (CorTypeInfo::IsObjRef(fromParamCorType)) { @@ -1205,24 +1205,6 @@ CorElementType TypeHandle::GetSignatureCorElementType() const } } -// As its name suggests, this returns the type used by the IL verifier. The basic difference between this -// type and the type in the meta-data is that enumerations have been normalized to their underlieing -// primitive type. see code:MethodTable#KindsOfElementTypes for more -CorElementType TypeHandle::GetVerifierCorElementType() const -{ - LIMITED_METHOD_CONTRACT; - - if (IsTypeDesc()) - { - return AsTypeDesc()->GetInternalCorElementType(); - } - else - { - return AsMethodTable()->GetVerifierCorElementType(); - } -} - - #ifdef DACCESS_COMPILE void diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index 1fb2f944bb509d..42cd1b56d30159 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -200,26 +200,15 @@ class TypeHandle // This helper: // - Will return enums underlying type // - Will return underlying primitive for System.Int32 etc... - // - Will return underlying primitive as will be used in the calling convention - // For example - // struct t - // { - // public int i; - // } - // will return ELEMENT_TYPE_I4 in x86 instead of ELEMENT_TYPE_VALUETYPE. We - // call this type of value type a primitive value type + // - Will return the primitive used by the calling convention // - // Internal representation is used among another things for the calling convention - // (jit benefits of primitive value types) or optimizing marshalling. + // Internal representation is used among other things for the calling convention + // and optimizing marshalling. // // This will NOT convert E_T_ARRAY, E_T_SZARRAY etc. to E_T_CLASS (though it probably // should). Use CorTypeInfo::IsObjRef for that. CorElementType GetInternalCorElementType() const; - // This helper will return the same as GetSignatureCorElementType except: - // - Will return enums underlying type - CorElementType GetVerifierCorElementType() const; - //------------------------------------------------------------------- // CASTING // From 0af6cad736cac34c8be2159ae8da6a5d5e1cd187 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 00:32:41 +0000 Subject: [PATCH 02/43] Rename enum category in cDAC contracts/docs and clean related comments Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/5e928e4d-026c-49f8-a093-001b6bf1d69c Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../design/datacontracts/RuntimeTypeSystem.md | 8 +++---- .../Contracts/RuntimeTypeSystem_1.cs | 6 ++--- .../MethodTableFlags_1.cs | 2 +- .../managed/cdac/tests/MethodTableTests.cs | 22 +++++++++---------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 28605efe3c70b3..4f19db53e998fe 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -294,7 +294,7 @@ internal partial struct RuntimeTypeSystem_1 Category_Array = 0x00080000, Category_ValueType = 0x00040000, Category_Nullable = 0x00050000, - Category_PrimitiveValueType = 0x00060000, + Category_Enum = 0x00060000, Category_TruePrimitive = 0x00070000, Category_Interface = 0x000C0000, Collectible = 0x00200000, @@ -813,7 +813,7 @@ Contracts used: return CorElementType.SzArray; case WFLAGS_HIGH.Category_ValueType: case WFLAGS_HIGH.Category_Nullable: - case WFLAGS_HIGH.Category_PrimitiveValueType: + case WFLAGS_HIGH.Category_Enum: return CorElementType.ValueType; case WFLAGS_HIGH.Category_TruePrimitive: return (CorElementType)GetClassData(typeHandle).InternalCorElementType; @@ -835,9 +835,9 @@ Contracts used: // if typedesc: check for CorElementType.ValueType } - // Enums have Category_PrimitiveValueType in their MethodTable flags and their + // Enums have Category_Enum in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ValueType. Regular primitive value types (IntPtr/UIntPtr) have Category_TruePrimitive. + // not ValueType. IntPtr/UIntPtr continue to use Category_TruePrimitive. public bool IsEnum(TypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 26debd447f39ec..1e67e2d9adf726 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -848,7 +848,7 @@ public CorElementType GetSignatureCorElementType(TypeHandle typeHandle) return CorElementType.SzArray; case MethodTableFlags_1.WFLAGS_HIGH.Category_ValueType: case MethodTableFlags_1.WFLAGS_HIGH.Category_Nullable: - case MethodTableFlags_1.WFLAGS_HIGH.Category_PrimitiveValueType: + case MethodTableFlags_1.WFLAGS_HIGH.Category_Enum: return CorElementType.ValueType; case MethodTableFlags_1.WFLAGS_HIGH.Category_TruePrimitive: return (CorElementType)GetClassData(typeHandle).InternalCorElementType; @@ -883,9 +883,9 @@ public bool IsValueType(TypeHandle typeHandle) public bool IsEnum(TypeHandle typeHandle) { - // Enums have Category_PrimitiveValueType in their MethodTable flags and their + // Enums have Category_Enum in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ValueType. Regular primitive value types (IntPtr/UIntPtr) have Category_TruePrimitive. + // not ValueType. IntPtr/UIntPtr continue to use Category_TruePrimitive. if (!typeHandle.IsMethodTable()) return false; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs index 466d45a4ee4975..11076a8c73a8d4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs @@ -42,7 +42,7 @@ internal enum WFLAGS_HIGH : uint Category_ElementType_Mask = 0x000E0000, Category_ValueType = 0x00040000, Category_Nullable = 0x00050000, - Category_PrimitiveValueType = 0x00060000, + Category_Enum = 0x00060000, Category_TruePrimitive = 0x00070000, Category_Interface = 0x000C0000, Collectible = 0x00200000, // GC depends on this bit. diff --git a/src/native/managed/cdac/tests/MethodTableTests.cs b/src/native/managed/cdac/tests/MethodTableTests.cs index e8c15ad11f6734..0c5f9a5d4d4c9c 100644 --- a/src/native/managed/cdac/tests/MethodTableTests.cs +++ b/src/native/managed/cdac/tests/MethodTableTests.cs @@ -516,7 +516,7 @@ public void IsValueTypeReturnsTrueForValueTypeCategories(MockTarget.Architecture { TargetPointer valueTypeMTPtr = default; TargetPointer nullableMTPtr = default; - TargetPointer primitiveValueTypeMTPtr = default; + TargetPointer enumMTPtr = default; TargetPointer truePrimitiveMTPtr = default; TestPlaceholderTarget target = CreateTarget( @@ -545,15 +545,15 @@ public void IsValueTypeReturnsTrueForValueTypeCategories(MockTarget.Architecture nullableMT.EEClassOrCanonMT = nullableEEClass.Address; nullableMTPtr = nullableMT.Address; - MockEEClass pvtEEClass = rtsBuilder.AddEEClass("PrimitiveValueTypeEEClass"); - MockMethodTable pvtMT = rtsBuilder.AddMethodTable("PrimitiveValueType"); - pvtMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_PrimitiveValueType; - pvtMT.BaseSize = rtsBuilder.Builder.TargetTestHelpers.ObjectBaseSize; - pvtMT.ParentMethodTable = systemObjectMethodTablePtr; - pvtMT.NumVirtuals = 3; - pvtEEClass.MethodTable = pvtMT.Address; - pvtMT.EEClassOrCanonMT = pvtEEClass.Address; - primitiveValueTypeMTPtr = pvtMT.Address; + MockEEClass enumEEClass = rtsBuilder.AddEEClass("EnumEEClass"); + MockMethodTable enumMT = rtsBuilder.AddMethodTable("Enum"); + enumMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_Enum; + enumMT.BaseSize = rtsBuilder.Builder.TargetTestHelpers.ObjectBaseSize; + enumMT.ParentMethodTable = systemObjectMethodTablePtr; + enumMT.NumVirtuals = 3; + enumEEClass.MethodTable = enumMT.Address; + enumMT.EEClassOrCanonMT = enumEEClass.Address; + enumMTPtr = enumMT.Address; MockEEClass tpEEClass = rtsBuilder.AddEEClass("TruePrimitiveEEClass"); MockMethodTable tpMT = rtsBuilder.AddMethodTable("TruePrimitive"); @@ -570,7 +570,7 @@ public void IsValueTypeReturnsTrueForValueTypeCategories(MockTarget.Architecture Assert.True(contract.IsValueType(contract.GetTypeHandle(valueTypeMTPtr))); Assert.True(contract.IsValueType(contract.GetTypeHandle(nullableMTPtr))); - Assert.True(contract.IsValueType(contract.GetTypeHandle(primitiveValueTypeMTPtr))); + Assert.True(contract.IsValueType(contract.GetTypeHandle(enumMTPtr))); Assert.True(contract.IsValueType(contract.GetTypeHandle(truePrimitiveMTPtr))); } From fbca1de222d63e76ad5a7e630e3e77b0ddcedae5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 01:35:44 +0000 Subject: [PATCH 03/43] Address review feedback on enum/primitive category values and comments Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/a5ef9c79-9897-4019-af57-7543f1af7c54 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- docs/design/datacontracts/RuntimeTypeSystem.md | 8 ++++---- .../Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 10 ++++++---- src/coreclr/vm/methodtable.cpp | 4 ++-- src/coreclr/vm/methodtable.h | 4 ++-- src/coreclr/vm/methodtable.inl | 5 +++-- .../Contracts/RuntimeTypeSystem_1.cs | 4 ++-- .../RuntimeTypeSystemHelpers/MethodTableFlags_1.cs | 4 ++-- src/native/managed/cdac/tests/MethodTableTests.cs | 2 +- 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 4f19db53e998fe..4935017c7a1b17 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -294,8 +294,8 @@ internal partial struct RuntimeTypeSystem_1 Category_Array = 0x00080000, Category_ValueType = 0x00040000, Category_Nullable = 0x00050000, - Category_Enum = 0x00060000, - Category_TruePrimitive = 0x00070000, + Category_Primitive = 0x00060000, + Category_Enum = 0x00070000, Category_Interface = 0x000C0000, Collectible = 0x00200000, RequiresAlign8 = 0x00800000, @@ -815,7 +815,7 @@ Contracts used: case WFLAGS_HIGH.Category_Nullable: case WFLAGS_HIGH.Category_Enum: return CorElementType.ValueType; - case WFLAGS_HIGH.Category_TruePrimitive: + case WFLAGS_HIGH.Category_Primitive: return (CorElementType)GetClassData(typeHandle).InternalCorElementType; default: return CorElementType.Class; @@ -837,7 +837,7 @@ Contracts used: // Enums have Category_Enum in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ValueType. IntPtr/UIntPtr continue to use Category_TruePrimitive. + // not ValueType. public bool IsEnum(TypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) 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 d6655cad15be91..a86253dd0eaf13 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 @@ -850,8 +850,8 @@ internal unsafe struct MethodTable private const uint enum_flag_Category_ValueType = 0x00040000; private const uint enum_flag_Category_Nullable = 0x00050000; private const uint enum_flag_Category_IsPrimitiveMask = 0x000E0000; - private const uint enum_flag_Category_Enum = 0x00060000; // sub-category of ValueType, Enum - private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) + private const uint enum_flag_Category_Primitive = 0x00060000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) + private const uint enum_flag_Category_Enum = 0x00070000; // sub-category of ValueType, Enum private const uint enum_flag_Category_Array = 0x00080000; private const uint enum_flag_Category_Array_Mask = 0x000C0000; private const uint enum_flag_Category_ValueType_Mask = 0x000C0000; @@ -955,9 +955,11 @@ public int MultiDimensionalArrayRank public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike; // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. - public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Enum; + public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive; - public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_TruePrimitive; + public bool IsTruePrimitive => + (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive && + (Flags & enum_flag_Category_Mask) != enum_flag_Category_Enum; public bool IsArray => (Flags & enum_flag_Category_Array_Mask) == enum_flag_Category_Array; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 3026707c1d2b61..d3058add99c2e1 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4969,7 +4969,7 @@ CorElementType MethodTable::GetInternalCorElementType() ret = ELEMENT_TYPE_VALUETYPE; break; - case enum_flag_Category_Enum: + case enum_flag_Category_Primitive: // This path should only be taken for enums and true primitive CoreLib types. ret = GetClass()->GetInternalCorElementType(); _ASSERTE((ret != ELEMENT_TYPE_CLASS) && @@ -5019,7 +5019,7 @@ CorElementType MethodTable::GetSignatureCorElementType() ret = ELEMENT_TYPE_VALUETYPE; break; - case enum_flag_Category_TruePrimitive: + case enum_flag_Category_Primitive: ret = GetClass()->GetInternalCorElementType(); break; diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index b5106ab3321786..a4ff1a900cd74d 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3787,8 +3787,8 @@ public : enum_flag_Category_ValueType = 0x00040000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_Enum = 0x00060000, // sub-category of ValueType, Enum. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_Primitive = 0x00060000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_Enum = 0x00070000, // sub-category of ValueType, Enum. [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array_Mask = 0x000C0000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index d0b112d01d7526..9f4b41090319f1 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -327,14 +327,15 @@ inline DWORD MethodTable::GetRank() inline BOOL MethodTable::IsTruePrimitive() { LIMITED_METHOD_DAC_CONTRACT; - return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_TruePrimitive; + return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Primitive; } //========================================================================================== inline void MethodTable::SetIsTruePrimitive() { LIMITED_METHOD_DAC_CONTRACT; - SetFlag(enum_flag_Category_TruePrimitive); + ClearFlag(enum_flag_Category_Mask); + SetFlag(enum_flag_Category_Primitive); } //========================================================================================== diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 1e67e2d9adf726..cb56858942dffa 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -850,7 +850,7 @@ public CorElementType GetSignatureCorElementType(TypeHandle typeHandle) case MethodTableFlags_1.WFLAGS_HIGH.Category_Nullable: case MethodTableFlags_1.WFLAGS_HIGH.Category_Enum: return CorElementType.ValueType; - case MethodTableFlags_1.WFLAGS_HIGH.Category_TruePrimitive: + case MethodTableFlags_1.WFLAGS_HIGH.Category_Primitive: return (CorElementType)GetClassData(typeHandle).InternalCorElementType; default: return CorElementType.Class; @@ -885,7 +885,7 @@ public bool IsEnum(TypeHandle typeHandle) { // Enums have Category_Enum in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ValueType. IntPtr/UIntPtr continue to use Category_TruePrimitive. + // not ValueType. if (!typeHandle.IsMethodTable()) return false; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs index 11076a8c73a8d4..56975c1df16073 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs @@ -42,8 +42,8 @@ internal enum WFLAGS_HIGH : uint Category_ElementType_Mask = 0x000E0000, Category_ValueType = 0x00040000, Category_Nullable = 0x00050000, - Category_Enum = 0x00060000, - Category_TruePrimitive = 0x00070000, + Category_Primitive = 0x00060000, + Category_Enum = 0x00070000, Category_Interface = 0x000C0000, Collectible = 0x00200000, // GC depends on this bit. RequiresAlign8 = 0x00800000, diff --git a/src/native/managed/cdac/tests/MethodTableTests.cs b/src/native/managed/cdac/tests/MethodTableTests.cs index 0c5f9a5d4d4c9c..08a2f7542d3ac0 100644 --- a/src/native/managed/cdac/tests/MethodTableTests.cs +++ b/src/native/managed/cdac/tests/MethodTableTests.cs @@ -557,7 +557,7 @@ public void IsValueTypeReturnsTrueForValueTypeCategories(MockTarget.Architecture MockEEClass tpEEClass = rtsBuilder.AddEEClass("TruePrimitiveEEClass"); MockMethodTable tpMT = rtsBuilder.AddMethodTable("TruePrimitive"); - tpMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_TruePrimitive; + tpMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_Primitive; tpMT.BaseSize = rtsBuilder.Builder.TargetTestHelpers.ObjectBaseSize; tpMT.ParentMethodTable = systemObjectMethodTablePtr; tpMT.NumVirtuals = 3; From 2bdd2da43e19f99050deda423ef2a396ec6f6df4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 01:43:54 +0000 Subject: [PATCH 04/43] Refine RuntimeHelpers primitive checks after review tool feedback Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/a5ef9c79-9897-4019-af57-7543f1af7c54 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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 a86253dd0eaf13..9124a55a5f223b 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 @@ -849,7 +849,6 @@ internal unsafe struct MethodTable 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_IsPrimitiveMask = 0x000E0000; private const uint enum_flag_Category_Primitive = 0x00060000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) private const uint enum_flag_Category_Enum = 0x00070000; // sub-category of ValueType, Enum private const uint enum_flag_Category_Array = 0x00080000; @@ -955,11 +954,9 @@ public int MultiDimensionalArrayRank public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike; // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. - public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive; + public bool IsPrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_Primitive or enum_flag_Category_Enum; - public bool IsTruePrimitive => - (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive && - (Flags & enum_flag_Category_Mask) != enum_flag_Category_Enum; + public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_Primitive; public bool IsArray => (Flags & enum_flag_Category_Array_Mask) == enum_flag_Category_Array; From 4a179b36b8fc7d9ddbae325a15058da683420521 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 01:46:08 +0000 Subject: [PATCH 05/43] Clarify primitive/enum mask behavior comment in MethodTable Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/a5ef9c79-9897-4019-af57-7543f1af7c54 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/methodtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index d3058add99c2e1..35b287b995a8c0 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4970,7 +4970,7 @@ CorElementType MethodTable::GetInternalCorElementType() break; case enum_flag_Category_Primitive: - // This path should only be taken for enums and true primitive CoreLib types. + // enum_flag_Category_ElementTypeMask maps both Category_Primitive and Category_Enum here. ret = GetClass()->GetInternalCorElementType(); _ASSERTE((ret != ELEMENT_TYPE_CLASS) && (ret != ELEMENT_TYPE_VALUETYPE)); From 53d2152c6addbdee2441137c0b69b3986c2558e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 02:55:09 +0000 Subject: [PATCH 06/43] Apply latest enum/primitive review suggestions across runtime and cDAC Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/4ef6b0df-8fc1-41d6-afe1-1119ff0f3c32 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- docs/design/datacontracts/RuntimeTypeSystem.md | 8 ++------ .../Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 7 +++++-- src/coreclr/vm/methodtable.h | 4 ++-- src/coreclr/vm/methodtable.inl | 3 +-- src/coreclr/vm/typehandle.h | 3 --- .../Contracts/RuntimeTypeSystem_1.cs | 8 ++------ 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 4935017c7a1b17..8a29098adfca42 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -843,12 +843,8 @@ Contracts used: if (!typeHandle.IsMethodTable()) return false; - CorElementType sigType = GetSignatureCorElementType(typeHandle); - if (sigType != CorElementType.ValueType) - return false; - - CorElementType internalType = (CorElementType)GetClassData(typeHandle).InternalCorElementType; - return internalType != CorElementType.ValueType; + MethodTable methodTable = _methodTables[typeHandle.Address]; + return methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) == WFLAGS_HIGH.Category_Enum; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. 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 9124a55a5f223b..a86253dd0eaf13 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 @@ -849,6 +849,7 @@ internal unsafe struct MethodTable 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_IsPrimitiveMask = 0x000E0000; private const uint enum_flag_Category_Primitive = 0x00060000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) private const uint enum_flag_Category_Enum = 0x00070000; // sub-category of ValueType, Enum private const uint enum_flag_Category_Array = 0x00080000; @@ -954,9 +955,11 @@ public int MultiDimensionalArrayRank public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike; // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. - public bool IsPrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_Primitive or enum_flag_Category_Enum; + public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive; - public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_Primitive; + public bool IsTruePrimitive => + (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive && + (Flags & enum_flag_Category_Mask) != enum_flag_Category_Enum; public bool IsArray => (Flags & enum_flag_Category_Array_Mask) == enum_flag_Category_Array; diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index a4ff1a900cd74d..37507bf3c0159c 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2769,7 +2769,7 @@ class MethodTable // // #KindsOfElementTypes // GetInternalCorElementType() retrieves the internal representation of the type. It's not always - // appropriate to use this. For example, we treat enums as their underlying type. To get the signature + // appropriate to use this. It treats enums as their underlying type. To get the signature // type, use the APIs in Typehandle.h. // // * code:TypeHandle.GetSignatureCorElementType() @@ -2784,7 +2784,7 @@ class MethodTable // ELEMENT_TYPE_I, // ELEMENT_TYPE_I4, // ELEMENT_TYPE_TYPEDBYREF etc. - // Note that GetInternalCorElementType might return these same values for enums. + // And not enum. BOOL IsTruePrimitive(); void SetIsTruePrimitive(); diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 9f4b41090319f1..6d203304eb7915 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -334,8 +334,7 @@ inline BOOL MethodTable::IsTruePrimitive() inline void MethodTable::SetIsTruePrimitive() { LIMITED_METHOD_DAC_CONTRACT; - ClearFlag(enum_flag_Category_Mask); - SetFlag(enum_flag_Category_Primitive); + m_dwFlags = (m_dwFlags & ~(DWORD)enum_flag_Category_Mask) | (DWORD)enum_flag_Category_Primitive; } //========================================================================================== diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index 42cd1b56d30159..a8617851bc87bd 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -202,9 +202,6 @@ class TypeHandle // - Will return underlying primitive for System.Int32 etc... // - Will return the primitive used by the calling convention // - // Internal representation is used among other things for the calling convention - // and optimizing marshalling. - // // This will NOT convert E_T_ARRAY, E_T_SZARRAY etc. to E_T_CLASS (though it probably // should). Use CorTypeInfo::IsObjRef for that. CorElementType GetInternalCorElementType() const; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index cb56858942dffa..41408991c2b95b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -889,12 +889,8 @@ public bool IsEnum(TypeHandle typeHandle) if (!typeHandle.IsMethodTable()) return false; - CorElementType sigType = GetSignatureCorElementType(typeHandle); - if (sigType != CorElementType.ValueType) - return false; - - CorElementType internalType = (CorElementType)GetClassData(typeHandle).InternalCorElementType; - return internalType != CorElementType.ValueType; + MethodTable methodTable = _methodTables[typeHandle.Address]; + return methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) == MethodTableFlags_1.WFLAGS_HIGH.Category_Enum; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. From 6ce3aae1e0a266ae74fccf2a1ed46d94c0755524 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 03:00:37 +0000 Subject: [PATCH 07/43] Clarify IsTruePrimitive comment wording in MethodTable Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/4ef6b0df-8fc1-41d6-afe1-1119ff0f3c32 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/methodtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 37507bf3c0159c..74441d230b584b 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2784,7 +2784,7 @@ class MethodTable // ELEMENT_TYPE_I, // ELEMENT_TYPE_I4, // ELEMENT_TYPE_TYPEDBYREF etc. - // And not enum. + // Note that IsTruePrimitive returns false for enum types. BOOL IsTruePrimitive(); void SetIsTruePrimitive(); From 4ec08184818f5591aa52fb8c81a99cc3e7bfdc7f Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 20:03:26 -0700 Subject: [PATCH 08/43] Update src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs --- .../System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 a86253dd0eaf13..078150b541b153 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 @@ -957,9 +957,7 @@ public int MultiDimensionalArrayRank // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive; - public bool IsTruePrimitive => - (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive && - (Flags & enum_flag_Category_Mask) != enum_flag_Category_Enum; + public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) == enum_flag_Category_Primitive; public bool IsArray => (Flags & enum_flag_Category_Array_Mask) == enum_flag_Category_Array; From f3b82386881e614840c3437081d1744ce73eba1e Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 20:31:13 -0700 Subject: [PATCH 09/43] Update src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs --- .../System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 078150b541b153..06ecbe9bf62ec2 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 @@ -851,7 +851,7 @@ internal unsafe struct MethodTable private const uint enum_flag_Category_Nullable = 0x00050000; private const uint enum_flag_Category_IsPrimitiveMask = 0x000E0000; private const uint enum_flag_Category_Primitive = 0x00060000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) - private const uint enum_flag_Category_Enum = 0x00070000; // sub-category of ValueType, Enum + // private const uint enum_flag_Category_Enum = 0x00070000; // sub-category of ValueType, Enum private const uint enum_flag_Category_Array = 0x00080000; private const uint enum_flag_Category_Array_Mask = 0x000C0000; private const uint enum_flag_Category_ValueType_Mask = 0x000C0000; From 257cd4353f1e64b7060dace857583229bcab1daa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 03:55:10 +0000 Subject: [PATCH 10/43] Add IsPrimitive(), refactor SetInternalCorElementType, delete SetIsTruePrimitive, simplify jitinterface condition, delete handle ELEMENT_TYPE_I Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d00ace36-750a-4a1e-8467-db312f324c69 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/jitinterface.cpp | 9 +-------- src/coreclr/vm/methodtable.cpp | 6 +++--- src/coreclr/vm/methodtable.h | 8 +++++--- src/coreclr/vm/methodtable.inl | 4 ++-- src/coreclr/vm/methodtablebuilder.cpp | 15 +-------------- 5 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index d313373bcfbec1..1fb1ea6b39bd7b 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -338,14 +338,7 @@ CorInfoType CEEInfo::asCorInfoType(CorElementType eeType, // Enums are exactly like primitives, even from a verification standpoint, // so we zap the type handle in this case. // - // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that) - // but don't count as primitives as far as verification is concerned... - // - // To make things stranger, TypedReference returns true for "IsTruePrimitive". - // However the JIT likes us to report the type handle in that case. - if (!typeHnd.IsTypeDesc() && ( - (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT)) - || typeHnd.AsMethodTable()->IsEnum()) ) + if (!typeHnd.IsTypeDesc() && typeHnd.AsMethodTable()->IsPrimitive()) { typeHndUpdated = TypeHandle(); } diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 35b287b995a8c0..336ab5e55f1eed 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -5034,7 +5034,7 @@ CorElementType MethodTable::GetSignatureCorElementType() #ifndef DACCESS_COMPILE //========================================================================================== -void MethodTable::SetInternalCorElementType (CorElementType _NormType) +void MethodTable::SetInternalCorElementType (CorElementType _NormType, bool isTruePrimitive) { WRAPPER_NO_CONTRACT; @@ -5049,8 +5049,8 @@ void MethodTable::SetInternalCorElementType (CorElementType _NormType) _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType); break; default: - SetFlag(enum_flag_Category_Enum); - _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Enum); + SetFlag(isTruePrimitive ? enum_flag_Category_Primitive : enum_flag_Category_Enum); + _ASSERTE(GetFlag(enum_flag_Category_Mask) == (isTruePrimitive ? enum_flag_Category_Primitive : enum_flag_Category_Enum)); break; } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 74441d230b584b..daa4f0c349d87b 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2775,7 +2775,7 @@ class MethodTable // * code:TypeHandle.GetSignatureCorElementType() // * code:TypeHandle.GetInternalCorElementType() CorElementType GetInternalCorElementType(); - void SetInternalCorElementType(CorElementType _NormType); + void SetInternalCorElementType(CorElementType _NormType, bool isTruePrimitive = false); // See code:TypeHandle::GetSignatureCorElementType for description CorElementType GetSignatureCorElementType(); @@ -2784,9 +2784,11 @@ class MethodTable // ELEMENT_TYPE_I, // ELEMENT_TYPE_I4, // ELEMENT_TYPE_TYPEDBYREF etc. - // Note that IsTruePrimitive returns false for enum types. + // And not enum. BOOL IsTruePrimitive(); - void SetIsTruePrimitive(); + + // Like IsTruePrimitive but also returns true for enum types. + BOOL IsPrimitive(); // Is this delegate? Returns false for System.Delegate and System.MulticastDelegate. inline BOOL IsDelegate() diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 6d203304eb7915..ab846eefefc4fa 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -331,10 +331,10 @@ inline BOOL MethodTable::IsTruePrimitive() } //========================================================================================== -inline void MethodTable::SetIsTruePrimitive() +inline BOOL MethodTable::IsPrimitive() { LIMITED_METHOD_DAC_CONTRACT; - m_dwFlags = (m_dwFlags & ~(DWORD)enum_flag_Category_Mask) | (DWORD)enum_flag_Category_Primitive; + return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_Primitive; } //========================================================================================== diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 038fa7a8d61417..c37e930e31050c 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -10744,8 +10744,7 @@ void MethodTableBuilder::CheckForSystemTypes() CorElementType type = CorTypeInfo::FindPrimitiveType(name); if (type != ELEMENT_TYPE_END) { - pMT->SetInternalCorElementType(type); - pMT->SetIsTruePrimitive(); + pMT->SetInternalCorElementType(type, true); #if defined(TARGET_X86) && defined(UNIX_X86_ABI) switch (type) @@ -10778,18 +10777,6 @@ void MethodTableBuilder::CheckForSystemTypes() { pMT->SetIsNullable(); } - else if (strcmp(name, g_RuntimeArgumentHandleName) == 0) - { - pMT->SetInternalCorElementType (ELEMENT_TYPE_I); - } - else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0) - { - pMT->SetInternalCorElementType (ELEMENT_TYPE_I); - } - else if (strcmp(name, g_RuntimeFieldHandleInternalName) == 0) - { - pMT->SetInternalCorElementType (ELEMENT_TYPE_I); - } else if ((strcmp(name, g_Int128Name) == 0) || (strcmp(name, g_UInt128Name) == 0)) { EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo(); From ceafd3dfce68ddca7e3a1d223bc9f0edefc94fc2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 03:57:36 +0000 Subject: [PATCH 11/43] Fix SetFlag type in SetInternalCorElementType default case Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d00ace36-750a-4a1e-8467-db312f324c69 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/methodtable.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 336ab5e55f1eed..3d44ca126fa64e 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -5049,10 +5049,13 @@ void MethodTable::SetInternalCorElementType (CorElementType _NormType, bool isTr _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType); break; default: - SetFlag(isTruePrimitive ? enum_flag_Category_Primitive : enum_flag_Category_Enum); - _ASSERTE(GetFlag(enum_flag_Category_Mask) == (isTruePrimitive ? enum_flag_Category_Primitive : enum_flag_Category_Enum)); + { + WFLAGS_HIGH_ENUM category = isTruePrimitive ? enum_flag_Category_Primitive : enum_flag_Category_Enum; + SetFlag(category); + _ASSERTE(GetFlag(enum_flag_Category_Mask) == category); break; } + } GetClass()->SetInternalCorElementType(_NormType); _ASSERTE(GetInternalCorElementType() == _NormType); From 1647dbe166065456b155866763b2b4a7a2d2c99f Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 21:01:55 -0700 Subject: [PATCH 12/43] Apply suggestion from @jkotas --- src/coreclr/vm/methodtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index daa4f0c349d87b..a30e8501c56adc 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2784,7 +2784,7 @@ class MethodTable // ELEMENT_TYPE_I, // ELEMENT_TYPE_I4, // ELEMENT_TYPE_TYPEDBYREF etc. - // And not enum. + // Note that IsTruePrimitive returns false for enum types. BOOL IsTruePrimitive(); // Like IsTruePrimitive but also returns true for enum types. From 2a130cbef227a920da2c77ab40d72e7dec1ef550 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 21:05:16 -0700 Subject: [PATCH 13/43] Apply suggestion from @jkotas --- src/coreclr/vm/typehandle.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index a8617851bc87bd..8f1592d19219ff 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -200,7 +200,6 @@ class TypeHandle // This helper: // - Will return enums underlying type // - Will return underlying primitive for System.Int32 etc... - // - Will return the primitive used by the calling convention // // This will NOT convert E_T_ARRAY, E_T_SZARRAY etc. to E_T_CLASS (though it probably // should). Use CorTypeInfo::IsObjRef for that. From 8179e5f62955929517ec41420614f4bc48ddc460 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 21:05:57 -0700 Subject: [PATCH 14/43] Apply suggestion from @jkotas --- src/coreclr/vm/typehandle.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index 8f1592d19219ff..6c10b2d755704d 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -201,8 +201,7 @@ class TypeHandle // - Will return enums underlying type // - Will return underlying primitive for System.Int32 etc... // - // This will NOT convert E_T_ARRAY, E_T_SZARRAY etc. to E_T_CLASS (though it probably - // should). Use CorTypeInfo::IsObjRef for that. + // This will NOT convert E_T_ARRAY, E_T_SZARRAY etc. to E_T_CLASS. Use CorTypeInfo::IsObjRef for that. CorElementType GetInternalCorElementType() const; //------------------------------------------------------------------- From 9bc8857f248a9cdd951d02fb921da5221f9f2b28 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 04:17:23 +0000 Subject: [PATCH 15/43] Change IsTruePrimitive and IsPrimitive return types from BOOL to bool Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/41f05a09-6124-4a52-a78d-8b1b82aa4f9c Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/methodtable.h | 4 ++-- src/coreclr/vm/methodtable.inl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index a30e8501c56adc..cbfd0079f8a977 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2785,10 +2785,10 @@ class MethodTable // ELEMENT_TYPE_I4, // ELEMENT_TYPE_TYPEDBYREF etc. // Note that IsTruePrimitive returns false for enum types. - BOOL IsTruePrimitive(); + bool IsTruePrimitive(); // Like IsTruePrimitive but also returns true for enum types. - BOOL IsPrimitive(); + bool IsPrimitive(); // Is this delegate? Returns false for System.Delegate and System.MulticastDelegate. inline BOOL IsDelegate() diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index ab846eefefc4fa..2019c1ab8b2d1c 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -324,14 +324,14 @@ inline DWORD MethodTable::GetRank() } //========================================================================================== -inline BOOL MethodTable::IsTruePrimitive() +inline bool MethodTable::IsTruePrimitive() { LIMITED_METHOD_DAC_CONTRACT; return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Primitive; } //========================================================================================== -inline BOOL MethodTable::IsPrimitive() +inline bool MethodTable::IsPrimitive() { LIMITED_METHOD_DAC_CONTRACT; return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_Primitive; From 22fcaef0155336969c1d51f4d3e3b56f9762b806 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 04:23:22 +0000 Subject: [PATCH 16/43] Apply MethodTable bool signature and parameter naming suggestions Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/522a0066-595e-44f6-a1fa-d58b7ae4b085 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/methodtable.cpp | 8 ++++---- src/coreclr/vm/methodtable.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 3d44ca126fa64e..430f7eaf11d530 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -5034,11 +5034,11 @@ CorElementType MethodTable::GetSignatureCorElementType() #ifndef DACCESS_COMPILE //========================================================================================== -void MethodTable::SetInternalCorElementType (CorElementType _NormType, bool isTruePrimitive) +void MethodTable::SetInternalCorElementType(CorElementType elemType, bool isTruePrimitive) { WRAPPER_NO_CONTRACT; - switch (_NormType) + switch (elemType) { case ELEMENT_TYPE_CLASS: _ASSERTE(!IsArray()); @@ -5057,8 +5057,8 @@ void MethodTable::SetInternalCorElementType (CorElementType _NormType, bool isTr } } - GetClass()->SetInternalCorElementType(_NormType); - _ASSERTE(GetInternalCorElementType() == _NormType); + GetClass()->SetInternalCorElementType(elemType); + _ASSERTE(GetInternalCorElementType() == elemType); } #endif // !DACCESS_COMPILE diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index cbfd0079f8a977..1544e77b11987b 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2775,7 +2775,7 @@ class MethodTable // * code:TypeHandle.GetSignatureCorElementType() // * code:TypeHandle.GetInternalCorElementType() CorElementType GetInternalCorElementType(); - void SetInternalCorElementType(CorElementType _NormType, bool isTruePrimitive = false); + void SetInternalCorElementType(CorElementType elemType, bool isTruePrimitive = false); // See code:TypeHandle::GetSignatureCorElementType for description CorElementType GetSignatureCorElementType(); From 58de2510513f58f3b148de34b5d96df00a3e5c69 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 05:21:36 +0000 Subject: [PATCH 17/43] Revert category flag names to PrimitiveValueType/TruePrimitive and fix signed/unsigned mismatch Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/308624f3-4df4-4397-a474-cdbd40a15d4a Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- docs/design/datacontracts/RuntimeTypeSystem.md | 12 ++++++------ .../CompilerServices/RuntimeHelpers.CoreCLR.cs | 8 ++++---- src/coreclr/vm/methodtable.cpp | 12 ++++++------ src/coreclr/vm/methodtable.h | 4 ++-- src/coreclr/vm/methodtable.inl | 4 ++-- .../Contracts/RuntimeTypeSystem_1.cs | 8 ++++---- .../RuntimeTypeSystemHelpers/MethodTableFlags_1.cs | 4 ++-- src/native/managed/cdac/tests/MethodTableTests.cs | 4 ++-- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 8a29098adfca42..bb92fa93681839 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -294,8 +294,8 @@ internal partial struct RuntimeTypeSystem_1 Category_Array = 0x00080000, Category_ValueType = 0x00040000, Category_Nullable = 0x00050000, - Category_Primitive = 0x00060000, - Category_Enum = 0x00070000, + Category_PrimitiveValueType = 0x00060000, + Category_TruePrimitive = 0x00070000, Category_Interface = 0x000C0000, Collectible = 0x00200000, RequiresAlign8 = 0x00800000, @@ -813,9 +813,9 @@ Contracts used: return CorElementType.SzArray; case WFLAGS_HIGH.Category_ValueType: case WFLAGS_HIGH.Category_Nullable: - case WFLAGS_HIGH.Category_Enum: + case WFLAGS_HIGH.Category_PrimitiveValueType: return CorElementType.ValueType; - case WFLAGS_HIGH.Category_Primitive: + case WFLAGS_HIGH.Category_TruePrimitive: return (CorElementType)GetClassData(typeHandle).InternalCorElementType; default: return CorElementType.Class; @@ -835,7 +835,7 @@ Contracts used: // if typedesc: check for CorElementType.ValueType } - // Enums have Category_Enum in their MethodTable flags and their + // Enums have Category_PrimitiveValueType in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), // not ValueType. public bool IsEnum(TypeHandle typeHandle) @@ -844,7 +844,7 @@ Contracts used: return false; MethodTable methodTable = _methodTables[typeHandle.Address]; - return methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) == WFLAGS_HIGH.Category_Enum; + return methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) == WFLAGS_HIGH.Category_PrimitiveValueType; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. 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 06ecbe9bf62ec2..5a976b2d8f54d3 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 @@ -850,8 +850,8 @@ internal unsafe struct MethodTable private const uint enum_flag_Category_ValueType = 0x00040000; private const uint enum_flag_Category_Nullable = 0x00050000; private const uint enum_flag_Category_IsPrimitiveMask = 0x000E0000; - private const uint enum_flag_Category_Primitive = 0x00060000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) - // private const uint enum_flag_Category_Enum = 0x00070000; // sub-category of ValueType, Enum + private const uint enum_flag_Category_PrimitiveValueType = 0x00060000; // sub-category of ValueType, Enum or primitive value type + private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) private const uint enum_flag_Category_Array = 0x00080000; private const uint enum_flag_Category_Array_Mask = 0x000C0000; private const uint enum_flag_Category_ValueType_Mask = 0x000C0000; @@ -955,9 +955,9 @@ public int MultiDimensionalArrayRank public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike; // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. - public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Primitive; + public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_TruePrimitive; - public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) == enum_flag_Category_Primitive; + public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) == enum_flag_Category_TruePrimitive; public bool IsArray => (Flags & enum_flag_Category_Array_Mask) == enum_flag_Category_Array; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 430f7eaf11d530..c7224f3c0f5946 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4969,8 +4969,8 @@ CorElementType MethodTable::GetInternalCorElementType() ret = ELEMENT_TYPE_VALUETYPE; break; - case enum_flag_Category_Primitive: - // enum_flag_Category_ElementTypeMask maps both Category_Primitive and Category_Enum here. + case enum_flag_Category_TruePrimitive: + // enum_flag_Category_ElementTypeMask maps both Category_TruePrimitive and Category_PrimitiveValueType here. ret = GetClass()->GetInternalCorElementType(); _ASSERTE((ret != ELEMENT_TYPE_CLASS) && (ret != ELEMENT_TYPE_VALUETYPE)); @@ -5015,11 +5015,11 @@ CorElementType MethodTable::GetSignatureCorElementType() case enum_flag_Category_ValueType: case enum_flag_Category_Nullable: - case enum_flag_Category_Enum: + case enum_flag_Category_PrimitiveValueType: ret = ELEMENT_TYPE_VALUETYPE; break; - case enum_flag_Category_Primitive: + case enum_flag_Category_TruePrimitive: ret = GetClass()->GetInternalCorElementType(); break; @@ -5050,9 +5050,9 @@ void MethodTable::SetInternalCorElementType(CorElementType elemType, bool isTrue break; default: { - WFLAGS_HIGH_ENUM category = isTruePrimitive ? enum_flag_Category_Primitive : enum_flag_Category_Enum; + WFLAGS_HIGH_ENUM category = isTruePrimitive ? enum_flag_Category_TruePrimitive : enum_flag_Category_PrimitiveValueType; SetFlag(category); - _ASSERTE(GetFlag(enum_flag_Category_Mask) == category); + _ASSERTE(GetFlag(enum_flag_Category_Mask) == static_cast(category)); break; } } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 1544e77b11987b..2de0a7ab49eed4 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3789,8 +3789,8 @@ public : enum_flag_Category_ValueType = 0x00040000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_Primitive = 0x00060000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_Enum = 0x00070000, // sub-category of ValueType, Enum. [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_PrimitiveValueType = 0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array_Mask = 0x000C0000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 2019c1ab8b2d1c..60c4c1bde2f89f 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -327,14 +327,14 @@ inline DWORD MethodTable::GetRank() inline bool MethodTable::IsTruePrimitive() { LIMITED_METHOD_DAC_CONTRACT; - return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Primitive; + return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_TruePrimitive; } //========================================================================================== inline bool MethodTable::IsPrimitive() { LIMITED_METHOD_DAC_CONTRACT; - return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_Primitive; + return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_TruePrimitive; } //========================================================================================== diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 41408991c2b95b..837cbf00224371 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -848,9 +848,9 @@ public CorElementType GetSignatureCorElementType(TypeHandle typeHandle) return CorElementType.SzArray; case MethodTableFlags_1.WFLAGS_HIGH.Category_ValueType: case MethodTableFlags_1.WFLAGS_HIGH.Category_Nullable: - case MethodTableFlags_1.WFLAGS_HIGH.Category_Enum: + case MethodTableFlags_1.WFLAGS_HIGH.Category_PrimitiveValueType: return CorElementType.ValueType; - case MethodTableFlags_1.WFLAGS_HIGH.Category_Primitive: + case MethodTableFlags_1.WFLAGS_HIGH.Category_TruePrimitive: return (CorElementType)GetClassData(typeHandle).InternalCorElementType; default: return CorElementType.Class; @@ -883,14 +883,14 @@ public bool IsValueType(TypeHandle typeHandle) public bool IsEnum(TypeHandle typeHandle) { - // Enums have Category_Enum in their MethodTable flags and their + // Enums have Category_PrimitiveValueType in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), // not ValueType. if (!typeHandle.IsMethodTable()) return false; MethodTable methodTable = _methodTables[typeHandle.Address]; - return methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) == MethodTableFlags_1.WFLAGS_HIGH.Category_Enum; + return methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) == MethodTableFlags_1.WFLAGS_HIGH.Category_PrimitiveValueType; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs index 56975c1df16073..466d45a4ee4975 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs @@ -42,8 +42,8 @@ internal enum WFLAGS_HIGH : uint Category_ElementType_Mask = 0x000E0000, Category_ValueType = 0x00040000, Category_Nullable = 0x00050000, - Category_Primitive = 0x00060000, - Category_Enum = 0x00070000, + Category_PrimitiveValueType = 0x00060000, + Category_TruePrimitive = 0x00070000, Category_Interface = 0x000C0000, Collectible = 0x00200000, // GC depends on this bit. RequiresAlign8 = 0x00800000, diff --git a/src/native/managed/cdac/tests/MethodTableTests.cs b/src/native/managed/cdac/tests/MethodTableTests.cs index 08a2f7542d3ac0..05ebd34cd4604c 100644 --- a/src/native/managed/cdac/tests/MethodTableTests.cs +++ b/src/native/managed/cdac/tests/MethodTableTests.cs @@ -547,7 +547,7 @@ public void IsValueTypeReturnsTrueForValueTypeCategories(MockTarget.Architecture MockEEClass enumEEClass = rtsBuilder.AddEEClass("EnumEEClass"); MockMethodTable enumMT = rtsBuilder.AddMethodTable("Enum"); - enumMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_Enum; + enumMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_PrimitiveValueType; enumMT.BaseSize = rtsBuilder.Builder.TargetTestHelpers.ObjectBaseSize; enumMT.ParentMethodTable = systemObjectMethodTablePtr; enumMT.NumVirtuals = 3; @@ -557,7 +557,7 @@ public void IsValueTypeReturnsTrueForValueTypeCategories(MockTarget.Architecture MockEEClass tpEEClass = rtsBuilder.AddEEClass("TruePrimitiveEEClass"); MockMethodTable tpMT = rtsBuilder.AddMethodTable("TruePrimitive"); - tpMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_Primitive; + tpMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_TruePrimitive; tpMT.BaseSize = rtsBuilder.Builder.TargetTestHelpers.ObjectBaseSize; tpMT.ParentMethodTable = systemObjectMethodTablePtr; tpMT.NumVirtuals = 3; From 492ea1eda1ffa10027264094c487d02b57b91560 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 22:37:08 -0700 Subject: [PATCH 18/43] Apply suggestion from @jkotas --- .../System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5a976b2d8f54d3..668e6663cc506e 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 @@ -955,7 +955,7 @@ public int MultiDimensionalArrayRank public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike; // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. - public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_TruePrimitive; + public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_PrimitiveValueType; public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) == enum_flag_Category_TruePrimitive; From 4b6ba08cc7c412c1891616a0765a6ec7284bbffb Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 22:38:43 -0700 Subject: [PATCH 19/43] Apply suggestion from @jkotas --- src/coreclr/vm/methodtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index c7224f3c0f5946..9f3a30d675ca1a 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4969,7 +4969,7 @@ CorElementType MethodTable::GetInternalCorElementType() ret = ELEMENT_TYPE_VALUETYPE; break; - case enum_flag_Category_TruePrimitive: + case enum_flag_Category_PrimitiveValueType: // enum_flag_Category_ElementTypeMask maps both Category_TruePrimitive and Category_PrimitiveValueType here. ret = GetClass()->GetInternalCorElementType(); _ASSERTE((ret != ELEMENT_TYPE_CLASS) && From 1e0c51023037a0999c11e430963ca3738e152808 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 22:39:06 -0700 Subject: [PATCH 20/43] Apply suggestion from @jkotas --- .../System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 668e6663cc506e..935ae133272fe7 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 @@ -957,7 +957,7 @@ public int MultiDimensionalArrayRank // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_PrimitiveValueType; - public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) == enum_flag_Category_TruePrimitive; + public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_TruePrimitive; public bool IsArray => (Flags & enum_flag_Category_Array_Mask) == enum_flag_Category_Array; From 64a71ba0242df571e6bf8ad0cd2a4b043b85587b Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 22:40:38 -0700 Subject: [PATCH 21/43] Apply suggestion from @jkotas --- src/coreclr/vm/methodtable.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 60c4c1bde2f89f..0b534584a55845 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -334,7 +334,7 @@ inline bool MethodTable::IsTruePrimitive() inline bool MethodTable::IsPrimitive() { LIMITED_METHOD_DAC_CONTRACT; - return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_TruePrimitive; + return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_PrimitiveValueType; } //========================================================================================== From e7ac939f90ee550e042669ca92c475e71c04452b Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 22:44:03 -0700 Subject: [PATCH 22/43] Apply suggestions from code review Co-authored-by: Jan Kotas --- src/coreclr/vm/methodtable.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 9f3a30d675ca1a..cc9932333764c4 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -5046,13 +5046,9 @@ void MethodTable::SetInternalCorElementType(CorElementType elemType, bool isTrue break; case ELEMENT_TYPE_VALUETYPE: SetFlag(enum_flag_Category_ValueType); - _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType); break; default: - { - WFLAGS_HIGH_ENUM category = isTruePrimitive ? enum_flag_Category_TruePrimitive : enum_flag_Category_PrimitiveValueType; - SetFlag(category); - _ASSERTE(GetFlag(enum_flag_Category_Mask) == static_cast(category)); + SetFlag(isTruePrimitive ? enum_flag_Category_TruePrimitive : enum_flag_Category_PrimitiveValueType); break; } } From 8d0b204afffd1ce9c0b1e9f234c8a238f7e363aa Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 22:51:23 -0700 Subject: [PATCH 23/43] Apply suggestion from @jkotas --- docs/design/datacontracts/RuntimeTypeSystem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index bb92fa93681839..a56d7889561529 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -837,7 +837,7 @@ Contracts used: // Enums have Category_PrimitiveValueType in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ValueType. + // not ValueType. Regular primitive value types (Int32, etc.) have Category_TruePrimitive. public bool IsEnum(TypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) From eba9e493d2ea5080a588f6f7ecdfd0159ec70778 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 23:00:38 -0700 Subject: [PATCH 24/43] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/vm/methodtable.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index cc9932333764c4..db587a1c764345 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -5051,7 +5051,6 @@ void MethodTable::SetInternalCorElementType(CorElementType elemType, bool isTrue SetFlag(isTruePrimitive ? enum_flag_Category_TruePrimitive : enum_flag_Category_PrimitiveValueType); break; } - } GetClass()->SetInternalCorElementType(elemType); _ASSERTE(GetInternalCorElementType() == elemType); From 53ca4a8ec200187fae2888328ac3d42ce5564010 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 23:02:44 -0700 Subject: [PATCH 25/43] Apply suggestion from @jkotas --- src/coreclr/vm/methodtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 2de0a7ab49eed4..6283c4001362b7 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3789,7 +3789,7 @@ public : enum_flag_Category_ValueType = 0x00040000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_PrimitiveValueType = 0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_PrimitiveValueType= 0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value From 6e6336ac9fd70207aa3e19a34d1d1266c627ae62 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 23:03:16 -0700 Subject: [PATCH 26/43] Apply suggestion from @jkotas --- src/coreclr/vm/methodtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 6283c4001362b7..584b14b311089b 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3790,7 +3790,7 @@ public : enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_PrimitiveValueType= 0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of PrimitiveValueType. (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array_Mask = 0x000C0000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value From 5f72765a2c00c13c88de5125fa7ac36c45500492 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 23:05:34 -0700 Subject: [PATCH 27/43] Apply suggestion from @jkotas --- src/coreclr/vm/methodtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 584b14b311089b..3a36da70642967 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3790,7 +3790,7 @@ public : enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_PrimitiveValueType= 0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of PrimitiveValueType. (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of PrimitiveValueType. Regular primitive value types (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array_Mask = 0x000C0000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value From 12c52810e3b75c1b1042caa50d78a4c59bc49bcd Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 6 May 2026 23:06:21 -0700 Subject: [PATCH 28/43] Apply suggestion from @jkotas --- src/coreclr/vm/methodtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 3a36da70642967..7fed86f2196770 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3789,7 +3789,7 @@ public : enum_flag_Category_ValueType = 0x00040000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_PrimitiveValueType= 0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of PrimitiveValueType. Regular primitive value types (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value From b7b9de796f5fefd17310e50e04170f7555bbafe3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 06:13:35 +0000 Subject: [PATCH 29/43] Update enum_flag_Category_PrimitiveValueType comment to 'Enum or true primitive' Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/9263f39d-624e-4ab2-aec8-3250d36f4d9a Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 2 +- src/coreclr/vm/methodtable.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 935ae133272fe7..64f2b6bc84b596 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 @@ -850,7 +850,7 @@ internal unsafe struct MethodTable private const uint enum_flag_Category_ValueType = 0x00040000; private const uint enum_flag_Category_Nullable = 0x00050000; private const uint enum_flag_Category_IsPrimitiveMask = 0x000E0000; - private const uint enum_flag_Category_PrimitiveValueType = 0x00060000; // sub-category of ValueType, Enum or primitive value type + private const uint enum_flag_Category_PrimitiveValueType = 0x00060000; // sub-category of ValueType, Enum or true primitive private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) private const uint enum_flag_Category_Array = 0x00080000; private const uint enum_flag_Category_Array_Mask = 0x000C0000; diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 7fed86f2196770..7a3626fba6a25f 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3789,7 +3789,7 @@ public : enum_flag_Category_ValueType = 0x00040000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or primitive value type. [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or true primitive. [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of PrimitiveValueType. Regular primitive value types (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value From cf223a585a1237ec57ee78c78183ca7808d32fac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 06:23:58 +0000 Subject: [PATCH 30/43] Update primitive category comments Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/17782ce4-6976-4012-a337-8003bc624549 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 2 +- src/coreclr/vm/methodtable.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 64f2b6bc84b596..cfa30b2573944f 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 @@ -851,7 +851,7 @@ internal unsafe struct MethodTable private const uint enum_flag_Category_Nullable = 0x00050000; private const uint enum_flag_Category_IsPrimitiveMask = 0x000E0000; private const uint enum_flag_Category_PrimitiveValueType = 0x00060000; // sub-category of ValueType, Enum or true primitive - private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) + private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of PrimitiveValueType. (Int32, etc.) private const uint enum_flag_Category_Array = 0x00080000; private const uint enum_flag_Category_Array_Mask = 0x000C0000; private const uint enum_flag_Category_ValueType_Mask = 0x000C0000; diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 7a3626fba6a25f..c3aabdbc84ce64 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3789,8 +3789,8 @@ public : enum_flag_Category_ValueType = 0x00040000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or true primitive. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of PrimitiveValueType. Regular primitive value types (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_PrimitiveValueType= 0x00060000, // sub-category of ValueType, Enum or true primitive. [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of PrimitiveValueType. (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array_Mask = 0x000C0000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value From fe05de31bc7ff348781648f5be4c7d1ab1de7895 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 06:43:55 +0000 Subject: [PATCH 31/43] Rename enum_flag_Category_PrimitiveValueType to enum_flag_Category_Enum throughout Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/104333fd-5bb4-4e6c-9d53-1cc01c62e143 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- docs/design/datacontracts/RuntimeTypeSystem.md | 4 ++-- .../Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 6 +++--- src/coreclr/vm/methodtable.cpp | 8 ++++---- src/coreclr/vm/methodtable.h | 4 ++-- src/coreclr/vm/methodtable.inl | 2 +- .../Contracts/RuntimeTypeSystem_1.cs | 6 +++--- .../RuntimeTypeSystemHelpers/MethodTableFlags_1.cs | 2 +- src/native/managed/cdac/tests/MethodTableTests.cs | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index a56d7889561529..b31f32f9d65ccd 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -835,7 +835,7 @@ Contracts used: // if typedesc: check for CorElementType.ValueType } - // Enums have Category_PrimitiveValueType in their MethodTable flags and their + // Enums have Category_Enum in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), // not ValueType. Regular primitive value types (Int32, etc.) have Category_TruePrimitive. public bool IsEnum(TypeHandle typeHandle) @@ -844,7 +844,7 @@ Contracts used: return false; MethodTable methodTable = _methodTables[typeHandle.Address]; - return methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) == WFLAGS_HIGH.Category_PrimitiveValueType; + return methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) == WFLAGS_HIGH.Category_Enum; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. 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 cfa30b2573944f..c037c95e9f3fce 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 @@ -850,8 +850,8 @@ internal unsafe struct MethodTable private const uint enum_flag_Category_ValueType = 0x00040000; private const uint enum_flag_Category_Nullable = 0x00050000; private const uint enum_flag_Category_IsPrimitiveMask = 0x000E0000; - private const uint enum_flag_Category_PrimitiveValueType = 0x00060000; // sub-category of ValueType, Enum or true primitive - private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of PrimitiveValueType. (Int32, etc.) + private const uint enum_flag_Category_Enum = 0x00060000; // sub-category of ValueType + private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of ValueType. (Int32, etc.) private const uint enum_flag_Category_Array = 0x00080000; private const uint enum_flag_Category_Array_Mask = 0x000C0000; private const uint enum_flag_Category_ValueType_Mask = 0x000C0000; @@ -955,7 +955,7 @@ public int MultiDimensionalArrayRank public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike; // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. - public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_PrimitiveValueType; + public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_Enum; public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_TruePrimitive; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index db587a1c764345..21aa442bdbfcf8 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4969,8 +4969,8 @@ CorElementType MethodTable::GetInternalCorElementType() ret = ELEMENT_TYPE_VALUETYPE; break; - case enum_flag_Category_PrimitiveValueType: - // enum_flag_Category_ElementTypeMask maps both Category_TruePrimitive and Category_PrimitiveValueType here. + case enum_flag_Category_Enum: + // enum_flag_Category_ElementTypeMask maps both Category_TruePrimitive and Category_Enum here. ret = GetClass()->GetInternalCorElementType(); _ASSERTE((ret != ELEMENT_TYPE_CLASS) && (ret != ELEMENT_TYPE_VALUETYPE)); @@ -5015,7 +5015,7 @@ CorElementType MethodTable::GetSignatureCorElementType() case enum_flag_Category_ValueType: case enum_flag_Category_Nullable: - case enum_flag_Category_PrimitiveValueType: + case enum_flag_Category_Enum: ret = ELEMENT_TYPE_VALUETYPE; break; @@ -5048,7 +5048,7 @@ void MethodTable::SetInternalCorElementType(CorElementType elemType, bool isTrue SetFlag(enum_flag_Category_ValueType); break; default: - SetFlag(isTruePrimitive ? enum_flag_Category_TruePrimitive : enum_flag_Category_PrimitiveValueType); + SetFlag(isTruePrimitive ? enum_flag_Category_TruePrimitive : enum_flag_Category_Enum); break; } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index c3aabdbc84ce64..9542f0aa251f2c 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -3789,8 +3789,8 @@ public : enum_flag_Category_ValueType = 0x00040000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_ValueType_Mask = 0x000C0000, enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_PrimitiveValueType= 0x00060000, // sub-category of ValueType, Enum or true primitive. [cDAC] [RuntimeTypeSystem]: Contract depends on this value - enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of PrimitiveValueType. (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_Enum = 0x00060000, // sub-category of ValueType. [cDAC] [RuntimeTypeSystem]: Contract depends on this value + enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType. (Int32, etc.). [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array = 0x00080000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value enum_flag_Category_Array_Mask = 0x000C0000, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 0b534584a55845..058d1e3349a5b9 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -334,7 +334,7 @@ inline bool MethodTable::IsTruePrimitive() inline bool MethodTable::IsPrimitive() { LIMITED_METHOD_DAC_CONTRACT; - return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_PrimitiveValueType; + return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_Enum; } //========================================================================================== diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 837cbf00224371..2bbd4a11a7c9de 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -848,7 +848,7 @@ public CorElementType GetSignatureCorElementType(TypeHandle typeHandle) return CorElementType.SzArray; case MethodTableFlags_1.WFLAGS_HIGH.Category_ValueType: case MethodTableFlags_1.WFLAGS_HIGH.Category_Nullable: - case MethodTableFlags_1.WFLAGS_HIGH.Category_PrimitiveValueType: + case MethodTableFlags_1.WFLAGS_HIGH.Category_Enum: return CorElementType.ValueType; case MethodTableFlags_1.WFLAGS_HIGH.Category_TruePrimitive: return (CorElementType)GetClassData(typeHandle).InternalCorElementType; @@ -883,14 +883,14 @@ public bool IsValueType(TypeHandle typeHandle) public bool IsEnum(TypeHandle typeHandle) { - // Enums have Category_PrimitiveValueType in their MethodTable flags and their + // Enums have Category_Enum in their MethodTable flags and their // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), // not ValueType. if (!typeHandle.IsMethodTable()) return false; MethodTable methodTable = _methodTables[typeHandle.Address]; - return methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) == MethodTableFlags_1.WFLAGS_HIGH.Category_PrimitiveValueType; + return methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) == MethodTableFlags_1.WFLAGS_HIGH.Category_Enum; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs index 466d45a4ee4975..11076a8c73a8d4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs @@ -42,7 +42,7 @@ internal enum WFLAGS_HIGH : uint Category_ElementType_Mask = 0x000E0000, Category_ValueType = 0x00040000, Category_Nullable = 0x00050000, - Category_PrimitiveValueType = 0x00060000, + Category_Enum = 0x00060000, Category_TruePrimitive = 0x00070000, Category_Interface = 0x000C0000, Collectible = 0x00200000, // GC depends on this bit. diff --git a/src/native/managed/cdac/tests/MethodTableTests.cs b/src/native/managed/cdac/tests/MethodTableTests.cs index 05ebd34cd4604c..0c5f9a5d4d4c9c 100644 --- a/src/native/managed/cdac/tests/MethodTableTests.cs +++ b/src/native/managed/cdac/tests/MethodTableTests.cs @@ -547,7 +547,7 @@ public void IsValueTypeReturnsTrueForValueTypeCategories(MockTarget.Architecture MockEEClass enumEEClass = rtsBuilder.AddEEClass("EnumEEClass"); MockMethodTable enumMT = rtsBuilder.AddMethodTable("Enum"); - enumMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_PrimitiveValueType; + enumMT.MTFlags = (uint)MethodTableFlags_1.WFLAGS_HIGH.Category_Enum; enumMT.BaseSize = rtsBuilder.Builder.TargetTestHelpers.ObjectBaseSize; enumMT.ParentMethodTable = systemObjectMethodTablePtr; enumMT.NumVirtuals = 3; From 99c07d85ac6ddcc495fb7e1bf6b90767197e6b44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 06:54:09 +0000 Subject: [PATCH 32/43] Add explanatory comment to IsPrimitive() about ElementTypeMask behavior Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/77f3ecf4-b37d-4e90-860a-e73634f54ac6 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/methodtable.inl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 058d1e3349a5b9..ec821ac7962ce4 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -334,6 +334,7 @@ inline bool MethodTable::IsTruePrimitive() inline bool MethodTable::IsPrimitive() { LIMITED_METHOD_DAC_CONTRACT; + // enum_flag_Category_ElementTypeMask maps both Category_TruePrimitive and Category_Enum here. return GetFlag(enum_flag_Category_ElementTypeMask) == enum_flag_Category_Enum; } From 8739054ea9e0cf56b16e6a75edc91e78fa09b1c1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 13:58:19 +0000 Subject: [PATCH 33/43] Restore ELEMENT_TYPE_I for runtime handle types without setting category flags Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/475ee8bc-54b9-4ace-b1d4-dc7da359a9b4 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/methodtablebuilder.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index c37e930e31050c..bc7f59a7524c26 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -10777,6 +10777,18 @@ void MethodTableBuilder::CheckForSystemTypes() { pMT->SetIsNullable(); } + else if (strcmp(name, g_RuntimeArgumentHandleName) == 0) + { + GetHalfBakedClass()->SetInternalCorElementType(ELEMENT_TYPE_I); + } + else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0) + { + GetHalfBakedClass()->SetInternalCorElementType(ELEMENT_TYPE_I); + } + else if (strcmp(name, g_RuntimeFieldHandleInternalName) == 0) + { + GetHalfBakedClass()->SetInternalCorElementType(ELEMENT_TYPE_I); + } else if ((strcmp(name, g_Int128Name) == 0) || (strcmp(name, g_UInt128Name) == 0)) { EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo(); From 4688e6d3bcc327079967ca8d9f1781611b068fdb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 14:17:05 +0000 Subject: [PATCH 34/43] Revert "Restore ELEMENT_TYPE_I for runtime handle types without setting category flags" This reverts commit 8739054ea9e0cf56b16e6a75edc91e78fa09b1c1. Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/methodtablebuilder.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index bc7f59a7524c26..c37e930e31050c 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -10777,18 +10777,6 @@ void MethodTableBuilder::CheckForSystemTypes() { pMT->SetIsNullable(); } - else if (strcmp(name, g_RuntimeArgumentHandleName) == 0) - { - GetHalfBakedClass()->SetInternalCorElementType(ELEMENT_TYPE_I); - } - else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0) - { - GetHalfBakedClass()->SetInternalCorElementType(ELEMENT_TYPE_I); - } - else if (strcmp(name, g_RuntimeFieldHandleInternalName) == 0) - { - GetHalfBakedClass()->SetInternalCorElementType(ELEMENT_TYPE_I); - } else if ((strcmp(name, g_Int128Name) == 0) || (strcmp(name, g_UInt128Name) == 0)) { EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo(); From 25a34203dfe6041d293f495a9453e5ef20d0a824 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 14:25:36 +0000 Subject: [PATCH 35/43] Fix runtime handle types by setting ELEMENT_TYPE_I with Category_Enum and validating enum underlying types in IsEnum() Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3ee6d5ff-6d86-4a80-9113-7a4bb37a39cd Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../design/datacontracts/RuntimeTypeSystem.md | 19 ++++++++++++++++--- src/coreclr/vm/methodtablebuilder.cpp | 12 ++++++++++++ .../Contracts/RuntimeTypeSystem_1.cs | 18 +++++++++++++++--- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index b31f32f9d65ccd..15933dac446a04 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -836,15 +836,28 @@ Contracts used: } // Enums have Category_Enum in their MethodTable flags and their - // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ValueType. Regular primitive value types (Int32, etc.) have Category_TruePrimitive. + // InternalCorElementType is a valid enum underlying type (I1, U1, I2, U2, I4, U4, I8, U8), + // not ELEMENT_TYPE_I (which is used for runtime handle types). + // Regular primitive value types (Int32, etc.) have Category_TruePrimitive. public bool IsEnum(TypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) return false; MethodTable methodTable = _methodTables[typeHandle.Address]; - return methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) == WFLAGS_HIGH.Category_Enum; + if (methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) != WFLAGS_HIGH.Category_Enum) + return false; + + // Check that the internal element type is a valid enum underlying type + CorElementType elementType = (CorElementType)GetClassData(typeHandle).InternalCorElementType; + return elementType == CorElementType.I1 || + elementType == CorElementType.U1 || + elementType == CorElementType.I2 || + elementType == CorElementType.U2 || + elementType == CorElementType.I4 || + elementType == CorElementType.U4 || + elementType == CorElementType.I8 || + elementType == CorElementType.U8; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index c37e930e31050c..05af0d7acf1b00 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -10777,6 +10777,18 @@ void MethodTableBuilder::CheckForSystemTypes() { pMT->SetIsNullable(); } + else if (strcmp(name, g_RuntimeArgumentHandleName) == 0) + { + pMT->SetInternalCorElementType(ELEMENT_TYPE_I, false); + } + else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0) + { + pMT->SetInternalCorElementType(ELEMENT_TYPE_I, false); + } + else if (strcmp(name, g_RuntimeFieldHandleInternalName) == 0) + { + pMT->SetInternalCorElementType(ELEMENT_TYPE_I, false); + } else if ((strcmp(name, g_Int128Name) == 0) || (strcmp(name, g_UInt128Name) == 0)) { EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 2bbd4a11a7c9de..84002fc829b794 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -884,13 +884,25 @@ public bool IsValueType(TypeHandle typeHandle) public bool IsEnum(TypeHandle typeHandle) { // Enums have Category_Enum in their MethodTable flags and their - // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ValueType. + // InternalCorElementType is a valid enum underlying type (I1, U1, I2, U2, I4, U4, I8, U8), + // not ELEMENT_TYPE_I (which is used for runtime handle types). if (!typeHandle.IsMethodTable()) return false; MethodTable methodTable = _methodTables[typeHandle.Address]; - return methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) == MethodTableFlags_1.WFLAGS_HIGH.Category_Enum; + if (methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) != MethodTableFlags_1.WFLAGS_HIGH.Category_Enum) + return false; + + // Check that the internal element type is a valid enum underlying type + CorElementType elementType = (CorElementType)GetClassData(typeHandle).InternalCorElementType; + return elementType == CorElementType.I1 || + elementType == CorElementType.U1 || + elementType == CorElementType.I2 || + elementType == CorElementType.U2 || + elementType == CorElementType.I4 || + elementType == CorElementType.U4 || + elementType == CorElementType.I8 || + elementType == CorElementType.U8; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. From ac9f6f6817ca5b97be3684115cac574b3c6dc900 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 14:47:21 +0000 Subject: [PATCH 36/43] Revert "Fix runtime handle types by setting ELEMENT_TYPE_I with Category_Enum and validating enum underlying types in IsEnum()" This reverts commit 25a34203dfe6041d293f495a9453e5ef20d0a824. Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../design/datacontracts/RuntimeTypeSystem.md | 19 +++---------------- src/coreclr/vm/methodtablebuilder.cpp | 12 ------------ .../Contracts/RuntimeTypeSystem_1.cs | 18 +++--------------- 3 files changed, 6 insertions(+), 43 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 15933dac446a04..b31f32f9d65ccd 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -836,28 +836,15 @@ Contracts used: } // Enums have Category_Enum in their MethodTable flags and their - // InternalCorElementType is a valid enum underlying type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ELEMENT_TYPE_I (which is used for runtime handle types). - // Regular primitive value types (Int32, etc.) have Category_TruePrimitive. + // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), + // not ValueType. Regular primitive value types (Int32, etc.) have Category_TruePrimitive. public bool IsEnum(TypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) return false; MethodTable methodTable = _methodTables[typeHandle.Address]; - if (methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) != WFLAGS_HIGH.Category_Enum) - return false; - - // Check that the internal element type is a valid enum underlying type - CorElementType elementType = (CorElementType)GetClassData(typeHandle).InternalCorElementType; - return elementType == CorElementType.I1 || - elementType == CorElementType.U1 || - elementType == CorElementType.I2 || - elementType == CorElementType.U2 || - elementType == CorElementType.I4 || - elementType == CorElementType.U4 || - elementType == CorElementType.I8 || - elementType == CorElementType.U8; + return methodTable.Flags.GetFlag(WFLAGS_HIGH.Category_Mask) == WFLAGS_HIGH.Category_Enum; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 05af0d7acf1b00..c37e930e31050c 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -10777,18 +10777,6 @@ void MethodTableBuilder::CheckForSystemTypes() { pMT->SetIsNullable(); } - else if (strcmp(name, g_RuntimeArgumentHandleName) == 0) - { - pMT->SetInternalCorElementType(ELEMENT_TYPE_I, false); - } - else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0) - { - pMT->SetInternalCorElementType(ELEMENT_TYPE_I, false); - } - else if (strcmp(name, g_RuntimeFieldHandleInternalName) == 0) - { - pMT->SetInternalCorElementType(ELEMENT_TYPE_I, false); - } else if ((strcmp(name, g_Int128Name) == 0) || (strcmp(name, g_UInt128Name) == 0)) { EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 84002fc829b794..2bbd4a11a7c9de 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -884,25 +884,13 @@ public bool IsValueType(TypeHandle typeHandle) public bool IsEnum(TypeHandle typeHandle) { // Enums have Category_Enum in their MethodTable flags and their - // InternalCorElementType is a valid enum underlying type (I1, U1, I2, U2, I4, U4, I8, U8), - // not ELEMENT_TYPE_I (which is used for runtime handle types). + // InternalCorElementType is a primitive type (I1, U1, I2, U2, I4, U4, I8, U8), + // not ValueType. if (!typeHandle.IsMethodTable()) return false; MethodTable methodTable = _methodTables[typeHandle.Address]; - if (methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) != MethodTableFlags_1.WFLAGS_HIGH.Category_Enum) - return false; - - // Check that the internal element type is a valid enum underlying type - CorElementType elementType = (CorElementType)GetClassData(typeHandle).InternalCorElementType; - return elementType == CorElementType.I1 || - elementType == CorElementType.U1 || - elementType == CorElementType.I2 || - elementType == CorElementType.U2 || - elementType == CorElementType.I4 || - elementType == CorElementType.U4 || - elementType == CorElementType.I8 || - elementType == CorElementType.U8; + return methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) == MethodTableFlags_1.WFLAGS_HIGH.Category_Enum; } // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. From d0a71b83ce3e8e2f46d6acae7ce9865502a657da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 14:51:33 +0000 Subject: [PATCH 37/43] Fix JIT assertion for runtime handle types by allowing pointer-sized struct assignment to TYP_I_IMPL locals Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/jit/importer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 84749718f92d18..8508eca8b0f252 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -6814,7 +6814,9 @@ void Compiler::impImportBlockCode(BasicBlock* block) (genActualType(lclTyp) == TYP_I_IMPL && (op1->TypeIs(TYP_BYREF) || op1->TypeIs(TYP_REF))) || (genActualType(op1->gtType) == TYP_I_IMPL && lclTyp == TYP_BYREF) || (varTypeIsFloating(lclTyp) && varTypeIsFloating(op1->TypeGet())) || - ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF)); + ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF) || + (genActualType(lclTyp) == TYP_I_IMPL && op1->TypeIs(TYP_STRUCT) && + info.compCompHnd->getClassSize(op1->GetLayout(this)->GetClassHandle()) == TARGET_POINTER_SIZE)); // If op1 is "&var" then its type is the transient "*" and it can // be used either as BYREF or TYP_I_IMPL. From 51d25a5754e418f7ec34cdadebf227157bce4a87 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 17:54:49 +0000 Subject: [PATCH 38/43] Fix runtime handle types by setting ELEMENT_TYPE_VALUETYPE for non-primitive value types Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d189165d-e317-4787-aa73-4aca2aac012e Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/jit/importer.cpp | 4 +--- src/coreclr/vm/methodtablebuilder.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 8508eca8b0f252..84749718f92d18 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -6814,9 +6814,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) (genActualType(lclTyp) == TYP_I_IMPL && (op1->TypeIs(TYP_BYREF) || op1->TypeIs(TYP_REF))) || (genActualType(op1->gtType) == TYP_I_IMPL && lclTyp == TYP_BYREF) || (varTypeIsFloating(lclTyp) && varTypeIsFloating(op1->TypeGet())) || - ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF) || - (genActualType(lclTyp) == TYP_I_IMPL && op1->TypeIs(TYP_STRUCT) && - info.compCompHnd->getClassSize(op1->GetLayout(this)->GetClassHandle()) == TARGET_POINTER_SIZE)); + ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF)); // If op1 is "&var" then its type is the transient "*" and it can // be used either as BYREF or TYP_I_IMPL. diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index c37e930e31050c..7d1590de5b6154 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -10803,6 +10803,12 @@ void MethodTableBuilder::CheckForSystemTypes() #error Unknown architecture #endif // TARGET_64BIT } + else + { + // For all other value types (including runtime handle types), set ELEMENT_TYPE_VALUETYPE + // to ensure they are correctly categorized as value types rather than reference types. + pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE, false); + } } else { From 1e2f63b00b023e45daad654f99836a9fe6b4a8d9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 18:03:06 +0000 Subject: [PATCH 39/43] Fix runtime handle types by returning CORINFO_TYPE_VALUECLASS from getTypeForPrimitiveValueClass for non-primitive value types Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/jit/importer.cpp | 4 +++- src/coreclr/vm/jitinterface.cpp | 6 ++++++ src/coreclr/vm/methodtablebuilder.cpp | 6 ------ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 84749718f92d18..8508eca8b0f252 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -6814,7 +6814,9 @@ void Compiler::impImportBlockCode(BasicBlock* block) (genActualType(lclTyp) == TYP_I_IMPL && (op1->TypeIs(TYP_BYREF) || op1->TypeIs(TYP_REF))) || (genActualType(op1->gtType) == TYP_I_IMPL && lclTyp == TYP_BYREF) || (varTypeIsFloating(lclTyp) && varTypeIsFloating(op1->TypeGet())) || - ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF)); + ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF) || + (genActualType(lclTyp) == TYP_I_IMPL && op1->TypeIs(TYP_STRUCT) && + info.compCompHnd->getClassSize(op1->GetLayout(this)->GetClassHandle()) == TARGET_POINTER_SIZE)); // If op1 is "&var" then its type is the transient "*" and it can // be used either as BYREF or TYP_I_IMPL. diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 1fb1ea6b39bd7b..1f2db8f5c03daa 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -4065,6 +4065,12 @@ CorInfoType CEEInfo::getTypeForPrimitiveValueClass( { result = asCorInfoType(elementType); } + else if (!th.IsTypeDesc() && th.AsMethodTable()->IsValueType() && !th.AsMethodTable()->IsTruePrimitive()) + { + // For non-primitive value types (e.g., runtime handle types), return CORINFO_TYPE_VALUECLASS + // so the JIT correctly types them as TYP_STRUCT instead of falling back to TYP_I_IMPL + result = CORINFO_TYPE_VALUECLASS; + } EE_TO_JIT_TRANSITION(); return result; diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 7d1590de5b6154..c37e930e31050c 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -10803,12 +10803,6 @@ void MethodTableBuilder::CheckForSystemTypes() #error Unknown architecture #endif // TARGET_64BIT } - else - { - // For all other value types (including runtime handle types), set ELEMENT_TYPE_VALUETYPE - // to ensure they are correctly categorized as value types rather than reference types. - pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE, false); - } } else { From 256d4253ec8f90fbbf54c5fb2419e577db75201e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 18:49:33 +0000 Subject: [PATCH 40/43] Revert assertion relaxation in importer.cpp as the fix in getTypeForPrimitiveValueClass makes it unnecessary Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/cb9f901c-1f24-4b03-b4ca-6dc67f6387ca Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/jit/importer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 8508eca8b0f252..84749718f92d18 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -6814,9 +6814,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) (genActualType(lclTyp) == TYP_I_IMPL && (op1->TypeIs(TYP_BYREF) || op1->TypeIs(TYP_REF))) || (genActualType(op1->gtType) == TYP_I_IMPL && lclTyp == TYP_BYREF) || (varTypeIsFloating(lclTyp) && varTypeIsFloating(op1->TypeGet())) || - ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF) || - (genActualType(lclTyp) == TYP_I_IMPL && op1->TypeIs(TYP_STRUCT) && - info.compCompHnd->getClassSize(op1->GetLayout(this)->GetClassHandle()) == TARGET_POINTER_SIZE)); + ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF)); // If op1 is "&var" then its type is the transient "*" and it can // be used either as BYREF or TYP_I_IMPL. From 7c775d2d1fcae2b47d85e50d953f11ba4dd0fdcd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 20:01:43 +0000 Subject: [PATCH 41/43] Revert getTypeForPrimitiveValueClass change as it causes test failures Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/jitinterface.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 1f2db8f5c03daa..1fb1ea6b39bd7b 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -4065,12 +4065,6 @@ CorInfoType CEEInfo::getTypeForPrimitiveValueClass( { result = asCorInfoType(elementType); } - else if (!th.IsTypeDesc() && th.AsMethodTable()->IsValueType() && !th.AsMethodTable()->IsTruePrimitive()) - { - // For non-primitive value types (e.g., runtime handle types), return CORINFO_TYPE_VALUECLASS - // so the JIT correctly types them as TYP_STRUCT instead of falling back to TYP_I_IMPL - result = CORINFO_TYPE_VALUECLASS; - } EE_TO_JIT_TRANSITION(); return result; From 8cd4494cb6305940e5d76035fa09acb68e07cc73 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 10 May 2026 00:28:07 +0000 Subject: [PATCH 42/43] Handle runtime handle internal types as TYP_I_IMPL in JIT lvaInitVarDsc RuntimeArgumentHandle, RuntimeMethodHandleInternal, and RuntimeFieldHandleInternal are pointer-sized value types that should be treated as native ints (TYP_I_IMPL) rather than structs for JIT purposes. This fix identifies these types by name and treats them specially without calling GetClass() or other struct-specific operations that would fail. Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/jit/lclvars.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 34ad714fc1d2c0..754c5e2ff89002 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -889,7 +889,34 @@ void Compiler::lvaInitVarDsc(LclVarDsc* varDsc, // Set the lvType (before this point it is TYP_UNDEF). if ((varTypeIsStruct(type))) { - lvaSetStruct(varNum, typeHnd, typeHnd != NO_CLASS_HANDLE); + // Special case: Runtime handle internal types (RuntimeArgumentHandle, RuntimeMethodHandleInternal, + // RuntimeFieldHandleInternal) are pointer-sized value types that should be treated as + // native ints (TYP_I_IMPL) rather than structs for JIT purposes. + bool isRuntimeHandleInternalType = false; + if ((typeHnd != NO_CLASS_HANDLE) && (info.compCompHnd->getClassSize(typeHnd) == TARGET_POINTER_SIZE)) + { + const char* namespaceName = nullptr; + const char* className = info.compCompHnd->getClassNameFromMetadata(typeHnd, &namespaceName); + if ((className != nullptr) && (namespaceName != nullptr) && (strcmp(namespaceName, "System") == 0)) + { + if ((strcmp(className, "RuntimeMethodHandleInternal") == 0) || + (strcmp(className, "RuntimeArgumentHandle") == 0) || + (strcmp(className, "RuntimeFieldHandleInternal") == 0)) + { + isRuntimeHandleInternalType = true; + } + } + } + + if (isRuntimeHandleInternalType) + { + // Treat runtime handle internal types as native ints + varDsc->lvType = TYP_I_IMPL; + } + else + { + lvaSetStruct(varNum, typeHnd, typeHnd != NO_CLASS_HANDLE); + } } else { From 09d49781984bd07154979512b5f41d3189e620b8 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sun, 10 May 2026 21:33:59 -0700 Subject: [PATCH 43/43] Revert "Handle runtime handle internal types as TYP_I_IMPL in JIT lvaInitVarDsc" This reverts commit 8cd4494cb6305940e5d76035fa09acb68e07cc73. --- src/coreclr/jit/lclvars.cpp | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 754c5e2ff89002..34ad714fc1d2c0 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -889,34 +889,7 @@ void Compiler::lvaInitVarDsc(LclVarDsc* varDsc, // Set the lvType (before this point it is TYP_UNDEF). if ((varTypeIsStruct(type))) { - // Special case: Runtime handle internal types (RuntimeArgumentHandle, RuntimeMethodHandleInternal, - // RuntimeFieldHandleInternal) are pointer-sized value types that should be treated as - // native ints (TYP_I_IMPL) rather than structs for JIT purposes. - bool isRuntimeHandleInternalType = false; - if ((typeHnd != NO_CLASS_HANDLE) && (info.compCompHnd->getClassSize(typeHnd) == TARGET_POINTER_SIZE)) - { - const char* namespaceName = nullptr; - const char* className = info.compCompHnd->getClassNameFromMetadata(typeHnd, &namespaceName); - if ((className != nullptr) && (namespaceName != nullptr) && (strcmp(namespaceName, "System") == 0)) - { - if ((strcmp(className, "RuntimeMethodHandleInternal") == 0) || - (strcmp(className, "RuntimeArgumentHandle") == 0) || - (strcmp(className, "RuntimeFieldHandleInternal") == 0)) - { - isRuntimeHandleInternalType = true; - } - } - } - - if (isRuntimeHandleInternalType) - { - // Treat runtime handle internal types as native ints - varDsc->lvType = TYP_I_IMPL; - } - else - { - lvaSetStruct(varNum, typeHnd, typeHnd != NO_CLASS_HANDLE); - } + lvaSetStruct(varNum, typeHnd, typeHnd != NO_CLASS_HANDLE); } else {