diff options
author | MichaĆ Petryka <35800402+MichalPetryka@users.noreply.github.com> | 2022-11-11 07:50:14 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-11 07:50:14 +0300 |
commit | 16b28c704108c691c54a73ad845069aac2e3e282 (patch) | |
tree | fee9502f5ebb033771e81f040272b1a2a3505566 | |
parent | 00e6482544b435c66279ffd7abf43e9a7ead0236 (diff) |
Make Type.IsEnum and Type.GetEnumUnderlyingType intrinsics (#71685)
* Make Type.GetTypeCode an intrinsic
Makes Type.GetTypeCode a JIT intrinsic for primitive types,
enums and strings.
Makes Type.IsEnum use intrinsics instead of IsSubclassOf
Makes Enum.GetUnderlyingType use Type.GetTypeCode
Moves the legacy FCall to InternalGetUnderlyingTypeImpl,
so that the non-intrinsic GetTypeCode can use it.
Introduces JIT tests checking the generated codegen.
* Change IsEnum to an intrinsic
* Fallback to the FCall for nint/nuint enums
* Fix compilation
* Add missing Intrinsic
* Add typeof support to IsKnownConstant
* Use gtIsTypeHandleToRuntimeTypeHelper
* Add __reftype tests
* Make more places use gtIsTypeof
* Update EnumTests.cs
* Add impTypeGetTypeCode to the header
* Update EnumGetUnderlyingTypeEnums.il
* Make the IsActualEnum helper an intrinsic
* Remove GetTypeCode intrinsics
* Create a new JIT-EE api, add GetEnumUnderlyingType back
* Optimize GetTypeCode with IsKnownConstant
* Change the code to make the inliner happy
* Handle all types in GetTypeCode
* Check for custom types
* Fix build, do suggested changes
Co-authored-by: Andy Ayers <andya@microsoft.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
42 files changed, 903 insertions, 229 deletions
diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 60416d4dbb7..fdfc88b419e 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -3397,6 +3397,7 @@ namespace System // This returns true for actual enum types only. internal unsafe bool IsActualEnum { + [Intrinsic] get { TypeHandle th = GetNativeTypeHandle(); diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 4958de74967..b4faaf34861 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2270,7 +2270,7 @@ public: //------------------------------------------------------------------------------ // printObjectDescription: Prints a (possibly truncated) textual UTF8 representation of the given - // object to a preallocated buffer. It's intended to be used only for debug/diagnostic + // object to a preallocated buffer. It's intended to be used only for debug/diagnostic // purposes such as JitDisasm. The buffer is null-terminated (even if truncated). // // Arguments: @@ -2635,6 +2635,16 @@ public: CORINFO_CLASS_HANDLE cls2 ) = 0; + // Returns TypeCompareState::Must if cls is known to be an enum. + // For enums with known exact type returns the underlying + // type in underlyingType when the provided pointer is + // non-NULL. + // Returns TypeCompareState::May when a runtime check is required. + virtual TypeCompareState isEnum( + CORINFO_CLASS_HANDLE cls, + CORINFO_CLASS_HANDLE* underlyingType + ) = 0; + // Given a class handle, returns the Parent type. // For COMObjectType, it returns Class Handle of System.Object. // Returns 0 if System.Object is passed in. @@ -2849,7 +2859,7 @@ public: CORINFO_CLASS_HANDLE *vcTypeRet /* OUT */ ) = 0; - // Obtains a list of exact classes for a given base type. Returns 0 if the number of + // Obtains a list of exact classes for a given base type. Returns 0 if the number of // the exact classes is greater than maxExactClasses or if more types might be loaded // in future. virtual int getExactClasses( diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 44c98ae5397..dc05dced40a 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -352,6 +352,10 @@ bool isMoreSpecificType( CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) override; +TypeCompareState isEnum( + CORINFO_CLASS_HANDLE cls, + CORINFO_CLASS_HANDLE* underlyingType) override; + CORINFO_CLASS_HANDLE getParentType( CORINFO_CLASS_HANDLE cls) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 2f1bb07461e..601ba406d83 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 77b6df16-d27f-4118-9dfd-d8073ff20fb6 */ - 0x77b6df16, - 0xd27f, - 0x4118, - {0x9d, 0xfd, 0xd8, 0x7, 0x3f, 0xf2, 0xf, 0xb6} +constexpr GUID JITEEVersionIdentifier = { /* e452af1d-0a1a-44a8-a5b3-ef6074b8ab4a */ + 0xe452af1d, + 0x0a1a, + 0x44a8, + {0xa5, 0xb3, 0xef, 0x60, 0x74, 0xb8, 0xab, 0x4a} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 8c43eb4823a..ed00cc19112 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -88,6 +88,7 @@ DEF_CLR_API(compareTypesForCast) DEF_CLR_API(compareTypesForEquality) DEF_CLR_API(mergeClasses) DEF_CLR_API(isMoreSpecificType) +DEF_CLR_API(isEnum) DEF_CLR_API(getParentType) DEF_CLR_API(getChildType) DEF_CLR_API(satisfiesClassConstraints) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 057f5ba4177..8cedeccd487 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -830,6 +830,16 @@ bool WrapICorJitInfo::isMoreSpecificType( return temp; } +TypeCompareState WrapICorJitInfo::isEnum( + CORINFO_CLASS_HANDLE cls, + CORINFO_CLASS_HANDLE* underlyingType) +{ + API_ENTER(isEnum); + TypeCompareState temp = wrapHnd->isEnum(cls, underlyingType); + API_LEAVE(isEnum); + return temp; +} + CORINFO_CLASS_HANDLE WrapICorJitInfo::getParentType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 068dd098cc4..a1b860ed99c 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -2878,6 +2878,8 @@ public: CORINFO_CLASS_HANDLE gtGetHelperArgClassHandle(GenTree* array); // Get the class handle for a field CORINFO_CLASS_HANDLE gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull); + // Check if this tree is a typeof() + bool gtIsTypeof(GenTree* tree, CORINFO_CLASS_HANDLE* handle = nullptr); GenTree* gtCallGetDefinedRetBufLclAddr(GenTreeCall* call); diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 29f0afa67ea..ea7f8fccd9b 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -1163,6 +1163,8 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed break; // These are foldable if the first argument is a constant + case NI_System_Type_get_IsEnum: + case NI_System_Type_GetEnumUnderlyingType: case NI_System_Type_get_IsValueType: case NI_System_Type_get_IsByRefLike: case NI_System_Type_GetTypeFromHandle: diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 186fcabe5fb..24081df5c38 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18336,6 +18336,42 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH } //------------------------------------------------------------------------ +// gtIsTypeof: Checks if the tree is a typeof() +// +// Arguments: +// tree - the tree that is checked +// handle - (optional, default nullptr) - if non-null is set to the type +// +// Return Value: +// Is the tree typeof() +// +bool Compiler::gtIsTypeof(GenTree* tree, CORINFO_CLASS_HANDLE* handle) +{ + if (tree->IsCall()) + { + GenTreeCall* call = tree->AsCall(); + if (gtIsTypeHandleToRuntimeTypeHelper(call)) + { + assert(call->gtArgs.CountArgs() == 1); + CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(call->gtArgs.GetArgByIndex(0)->GetEarlyNode()); + if (hClass != NO_CLASS_HANDLE) + { + if (handle != nullptr) + { + *handle = hClass; + } + return true; + } + } + } + if (handle != nullptr) + { + *handle = NO_CLASS_HANDLE; + } + return false; +} + +//------------------------------------------------------------------------ // gtCallGetDefinedRetBufLclAddr: // Get the tree corresponding to the address of the retbuf that this call defines. // diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 65fb915f783..19e2c842393 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -2932,37 +2932,24 @@ GenTree* Compiler::impTypeIsAssignable(GenTree* typeTo, GenTree* typeFrom) // // to true/false - if (typeTo->IsCall() && typeFrom->IsCall()) + // make sure both arguments are `typeof()` + CORINFO_CLASS_HANDLE hClassTo = NO_CLASS_HANDLE; + CORINFO_CLASS_HANDLE hClassFrom = NO_CLASS_HANDLE; + if (gtIsTypeof(typeTo, &hClassTo) && gtIsTypeof(typeFrom, &hClassFrom)) { - // make sure both arguments are `typeof()` - CORINFO_METHOD_HANDLE hTypeof = eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE); - if ((typeTo->AsCall()->gtCallMethHnd == hTypeof) && (typeFrom->AsCall()->gtCallMethHnd == hTypeof)) + TypeCompareState castResult = info.compCompHnd->compareTypesForCast(hClassFrom, hClassTo); + if (castResult == TypeCompareState::May) { - assert((typeTo->AsCall()->gtArgs.CountArgs() == 1) && (typeFrom->AsCall()->gtArgs.CountArgs() == 1)); - CORINFO_CLASS_HANDLE hClassTo = - gtGetHelperArgClassHandle(typeTo->AsCall()->gtArgs.GetArgByIndex(0)->GetEarlyNode()); - CORINFO_CLASS_HANDLE hClassFrom = - gtGetHelperArgClassHandle(typeFrom->AsCall()->gtArgs.GetArgByIndex(0)->GetEarlyNode()); - - if (hClassTo == NO_CLASS_HANDLE || hClassFrom == NO_CLASS_HANDLE) - { - return nullptr; - } - - TypeCompareState castResult = info.compCompHnd->compareTypesForCast(hClassFrom, hClassTo); - if (castResult == TypeCompareState::May) - { - // requires runtime check - // e.g. __Canon, COMObjects, Nullable - return nullptr; - } + // requires runtime check + // e.g. __Canon, COMObjects, Nullable + return nullptr; + } - GenTreeIntCon* retNode = gtNewIconNode((castResult == TypeCompareState::Must) ? 1 : 0); - impPopStack(); // drop both CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE calls - impPopStack(); + GenTreeIntCon* retNode = gtNewIconNode((castResult == TypeCompareState::Must) ? 1 : 0); + impPopStack(); // drop both CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE calls + impPopStack(); - return retNode; - } + return retNode; } return nullptr; @@ -13391,15 +13378,10 @@ void Compiler::impInlineRecordArgInfo(InlineInfo* pInlineInfo, return; } } - else + else if (gtIsTypeof(curArgVal)) { - if (curArgVal->IsHelperCall() && gtIsTypeHandleToRuntimeTypeHelper(curArgVal->AsCall()) && - (gtGetHelperArgClassHandle(curArgVal->AsCall()->gtArgs.GetArgByIndex(0)->GetEarlyNode()) != - NO_CLASS_HANDLE)) - { - inlCurArgInfo->argIsInvariant = true; - inlCurArgInfo->argHasSideEff = false; - } + inlCurArgInfo->argIsInvariant = true; + inlCurArgInfo->argHasSideEff = false; } bool isExact = false; diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index a5aa32c1cd7..b2cbc6965f5 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -2587,12 +2587,12 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: { GenTree* op1 = impPopStack().val; - if (op1->OperIsConst()) + if (op1->OperIsConst() || gtIsTypeof(op1)) { // op1 is a known constant, replace with 'true'. retNode = gtNewIconNode(1); JITDUMP("\nExpanding RuntimeHelpers.IsKnownConstant to true early\n"); - // We can also consider FTN_ADDR and typeof(T) here + // We can also consider FTN_ADDR here } else { @@ -2854,6 +2854,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, break; } + case NI_System_Type_get_IsEnum: case NI_System_Type_get_IsValueType: case NI_System_Type_get_IsByRefLike: { @@ -2865,35 +2866,56 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, // to `true` or `false` // e.g., `typeof(int).IsValueType` => `true` // e.g., `typeof(Span<int>).IsByRefLike` => `true` - if (impStackTop().val->IsCall()) + CORINFO_CLASS_HANDLE hClass = NO_CLASS_HANDLE; + if (gtIsTypeof(impStackTop().val, &hClass)) { - GenTreeCall* call = impStackTop().val->AsCall(); - if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE)) + switch (ni) { - assert(call->gtArgs.CountArgs() == 1); - CORINFO_CLASS_HANDLE hClass = - gtGetHelperArgClassHandle(call->gtArgs.GetArgByIndex(0)->GetEarlyNode()); - if (hClass != NO_CLASS_HANDLE) + case NI_System_Type_get_IsEnum: { - switch (ni) + TypeCompareState state = info.compCompHnd->isEnum(hClass, nullptr); + if (state == TypeCompareState::May) { - case NI_System_Type_get_IsValueType: - retNode = gtNewIconNode(eeIsValueClass(hClass) ? 1 : 0); - break; - case NI_System_Type_get_IsByRefLike: - retNode = gtNewIconNode( - (info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_BYREF_LIKE) ? 1 : 0); - break; - default: - NO_WAY("Intrinsic not supported in this path."); + retNode = nullptr; + break; } - impPopStack(); // drop CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE call + retNode = gtNewIconNode(state == TypeCompareState::Must ? 1 : 0); + break; } + case NI_System_Type_get_IsValueType: + retNode = gtNewIconNode(eeIsValueClass(hClass) ? 1 : 0); + break; + case NI_System_Type_get_IsByRefLike: + retNode = gtNewIconNode( + (info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_BYREF_LIKE) ? 1 : 0); + break; + default: + NO_WAY("Intrinsic not supported in this path."); + } + if (retNode != nullptr) + { + impPopStack(); // drop CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE call } } break; } + case NI_System_Type_GetEnumUnderlyingType: + { + GenTree* type = impStackTop().val; + CORINFO_CLASS_HANDLE hClassEnum = NO_CLASS_HANDLE; + CORINFO_CLASS_HANDLE hClassUnderlying = NO_CLASS_HANDLE; + if (gtIsTypeof(type, &hClassEnum) && (hClassEnum != NO_CLASS_HANDLE) && + (info.compCompHnd->isEnum(hClassEnum, &hClassUnderlying) == TypeCompareState::Must) && + (hClassUnderlying != NO_CLASS_HANDLE)) + { + GenTree* handle = gtNewIconEmbClsHndNode(hClassUnderlying); + retNode = gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, handle); + impPopStack(); + } + break; + } + case NI_System_Threading_Thread_get_ManagedThreadId: { if (impStackTop().val->OperIs(GT_RET_EXPR)) @@ -7140,6 +7162,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) result = NI_System_RuntimeTypeHandle_GetValueInternal; } } + else if (strcmp(className, "RuntimeType") == 0) + { + if (strcmp(methodName, "get_IsActualEnum") == 0) + { + result = NI_System_Type_get_IsEnum; + } + } else if (strcmp(className, "Type") == 0) { if (strcmp(methodName, "get_IsValueType") == 0) @@ -7170,6 +7199,14 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Type_GetTypeFromHandle; } + else if (strcmp(methodName, "get_IsEnum") == 0) + { + result = NI_System_Type_get_IsEnum; + } + else if (strcmp(methodName, "GetEnumUnderlyingType") == 0) + { + result = NI_System_Type_GetEnumUnderlyingType; + } } else if (strcmp(className, "String") == 0) { diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 2842b3b3e7d..16b28efe45a 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -11020,7 +11020,7 @@ DONE_MORPHING_CHILDREN: assert(!optValnumCSE_phase); JITDUMP("\nExpanding RuntimeHelpers.IsKnownConstant to "); - if (op1->OperIsConst()) + if (op1->OperIsConst() || gtIsTypeof(op1)) { // We're lucky to catch a constant here while importer was not JITDUMP("true\n"); diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index e33b1f391f6..37af303c0ab 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -60,6 +60,8 @@ enum NamedIntrinsic : unsigned short NI_System_GC_KeepAlive, NI_System_Threading_Thread_get_CurrentThread, NI_System_Threading_Thread_get_ManagedThreadId, + NI_System_Type_get_IsEnum, + NI_System_Type_GetEnumUnderlyingType, NI_System_Type_get_IsValueType, NI_System_Type_get_IsByRefLike, NI_System_Type_IsAssignableFrom, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 62beee1b926..7b1ce731f25 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2753,6 +2753,36 @@ namespace Internal.JitInterface return merged == type1; } + private TypeCompareState isEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) + { + Debug.Assert(cls != null); + + if (underlyingType != null) + { + *underlyingType = null; + } + + TypeDesc type = HandleToObject(cls); + + if (type.IsGenericParameter) + { + return TypeCompareState.May; + } + + if (type.IsEnum) + { + if (underlyingType != null) + { + *underlyingType = ObjectToHandle(type.UnderlyingType); + } + return TypeCompareState.Must; + } + else + { + return TypeCompareState.MustNot; + } + } + private CORINFO_CLASS_STRUCT_* getParentType(CORINFO_CLASS_STRUCT_* cls) { throw new NotImplementedException("getParentType"); } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 4b830673d4a..40218af44e7 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1256,6 +1256,21 @@ namespace Internal.JitInterface } [UnmanagedCallersOnly] + private static TypeCompareState _isEnum(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) + { + var _this = GetThis(thisHandle); + try + { + return _this.isEnum(cls, underlyingType); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + + [UnmanagedCallersOnly] private static CORINFO_CLASS_STRUCT_* _getParentType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) { var _this = GetThis(thisHandle); @@ -2685,7 +2700,7 @@ namespace Internal.JitInterface private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 181); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 182); callbacks[0] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte>)&_isIntrinsic; callbacks[1] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodAttribs; @@ -2771,103 +2786,104 @@ namespace Internal.JitInterface callbacks[81] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForEquality; callbacks[82] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_mergeClasses; callbacks[83] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_isMoreSpecificType; - callbacks[84] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getParentType; - callbacks[85] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoType>)&_getChildType; - callbacks[86] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_satisfiesClassConstraints; - callbacks[87] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isSDArray; - callbacks[88] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getArrayRank; - callbacks[89] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CorInfoArrayIntrinsic>)&_getArrayIntrinsicID; - callbacks[90] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint, void*>)&_getArrayInitializationData; - callbacks[91] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_HELPER_DESC*, CorInfoIsAccessAllowedResult>)&_canAccessClass; - callbacks[92] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte**, byte*>)&_getFieldName; - callbacks[93] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getFieldClass; - callbacks[94] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_**, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getFieldType; - callbacks[95] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint>)&_getFieldOffset; - callbacks[96] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_ACCESS_FLAGS, CORINFO_FIELD_INFO*, void>)&_getFieldInfo; - callbacks[97] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte>)&_isFieldStatic; - callbacks[98] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, int>)&_getArrayOrStringLength; - callbacks[99] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint**, BoundaryTypes*, void>)&_getBoundaries; - callbacks[100] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, OffsetMapping*, void>)&_setBoundaries; - callbacks[101] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, ILVarInfo**, bool*, void>)&_getVars; - callbacks[102] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, NativeVarInfo*, void>)&_setVars; - callbacks[103] = (delegate* unmanaged<IntPtr, IntPtr*, InlineTreeNode*, uint, RichOffsetMapping*, uint, void>)&_reportRichMappings; - callbacks[104] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocateArray; - callbacks[105] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_freeArray; - callbacks[106] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_ARG_LIST_STRUCT_*>)&_getArgNext; - callbacks[107] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoTypeWithMod>)&_getArgType; - callbacks[108] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_CLASS_STRUCT_**, int>)&_getExactClasses; - callbacks[109] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getArgClass; - callbacks[110] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHFAElemType>)&_getHFAType; - callbacks[111] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, HRESULT>)&_GetErrorHRESULT; - callbacks[112] = (delegate* unmanaged<IntPtr, IntPtr*, char*, uint, uint>)&_GetErrorMessage; - callbacks[113] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, int>)&_FilterException; - callbacks[114] = (delegate* unmanaged<IntPtr, IntPtr*, HRESULT, void>)&_ThrowExceptionForJitResult; - callbacks[115] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_HELPER_DESC*, void>)&_ThrowExceptionForHelper; - callbacks[116] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithErrorTrap; - callbacks[117] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithSPMIErrorTrap; - callbacks[118] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_EE_INFO*, void>)&_getEEInfo; - callbacks[119] = (delegate* unmanaged<IntPtr, IntPtr*, char*>)&_getJitTimeLogFilename; - callbacks[120] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, mdToken>)&_getMethodDefFromMethod; - callbacks[121] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte*>)&_getMethodName; - callbacks[122] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte**, byte**, byte*>)&_getMethodNameFromMetadata; - callbacks[123] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodHash; - callbacks[124] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, byte*, UIntPtr, UIntPtr>)&_findNameOfToken; - callbacks[125] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*, byte>)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[126] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getLoongArch64PassStructInRegisterFlags; - callbacks[127] = (delegate* unmanaged<IntPtr, IntPtr*, void**, uint>)&_getThreadTLSIndex; - callbacks[128] = (delegate* unmanaged<IntPtr, IntPtr*, void**, void*>)&_getInlinedCallFrameVptr; - callbacks[129] = (delegate* unmanaged<IntPtr, IntPtr*, void**, int*>)&_getAddrOfCaptureThreadGlobal; - callbacks[130] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, void**, void*>)&_getHelperFtn; - callbacks[131] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, CORINFO_ACCESS_FLAGS, void>)&_getFunctionEntryPoint; - callbacks[132] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, void>)&_getFunctionFixedEntryPoint; - callbacks[133] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, void*>)&_getMethodSync; - callbacks[134] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CorInfoHelpFunc>)&_getLazyStringLiteralHelper; - callbacks[135] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, void**, CORINFO_MODULE_STRUCT_*>)&_embedModuleHandle; - callbacks[136] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, CORINFO_CLASS_STRUCT_*>)&_embedClassHandle; - callbacks[137] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, CORINFO_METHOD_STRUCT_*>)&_embedMethodHandle; - callbacks[138] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, CORINFO_FIELD_STRUCT_*>)&_embedFieldHandle; - callbacks[139] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CORINFO_GENERICHANDLE_RESULT*, void>)&_embedGenericHandle; - callbacks[140] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP_KIND*, void>)&_getLocationOfThisType; - callbacks[141] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, void>)&_getAddressOfPInvokeTarget; - callbacks[142] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, void*>)&_GetCookieForPInvokeCalliSig; - callbacks[143] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetCookieForPInvokeCalliSig; - callbacks[144] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_JUST_MY_CODE_HANDLE_**, CORINFO_JUST_MY_CODE_HANDLE_*>)&_getJustMyCodeHandle; - callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, bool*, void**, bool*, void>)&_GetProfilingHandle; - callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_CALLINFO_FLAGS, CORINFO_CALL_INFO*, void>)&_getCallInfo; - callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canAccessFamily; - callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID; - callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID; - callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress; - callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, byte, byte>)&_getReadonlyStaticFieldValue; - callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass; - callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle; - callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle; - callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral; - callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral; - callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID; - callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency; - callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor; - callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete; - callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers; - callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall; - callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage; - callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall; - callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem; - callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo; - callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo; - callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo; - callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount; - callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo; - callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg; - callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert; - callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError; - callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults; - callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema; - callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite; - callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation; - callbacks[178] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint; - callbacks[179] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture; - callbacks[180] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags; + callbacks[84] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, TypeCompareState>)&_isEnum; + callbacks[85] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getParentType; + callbacks[86] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoType>)&_getChildType; + callbacks[87] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_satisfiesClassConstraints; + callbacks[88] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isSDArray; + callbacks[89] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getArrayRank; + callbacks[90] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CorInfoArrayIntrinsic>)&_getArrayIntrinsicID; + callbacks[91] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint, void*>)&_getArrayInitializationData; + callbacks[92] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_HELPER_DESC*, CorInfoIsAccessAllowedResult>)&_canAccessClass; + callbacks[93] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte**, byte*>)&_getFieldName; + callbacks[94] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getFieldClass; + callbacks[95] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_**, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getFieldType; + callbacks[96] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint>)&_getFieldOffset; + callbacks[97] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_ACCESS_FLAGS, CORINFO_FIELD_INFO*, void>)&_getFieldInfo; + callbacks[98] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte>)&_isFieldStatic; + callbacks[99] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, int>)&_getArrayOrStringLength; + callbacks[100] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint**, BoundaryTypes*, void>)&_getBoundaries; + callbacks[101] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, OffsetMapping*, void>)&_setBoundaries; + callbacks[102] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, ILVarInfo**, bool*, void>)&_getVars; + callbacks[103] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, NativeVarInfo*, void>)&_setVars; + callbacks[104] = (delegate* unmanaged<IntPtr, IntPtr*, InlineTreeNode*, uint, RichOffsetMapping*, uint, void>)&_reportRichMappings; + callbacks[105] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocateArray; + callbacks[106] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_freeArray; + callbacks[107] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_ARG_LIST_STRUCT_*>)&_getArgNext; + callbacks[108] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoTypeWithMod>)&_getArgType; + callbacks[109] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_CLASS_STRUCT_**, int>)&_getExactClasses; + callbacks[110] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getArgClass; + callbacks[111] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHFAElemType>)&_getHFAType; + callbacks[112] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, HRESULT>)&_GetErrorHRESULT; + callbacks[113] = (delegate* unmanaged<IntPtr, IntPtr*, char*, uint, uint>)&_GetErrorMessage; + callbacks[114] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, int>)&_FilterException; + callbacks[115] = (delegate* unmanaged<IntPtr, IntPtr*, HRESULT, void>)&_ThrowExceptionForJitResult; + callbacks[116] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_HELPER_DESC*, void>)&_ThrowExceptionForHelper; + callbacks[117] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithErrorTrap; + callbacks[118] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithSPMIErrorTrap; + callbacks[119] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_EE_INFO*, void>)&_getEEInfo; + callbacks[120] = (delegate* unmanaged<IntPtr, IntPtr*, char*>)&_getJitTimeLogFilename; + callbacks[121] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, mdToken>)&_getMethodDefFromMethod; + callbacks[122] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte*>)&_getMethodName; + callbacks[123] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte**, byte**, byte*>)&_getMethodNameFromMetadata; + callbacks[124] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodHash; + callbacks[125] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, byte*, UIntPtr, UIntPtr>)&_findNameOfToken; + callbacks[126] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*, byte>)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[127] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getLoongArch64PassStructInRegisterFlags; + callbacks[128] = (delegate* unmanaged<IntPtr, IntPtr*, void**, uint>)&_getThreadTLSIndex; + callbacks[129] = (delegate* unmanaged<IntPtr, IntPtr*, void**, void*>)&_getInlinedCallFrameVptr; + callbacks[130] = (delegate* unmanaged<IntPtr, IntPtr*, void**, int*>)&_getAddrOfCaptureThreadGlobal; + callbacks[131] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, void**, void*>)&_getHelperFtn; + callbacks[132] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, CORINFO_ACCESS_FLAGS, void>)&_getFunctionEntryPoint; + callbacks[133] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, void>)&_getFunctionFixedEntryPoint; + callbacks[134] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, void*>)&_getMethodSync; + callbacks[135] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CorInfoHelpFunc>)&_getLazyStringLiteralHelper; + callbacks[136] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, void**, CORINFO_MODULE_STRUCT_*>)&_embedModuleHandle; + callbacks[137] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, CORINFO_CLASS_STRUCT_*>)&_embedClassHandle; + callbacks[138] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, CORINFO_METHOD_STRUCT_*>)&_embedMethodHandle; + callbacks[139] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, CORINFO_FIELD_STRUCT_*>)&_embedFieldHandle; + callbacks[140] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CORINFO_GENERICHANDLE_RESULT*, void>)&_embedGenericHandle; + callbacks[141] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP_KIND*, void>)&_getLocationOfThisType; + callbacks[142] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, void>)&_getAddressOfPInvokeTarget; + callbacks[143] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, void*>)&_GetCookieForPInvokeCalliSig; + callbacks[144] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetCookieForPInvokeCalliSig; + callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_JUST_MY_CODE_HANDLE_**, CORINFO_JUST_MY_CODE_HANDLE_*>)&_getJustMyCodeHandle; + callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, bool*, void**, bool*, void>)&_GetProfilingHandle; + callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_CALLINFO_FLAGS, CORINFO_CALL_INFO*, void>)&_getCallInfo; + callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canAccessFamily; + callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID; + callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID; + callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress; + callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, byte, byte>)&_getReadonlyStaticFieldValue; + callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass; + callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle; + callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle; + callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral; + callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral; + callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID; + callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency; + callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor; + callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete; + callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers; + callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall; + callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage; + callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall; + callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem; + callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo; + callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo; + callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo; + callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount; + callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo; + callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg; + callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert; + callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError; + callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults; + callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema; + callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite; + callbacks[178] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation; + callbacks[179] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint; + callbacks[180] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture; + callbacks[181] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index e120cacc136..d33bea88a4c 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -240,6 +240,7 @@ FUNCTIONS TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) bool isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) + TypeCompareState isEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) CORINFO_CLASS_HANDLE getParentType(CORINFO_CLASS_HANDLE cls) CorInfoType getChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet) bool satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index fb7889cbb9d..4f2f5944d2d 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -95,6 +95,7 @@ struct JitInterfaceCallbacks TypeCompareState (* compareTypesForEquality)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); CORINFO_CLASS_HANDLE (* mergeClasses)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); bool (* isMoreSpecificType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); + TypeCompareState (* isEnum)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType); CORINFO_CLASS_HANDLE (* getParentType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); CorInfoType (* getChildType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet); bool (* satisfiesClassConstraints)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); @@ -1025,6 +1026,16 @@ public: return temp; } + virtual TypeCompareState isEnum( + CORINFO_CLASS_HANDLE cls, + CORINFO_CLASS_HANDLE* underlyingType) +{ + CorInfoExceptionClass* pException = nullptr; + TypeCompareState temp = _callbacks->isEnum(_thisHandle, &pException, cls, underlyingType); + if (pException != nullptr) throw pException; + return temp; +} + virtual CORINFO_CLASS_HANDLE getParentType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index dab1ac0c1a0..588d96884df 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -159,6 +159,7 @@ LWM(IsValidToken, DLD, DWORD) LWM(IsValueClass, DWORDLONG, DWORD) LWM(MergeClasses, DLDL, DWORDLONG) LWM(IsMoreSpecificType, DLDL, DWORD) +LWM(IsEnum, DWORDLONG, DLD) LWM(PInvokeMarshalingRequired, MethodOrSigInfoValue, DWORD) LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, ResolveTokenValue) LWM(ResolveVirtualMethod, Agnostic_ResolveVirtualMethodKey, Agnostic_ResolveVirtualMethodResult) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index c85c3dd823c..cb6db7560e2 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -5911,6 +5911,41 @@ bool MethodContext::repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA return value != 0; } +void MethodContext::recIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType, TypeCompareState result) +{ + if (IsEnum == nullptr) + IsEnum = new LightWeightMap<DWORDLONG, DLD>(); + + DWORDLONG key = CastHandle(cls); + + DLD value; + ZeroMemory(&value, sizeof(value)); + if (underlyingType != nullptr) + value.A = CastHandle(*underlyingType); + else + value.A = 0; + value.B = (DWORD)result; + + IsEnum->Add(key, value); + DEBUG_REC(dmpIsEnum(key, value)); +} +void MethodContext::dmpIsEnum(DWORDLONG key, DLD value) +{ + printf("IsEnum key cls-%016llX, value underlyingType-%016llX result-%u", key, value.A, value.B); +} +TypeCompareState MethodContext::repIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) +{ + DWORDLONG key = CastHandle(cls); + + AssertMapAndKeyExist(IsEnum, key, ": key %016llX", key); + + DLD value = IsEnum->Get(key); + DEBUG_REP(dmpIsEnum(key, value)); + if (underlyingType != nullptr) + *underlyingType = (CORINFO_CLASS_HANDLE)value.A; + return (TypeCompareState)value.B; +} + void MethodContext::recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result) { if (GetCookieForPInvokeCalliSig == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index c3e2fdabfde..184102f757d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -744,6 +744,10 @@ public: void dmpIsMoreSpecificType(DLDL key, DWORD value); bool repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); + void recIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType, TypeCompareState result); + void dmpIsEnum(DWORDLONG key, DLD value); + TypeCompareState repIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType); + void recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result); void dmpGetCookieForPInvokeCalliSig(const GetCookieForPInvokeCalliSigValue& key, DLDL value); LPVOID repGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection); @@ -1154,6 +1158,7 @@ enum mcPackets Packet_IsObjectImmutable = 200, Packet_ExpandRawHandleIntrinsic = 201, Packet_GetArrayOrStringLength = 202, + Packet_IsEnum = 203, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 75d5a6f4374..9e91b15de69 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -968,6 +968,24 @@ bool interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA return temp; } +// Returns TypeCompareState::Must if cls is known to be an enum. +// For enums with known exact type returns the underlying +// type in underlyingType when the provided pointer is +// non-NULL. +// Returns TypeCompareState::May when a runtime check is required. +TypeCompareState interceptor_ICJI::isEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) +{ + mc->cr->AddCall("isEnum"); + CORINFO_CLASS_HANDLE tempUnderlyingType = nullptr; + TypeCompareState temp = original_ICorJitInfo->isEnum(cls, &tempUnderlyingType); + mc->recIsEnum(cls, &tempUnderlyingType, temp); + if (underlyingType != nullptr) + { + *underlyingType = tempUnderlyingType; + } + return temp; +} + // Given a class handle, returns the Parent type. // For COMObjectType, it returns Class Handle of System.Object. // Returns 0 if System.Object is passed in. diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index c9bb221333a..2ecdf378351 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -679,6 +679,14 @@ bool interceptor_ICJI::isMoreSpecificType( return original_ICorJitInfo->isMoreSpecificType(cls1, cls2); } +TypeCompareState interceptor_ICJI::isEnum( + CORINFO_CLASS_HANDLE cls, + CORINFO_CLASS_HANDLE* underlyingType) +{ + mcs->AddCall("isEnum"); + return original_ICorJitInfo->isEnum(cls, underlyingType); +} + CORINFO_CLASS_HANDLE interceptor_ICJI::getParentType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 6f5367b1fbf..1e0593ec325 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -595,6 +595,13 @@ bool interceptor_ICJI::isMoreSpecificType( return original_ICorJitInfo->isMoreSpecificType(cls1, cls2); } +TypeCompareState interceptor_ICJI::isEnum( + CORINFO_CLASS_HANDLE cls, + CORINFO_CLASS_HANDLE* underlyingType) +{ + return original_ICorJitInfo->isEnum(cls, underlyingType); +} + CORINFO_CLASS_HANDLE interceptor_ICJI::getParentType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index cebb456c7af..a86f7d27184 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -819,6 +819,17 @@ bool MyICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE return jitInstance->mc->repIsMoreSpecificType(cls1, cls2); } +// Returns TypeCompareState::Must if cls is known to be an enum. +// For enums with known exact type returns the underlying +// type in underlyingType when the provided pointer is +// non-NULL. +// Returns TypeCompareState::May when a runtime check is required. +TypeCompareState MyICJI::isEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) +{ + jitInstance->mc->cr->AddCall("isEnum"); + return jitInstance->mc->repIsEnum(cls, underlyingType); +} + // Given a class handle, returns the Parent type. // For COMObjectType, it returns Class Handle of System.Object. // Returns 0 if System.Object is passed in. diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 3d0012cbd41..9c8d9cbe59c 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -4529,6 +4529,57 @@ bool CEEInfo::isMoreSpecificType( } /*********************************************************************/ +// Returns TypeCompareState::Must if cls is known to be an enum. +// For enums with known exact type returns the underlying +// type in underlyingType when the provided pointer is +// non-NULL. +// Returns TypeCompareState::May when a runtime check is required. +TypeCompareState CEEInfo::isEnum( + CORINFO_CLASS_HANDLE cls, + CORINFO_CLASS_HANDLE* underlyingType) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + TypeCompareState result = TypeCompareState::May; + + if (underlyingType != nullptr) + { + *underlyingType = nullptr; + } + + JIT_TO_EE_TRANSITION_LEAF(); + + TypeHandle th(cls); + + _ASSERTE(!th.IsNull()); + + if (!th.IsGenericVariable()) + { + if (!th.IsTypeDesc() && th.AsMethodTable()->IsEnum()) + { + result = TypeCompareState::Must; + if (underlyingType != nullptr) + { + CorElementType elemType = th.AsMethodTable()->GetInternalCorElementType(); + TypeHandle underlyingHandle(CoreLibBinder::GetElementType(elemType)); + *underlyingType = CORINFO_CLASS_HANDLE(underlyingHandle.AsPtr()); + } + } + else + { + result = TypeCompareState::MustNot; + } + } + + EE_TO_JIT_TRANSITION_LEAF(); + return result; +} + +/*********************************************************************/ // Given a class handle, returns the Parent type. // For COMObjectType, it returns Class Handle of System.Object. // Returns 0 if System.Object is passed in. diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs index fbee608bbf4..aedbfa953bf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs @@ -243,7 +243,7 @@ namespace System.Collections.Generic public void GetObjectData(SerializationInfo info, StreamingContext context) { // For back-compat we need to serialize the comparers for enums with underlying types other than int as ObjectEqualityComparer - if (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))) != TypeCode.Int32) + if (Type.GetTypeCode(typeof(T)) != TypeCode.Int32) { info.SetType(typeof(ObjectEqualityComparer<T>)); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index 5b52162fa14..47014ec5d71 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -104,6 +104,9 @@ namespace System.Runtime.CompilerServices // Feel free to add more overloads on demand #pragma warning disable IDE0060 [Intrinsic] + internal static bool IsKnownConstant(Type? t) => false; + + [Intrinsic] internal static bool IsKnownConstant(string? t) => false; [Intrinsic] diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index d4b45f21bc9..7472df80e99 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -267,66 +267,7 @@ namespace System if (typeCode != TypeCode.Empty) return typeCode; - CorElementType corElementType = RuntimeTypeHandle.GetCorElementType(this); - switch (corElementType) - { - case CorElementType.ELEMENT_TYPE_BOOLEAN: - typeCode = TypeCode.Boolean; break; - case CorElementType.ELEMENT_TYPE_CHAR: - typeCode = TypeCode.Char; break; - case CorElementType.ELEMENT_TYPE_I1: - typeCode = TypeCode.SByte; break; - case CorElementType.ELEMENT_TYPE_U1: - typeCode = TypeCode.Byte; break; - case CorElementType.ELEMENT_TYPE_I2: - typeCode = TypeCode.Int16; break; - case CorElementType.ELEMENT_TYPE_U2: - typeCode = TypeCode.UInt16; break; - case CorElementType.ELEMENT_TYPE_I4: - typeCode = TypeCode.Int32; break; - case CorElementType.ELEMENT_TYPE_U4: - typeCode = TypeCode.UInt32; break; - case CorElementType.ELEMENT_TYPE_I8: - typeCode = TypeCode.Int64; break; - case CorElementType.ELEMENT_TYPE_U8: - typeCode = TypeCode.UInt64; break; - case CorElementType.ELEMENT_TYPE_R4: - typeCode = TypeCode.Single; break; - case CorElementType.ELEMENT_TYPE_R8: - typeCode = TypeCode.Double; break; -#if !CORECLR - case CorElementType.ELEMENT_TYPE_STRING: - typeCode = TypeCode.String; break; -#endif - case CorElementType.ELEMENT_TYPE_VALUETYPE: - if (ReferenceEquals(this, typeof(decimal))) - typeCode = TypeCode.Decimal; - else if (ReferenceEquals(this, typeof(DateTime))) - typeCode = TypeCode.DateTime; - else if (IsActualEnum) - typeCode = GetTypeCode(Enum.InternalGetUnderlyingType(this)); - else - typeCode = TypeCode.Object; - break; - default: -#if CORECLR - // GetSignatureCorElementType returns E_T_CLASS for E_T_STRING - if (ReferenceEquals(this, typeof(string))) - { - typeCode = TypeCode.String; - break; - } -#endif - if (ReferenceEquals(this, typeof(DBNull))) - { - typeCode = TypeCode.DBNull; - break; - } - - typeCode = TypeCode.Object; - break; - } - + typeCode = Type.GetRuntimeTypeCode(this); Cache.TypeCode = typeCode; return typeCode; diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index 5a7ebed457d..0ab6e955e37 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -104,7 +104,7 @@ namespace System public bool IsContextful => IsContextfulImpl(); protected virtual bool IsContextfulImpl() => false; - public virtual bool IsEnum => IsSubclassOf(typeof(Enum)); + public virtual bool IsEnum { [Intrinsic] get => IsSubclassOf(typeof(Enum)); } public bool IsMarshalByRef => IsMarshalByRefImpl(); protected virtual bool IsMarshalByRefImpl() => false; public bool IsPrimitive => IsPrimitiveImpl(); @@ -438,11 +438,59 @@ namespace System return cls; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TypeCode GetTypeCode(Type? type) { + if (RuntimeHelpers.IsKnownConstant(type) && type is RuntimeType) + { + return GetRuntimeTypeCode((RuntimeType)type); + } return type?.GetTypeCodeImpl() ?? TypeCode.Empty; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static TypeCode GetRuntimeTypeCode(RuntimeType type) + { + RuntimeType underlyingType = type; + if (type.IsActualEnum) + underlyingType = (RuntimeType)type.GetEnumUnderlyingType(); + + if (underlyingType == typeof(sbyte)) + return TypeCode.SByte; + else if (underlyingType == typeof(byte)) + return TypeCode.Byte; + else if (underlyingType == typeof(short)) + return TypeCode.Int16; + else if (underlyingType == typeof(ushort)) + return TypeCode.UInt16; + else if (underlyingType == typeof(int)) + return TypeCode.Int32; + else if (underlyingType == typeof(uint)) + return TypeCode.UInt32; + else if (underlyingType == typeof(long)) + return TypeCode.Int64; + else if (underlyingType == typeof(ulong)) + return TypeCode.UInt64; + else if (underlyingType == typeof(bool)) + return TypeCode.Boolean; + else if (underlyingType == typeof(char)) + return TypeCode.Char; + else if (underlyingType == typeof(float)) + return TypeCode.Single; + else if (underlyingType == typeof(double)) + return TypeCode.Double; + else if (underlyingType == typeof(decimal)) + return TypeCode.Decimal; + else if (underlyingType == typeof(DateTime)) + return TypeCode.DateTime; + else if (underlyingType == typeof(string)) + return TypeCode.String; + else if (underlyingType == typeof(DBNull)) + return TypeCode.DBNull; + else + return TypeCode.Object; + } + protected virtual TypeCode GetTypeCodeImpl() { Type systemType = UnderlyingSystemType; @@ -503,6 +551,7 @@ namespace System [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2085:UnrecognizedReflectionPattern", Justification = "The single instance field on enum types is never trimmed")] + [Intrinsic] public virtual Type GetEnumUnderlyingType() { if (!IsEnum) diff --git a/src/libraries/System.Runtime/tests/System/EnumTests.cs b/src/libraries/System.Runtime/tests/System/EnumTests.cs index a243e6c7c8b..a4cbc4a52ac 100644 --- a/src/libraries/System.Runtime/tests/System/EnumTests.cs +++ b/src/libraries/System.Runtime/tests/System/EnumTests.cs @@ -464,7 +464,7 @@ namespace System.Tests yield return new object[] { (char)2, "Value2" }; yield return new object[] { (char)4, null }; } - + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] [MemberData(nameof(GetName_CharEnum_TestData))] public void GetName_InvokeCharEnum_ReturnsExpected(object value, string expected) @@ -479,7 +479,7 @@ namespace System.Tests yield return new object[] { true, "Value1" }; yield return new object[] { false, "Value2" }; } - + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] [MemberData(nameof(GetName_BoolEnum_TestData))] public void GetName_InvokeBoolEnum_ReturnsExpected(object value, string expected) @@ -1443,7 +1443,7 @@ namespace System.Tests { AssertExtensions.Throws<ArgumentNullException>("enumType", () => Enum.GetNames(null)); } - + [Theory] [InlineData(typeof(object))] [InlineData(typeof(int))] diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsics.GetEnumUnderlyingType.cs b/src/tests/JIT/Intrinsics/TypeIntrinsics.GetEnumUnderlyingType.cs new file mode 100644 index 00000000000..93142921f1d --- /dev/null +++ b/src/tests/JIT/Intrinsics/TypeIntrinsics.GetEnumUnderlyingType.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +public class GetEnumUnderlyingType +{ + public static void TestGetEnumUnderlyingType() + { + AssertEquals(typeof(sbyte), typeof(SByteEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(byte), typeof(ByteEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(short), typeof(ShortEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(ushort), typeof(UShortEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(int), typeof(IntEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(uint), typeof(UIntEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(long), typeof(LongEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(ulong), typeof(ULongEnum).GetEnumUnderlyingType()); + + AssertEquals(typeof(char), typeof(CharEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(bool), typeof(BoolEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(float), typeof(FloatEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(double), typeof(DoubleEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(nint), typeof(IntPtrEnum).GetEnumUnderlyingType()); + AssertEquals(typeof(nuint), typeof(UIntPtrEnum).GetEnumUnderlyingType()); + + AssertThrowsArgumentException(() => typeof(int).GetEnumUnderlyingType()); + AssertThrowsArgumentException(() => typeof(nint).GetEnumUnderlyingType()); + AssertThrowsArgumentException(() => typeof(Enum).GetEnumUnderlyingType()); + AssertThrowsArgumentException(() => typeof(object).GetEnumUnderlyingType()); + AssertThrowsNullReferenceException(() => ((Type)null).GetEnumUnderlyingType()); + + AssertEquals(typeof(sbyte), NoInline(typeof(SByteEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(byte), NoInline(typeof(ByteEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(short), NoInline(typeof(ShortEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(ushort), NoInline(typeof(UShortEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(int), NoInline(typeof(IntEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(uint), NoInline(typeof(UIntEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(long), NoInline(typeof(LongEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(ulong), NoInline(typeof(ULongEnum).GetEnumUnderlyingType())); + + AssertEquals(typeof(char), NoInline(typeof(CharEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(bool), NoInline(typeof(BoolEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(float), NoInline(typeof(FloatEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(double), NoInline(typeof(DoubleEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(nint), NoInline(typeof(IntPtrEnum).GetEnumUnderlyingType())); + AssertEquals(typeof(nuint), NoInline(typeof(UIntPtrEnum).GetEnumUnderlyingType())); + + AssertThrowsArgumentException(() => NoInline(typeof(int).GetEnumUnderlyingType())); + AssertThrowsArgumentException(() => NoInline(typeof(nint).GetEnumUnderlyingType())); + AssertThrowsArgumentException(() => NoInline(typeof(Enum).GetEnumUnderlyingType())); + AssertThrowsArgumentException(() => NoInline(typeof(object).GetEnumUnderlyingType())); + AssertThrowsNullReferenceException(() => NoInline(null).GetEnumUnderlyingType()); + + AssertThrowsArgumentException(() => typeof(GenericEnumClass<>).GetGenericArguments()[0].GetEnumUnderlyingType()); + } + + public enum SByteEnum : sbyte {} + public enum ByteEnum : byte {} + public enum ShortEnum : short {} + public enum UShortEnum : ushort {} + public enum IntEnum {} + public enum UIntEnum : uint {} + public enum LongEnum : long {} + public enum ULongEnum : ulong {} + + public class GenericEnumClass<T> where T : Enum + { + public T field; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Type NoInline(Type type) => type; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void AssertEquals(Type expected, Type actual, [CallerLineNumber] int l = 0) + { + if (expected != actual) + throw new InvalidOperationException($"Invalid type, expected {expected.FullName}, got {actual.FullName} at line {l}"); + } + + private static void AssertThrowsArgumentException(Action a, [CallerLineNumber] int l = 0) + { + try + { + a(); + } + catch (ArgumentException) + { + return; + } + throw new InvalidOperationException($"Expected ArgumentException at line {l}"); + } + + private static void AssertThrowsNullReferenceException(Action a, [CallerLineNumber] int l = 0) + { + try + { + a(); + } + catch (NullReferenceException) + { + return; + } + throw new InvalidOperationException($"Expected NullReferenceException at line {l}"); + } +} diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableFrom.cs b/src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableFrom.cs index d6520d30f9b..706cae6a8e8 100644 --- a/src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableFrom.cs +++ b/src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableFrom.cs @@ -71,7 +71,7 @@ public partial class Program IsFalse(typeof(float).IsAssignableFrom(typeof(SimpleEnum_uint))); IsFalse(typeof(SimpleEnum_uint).IsAssignableFrom(typeof(ValueType))); - // Covariance/Contravariance + // Covariance/Contravariance IsTrue (typeof(IEnumerable<object>).IsAssignableFrom(typeof(List<string>))); IsTrue (typeof(IEnumerable<ClassA>).IsAssignableFrom(typeof(List<ClassB>))); IsTrue (typeof(IEnumerable<ClassA>).IsAssignableFrom(typeof(IList<ClassB>))); @@ -166,6 +166,20 @@ public partial class Program IsFalse(typeof(Vector128<float>).IsAssignableFrom(typeof(Vector<float>))); IsFalse(typeof(Vector256<float>).IsAssignableFrom(typeof(Vector<float>))); + // null type + IsFalse(typeof(int).IsAssignableFrom(null)); + IsFalse(typeof(object).IsAssignableFrom(null)); + ThrowsNRE(() => { _ = ((Type)null).IsAssignableFrom(typeof(int)); }); + ThrowsNRE(() => { _ = ((Type)null).IsAssignableFrom(typeof(object)); }); + ThrowsNRE(() => { _ = ((Type)null).IsAssignableFrom(null); }); + ThrowsNRE(() => { _ = ((Type)null).IsAssignableFrom(null); }); + IsFalse(typeof(int).IsAssignableFrom(__reftype(default))); + IsFalse(typeof(object).IsAssignableFrom(__reftype(default))); + ThrowsNRE(() => { _ = __reftype(default).IsAssignableFrom(typeof(int)); }); + ThrowsNRE(() => { _ = __reftype(default).IsAssignableFrom(typeof(object)); }); + ThrowsNRE(() => { _ = __reftype(default).IsAssignableFrom(__reftype(default)); }); + ThrowsNRE(() => { _ = __reftype(default).IsAssignableFrom(__reftype(default)); }); + // System.__Canon IsTrue (IsAssignableFrom<KeyValuePair<IDisposable, IDisposable>, KeyValuePair<IDisposable, IDisposable>>()); IsTrue (IsAssignableFrom<KeyValuePair<IDisposable, object>, KeyValuePair<IDisposable, object>>()); diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableTo.cs b/src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableTo.cs index 6a7ccc73e36..d5bb363d8e2 100644 --- a/src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableTo.cs +++ b/src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableTo.cs @@ -71,7 +71,7 @@ public partial class Program IsFalse(typeof(SimpleEnum_uint).IsAssignableTo(typeof(float))); IsFalse(typeof(ValueType).IsAssignableTo(typeof(SimpleEnum_uint))); - // Covariance/Contravariance + // Covariance/Contravariance IsTrue (typeof(List<string>).IsAssignableTo(typeof(IEnumerable<object>))); IsTrue (typeof(List<ClassB>).IsAssignableTo(typeof(IEnumerable<ClassA>))); IsTrue (typeof(IList<ClassB>).IsAssignableTo(typeof(IEnumerable<ClassA>))); @@ -166,6 +166,20 @@ public partial class Program IsFalse(typeof(Vector<float>).IsAssignableTo(typeof(Vector128<float>))); IsFalse(typeof(Vector<float>).IsAssignableTo(typeof(Vector256<float>))); + // null type + IsFalse(typeof(int).IsAssignableTo(null)); + IsFalse(typeof(object).IsAssignableTo(null)); + ThrowsNRE(() => { _ = ((Type)null).IsAssignableTo(typeof(int)); }); + ThrowsNRE(() => { _ = ((Type)null).IsAssignableTo(typeof(object)); }); + ThrowsNRE(() => { _ = ((Type)null).IsAssignableTo(null); }); + ThrowsNRE(() => { _ = ((Type)null).IsAssignableTo(null); }); + IsFalse(typeof(int).IsAssignableTo(__reftype(default))); + IsFalse(typeof(object).IsAssignableTo(__reftype(default))); + ThrowsNRE(() => { _ = __reftype(default).IsAssignableTo(typeof(int)); }); + ThrowsNRE(() => { _ = __reftype(default).IsAssignableTo(typeof(object)); }); + ThrowsNRE(() => { _ = __reftype(default).IsAssignableTo(__reftype(default)); }); + ThrowsNRE(() => { _ = __reftype(default).IsAssignableTo(__reftype(default)); }); + // System.__Canon IsTrue (IsAssignableTo<KeyValuePair<IDisposable, IDisposable>, KeyValuePair<IDisposable, IDisposable>>()); IsTrue (IsAssignableTo<KeyValuePair<IDisposable, object>, KeyValuePair<IDisposable, object>>()); diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsics.cs b/src/tests/JIT/Intrinsics/TypeIntrinsics.cs index 0c91318abb3..d5a99d7392f 100644 --- a/src/tests/JIT/Intrinsics/TypeIntrinsics.cs +++ b/src/tests/JIT/Intrinsics/TypeIntrinsics.cs @@ -92,12 +92,43 @@ public partial class Program IsTrue (IsValueTypeRef(ref _varGenericStructStr)); IsTrue (IsValueTypeRef(ref _varEnum)); + // test __reftype + IsTrue (__reftype(__makeref(_varInt)).IsValueType); + IsFalse(__reftype(__makeref(_varObject)).IsValueType); + ThrowsNRE(() => { IsValueType(_varNullableIntNull); }); ThrowsNRE(() => { IsValueType(_varStringNull); }); ThrowsNRE(() => { IsValueTypeRef(ref _varNullableIntNull); }); ThrowsNRE(() => { IsValueTypeRef(ref _varStringNull); }); + ThrowsNRE(() => { _ = Type.GetTypeFromHandle(default).IsValueType; }); + ThrowsNRE(() => { _ = Type.GetTypeFromHandle(new RuntimeTypeHandle()).IsValueType; }); + ThrowsNRE(() => { _ = __reftype(default).IsValueType; }); TestIsAssignableFrom(); + TestIsAssignableTo(); + + IsFalse(typeof(byte).IsEnum); + IsFalse(typeof(int).IsEnum); + IsFalse(typeof(int?).IsEnum); + IsFalse(typeof(int*).IsEnum); + IsFalse(typeof(nint).IsEnum); + IsFalse(typeof(void).IsEnum); + IsFalse(typeof(object).IsEnum); + IsFalse(typeof(Enum).IsEnum); + IsFalse(typeof(ValueType).IsEnum); + IsFalse(typeof(GenericStruct<int>).IsEnum); + IsFalse(typeof(SimpleStruct).IsEnum); + IsTrue (typeof(SimpleEnum).IsEnum); + IsTrue (typeof(CharEnum).IsEnum); + IsTrue (typeof(BoolEnum).IsEnum); + IsTrue (typeof(FloatEnum).IsEnum); + IsTrue (typeof(DoubleEnum).IsEnum); + IsTrue (typeof(IntPtrEnum).IsEnum); + IsTrue (typeof(UIntPtrEnum).IsEnum); + + IsTrue(typeof(GenericEnumClass<>).GetGenericArguments()[0].IsEnum); + + GetEnumUnderlyingType.TestGetEnumUnderlyingType(); return 100 + _errors; } @@ -135,7 +166,6 @@ public partial class Program [MethodImpl(MethodImplOptions.NoInlining)] private static dynamic CreateDynamic2() => new { Name = "Test" }; - static void IsTrue(bool expression, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "") { if (!expression) @@ -169,14 +199,25 @@ public partial class Program Console.WriteLine($"{file}:L{line} {exc}"); } Console.WriteLine($"Line {line}: test failed (expected: NullReferenceException)"); + _errors++; } } +public class GenericEnumClass<T> where T : Enum +{ + public T field; +} + public struct GenericStruct<T> { public T field; } +public struct SimpleStruct +{ + public int field; +} + public enum SimpleEnum { A,B,C diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsicsEnums.il b/src/tests/JIT/Intrinsics/TypeIntrinsicsEnums.il new file mode 100644 index 00000000000..36f9f07dd8f --- /dev/null +++ b/src/tests/JIT/Intrinsics/TypeIntrinsicsEnums.il @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) } + +.assembly TypeIntrinsicsEnums { } + +.class public auto ansi sealed CharEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname char value__ +} // end of class CharEnum + +.class public auto ansi sealed BoolEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname bool value__ +} // end of class BoolEnum + +.class public auto ansi sealed FloatEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname float32 value__ +} // end of class FloatEnum + +.class public auto ansi sealed DoubleEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname float64 value__ +} // end of class DoubleEnum + +.class public auto ansi sealed IntPtrEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname native int value__ +} // end of class IntPtrEnum + +.class public auto ansi sealed UIntPtrEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname native uint value__ +} // end of class UIntPtrEnum diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsicsEnums.ilproj b/src/tests/JIT/Intrinsics/TypeIntrinsicsEnums.ilproj new file mode 100644 index 00000000000..05fbf28a4e3 --- /dev/null +++ b/src/tests/JIT/Intrinsics/TypeIntrinsicsEnums.ilproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk.IL"> + <PropertyGroup> + <OutputType>Library</OutputType> + <RestorePackages>true</RestorePackages> + <CLRTestKind>BuildOnly</CLRTestKind> + <GenerateRunScript>false</GenerateRunScript> + </PropertyGroup> + <ItemGroup> + <Compile Include="$(MSBuildProjectName).il" /> + </ItemGroup> +</Project> diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsics_r.csproj b/src/tests/JIT/Intrinsics/TypeIntrinsics_r.csproj index 9ee21d6e902..8a556ce073a 100644 --- a/src/tests/JIT/Intrinsics/TypeIntrinsics_r.csproj +++ b/src/tests/JIT/Intrinsics/TypeIntrinsics_r.csproj @@ -5,8 +5,12 @@ <Optimize /> </PropertyGroup> <ItemGroup> + <ProjectReference Include="TypeIntrinsicsEnums.ilproj" /> + </ItemGroup> + <ItemGroup> <Compile Include="TypeIntrinsics.cs" /> <Compile Include="TypeIntrinsics.IsAssignableFrom.cs" /> <Compile Include="TypeIntrinsics.IsAssignableTo.cs" /> + <Compile Include="TypeIntrinsics.GetEnumUnderlyingType.cs" /> </ItemGroup> </Project> diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsics_ro.csproj b/src/tests/JIT/Intrinsics/TypeIntrinsics_ro.csproj index d752cddd2a0..4b1c9895780 100644 --- a/src/tests/JIT/Intrinsics/TypeIntrinsics_ro.csproj +++ b/src/tests/JIT/Intrinsics/TypeIntrinsics_ro.csproj @@ -5,8 +5,12 @@ <Optimize>True</Optimize> </PropertyGroup> <ItemGroup> + <ProjectReference Include="TypeIntrinsicsEnums.ilproj" /> + </ItemGroup> + <ItemGroup> <Compile Include="TypeIntrinsics.cs" /> <Compile Include="TypeIntrinsics.IsAssignableFrom.cs" /> <Compile Include="TypeIntrinsics.IsAssignableTo.cs" /> + <Compile Include="TypeIntrinsics.GetEnumUnderlyingType.cs" /> </ItemGroup> </Project> diff --git a/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCode.cs b/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCode.cs new file mode 100644 index 00000000000..d27b6630120 --- /dev/null +++ b/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCode.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; + +public class Program +{ + public static int Main() + { + AreSame(Type.GetTypeCode(null), TypeCode.Empty); + AreSame(Type.GetTypeCode(typeof(void*)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(nint)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(nuint)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(IntPtr)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(UIntPtr)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(bool)), TypeCode.Boolean); + AreSame(Type.GetTypeCode(typeof(char)), TypeCode.Char); + AreSame(Type.GetTypeCode(typeof(sbyte)), TypeCode.SByte); + AreSame(Type.GetTypeCode(typeof(byte)), TypeCode.Byte); + AreSame(Type.GetTypeCode(typeof(short)), TypeCode.Int16); + AreSame(Type.GetTypeCode(typeof(ushort)), TypeCode.UInt16); + AreSame(Type.GetTypeCode(typeof(int)), TypeCode.Int32); + AreSame(Type.GetTypeCode(typeof(uint)), TypeCode.UInt32); + AreSame(Type.GetTypeCode(typeof(long)), TypeCode.Int64); + AreSame(Type.GetTypeCode(typeof(ulong)), TypeCode.UInt64); + AreSame(Type.GetTypeCode(typeof(float)), TypeCode.Single); + AreSame(Type.GetTypeCode(typeof(double)), TypeCode.Double); + AreSame(Type.GetTypeCode(typeof(decimal)), TypeCode.Decimal); + AreSame(Type.GetTypeCode(typeof(string)), TypeCode.String); + AreSame(Type.GetTypeCode(typeof(object)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(DateTime)), TypeCode.DateTime); + + AreSame(Type.GetTypeCode(typeof(GenericEnumClass<>)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(GenericEnumClass<IntEnum>)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(GenericEnumClass<>).GetGenericArguments()[0]), TypeCode.Object); + + AreSame(Type.GetTypeCode(typeof(SByteEnum)), TypeCode.SByte); + AreSame(Type.GetTypeCode(typeof(ByteEnum)), TypeCode.Byte); + AreSame(Type.GetTypeCode(typeof(ShortEnum)), TypeCode.Int16); + AreSame(Type.GetTypeCode(typeof(UShortEnum)), TypeCode.UInt16); + AreSame(Type.GetTypeCode(typeof(IntEnum)), TypeCode.Int32); + AreSame(Type.GetTypeCode(typeof(UIntEnum)), TypeCode.UInt32); + AreSame(Type.GetTypeCode(typeof(LongEnum)), TypeCode.Int64); + AreSame(Type.GetTypeCode(typeof(ULongEnum)), TypeCode.UInt64); + + AreSame(Type.GetTypeCode(typeof(CharEnum)), TypeCode.Char); + AreSame(Type.GetTypeCode(typeof(BoolEnum)), TypeCode.Boolean); + AreSame(Type.GetTypeCode(typeof(FloatEnum)), TypeCode.Single); + AreSame(Type.GetTypeCode(typeof(DoubleEnum)), TypeCode.Double); + AreSame(Type.GetTypeCode(typeof(IntPtrEnum)), TypeCode.Object); + AreSame(Type.GetTypeCode(typeof(UIntPtrEnum)), TypeCode.Object); + + AreSame(Type.GetTypeCode(NoInline(typeof(string))), TypeCode.String); + AreSame(Type.GetTypeCode(NoInline(typeof(int))), TypeCode.Int32); + AreSame(Type.GetTypeCode(NoInline(typeof(IntEnum))), TypeCode.Int32); + AreSame(Type.GetTypeCode(NoInline(typeof(CharEnum))), TypeCode.Char); + AreSame(Type.GetTypeCode(NoInline(typeof(IntPtrEnum))), TypeCode.Object); + + AreSame(Type.GetTypeCode(__reftype(__makeref(_varInt))), TypeCode.Int32); + AreSame(Type.GetTypeCode(__reftype(__makeref(_varObject))), TypeCode.Object); + + return 100; + } + + private static int _varInt = 42; + private static object _varObject = new object(); + + public enum SByteEnum : sbyte {} + public enum ByteEnum : byte {} + public enum ShortEnum : short {} + public enum UShortEnum : ushort {} + public enum IntEnum {} + public enum UIntEnum : uint {} + public enum LongEnum : long {} + public enum ULongEnum : ulong {} + + public class GenericEnumClass<T> where T : Enum + { + public T field; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Type NoInline(Type type) => type; + + [MethodImpl(MethodImplOptions.NoInlining)] + static void AreSame(TypeCode a, TypeCode b, [CallerLineNumber] int line = 0) + { + if (a != b) + { + throw new InvalidOperationException($"Invalid TypeCode, expected {b}, got {a} at line {line}"); + } + } +} diff --git a/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCode.csproj b/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCode.csproj new file mode 100644 index 00000000000..5d3631a5de7 --- /dev/null +++ b/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCode.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <OutputType>Exe</OutputType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <ProjectReference Include="$(MSBuildProjectName)Enums.ilproj" /> + </ItemGroup> + <ItemGroup> + <Compile Include="$(MSBuildProjectName).cs" /> + </ItemGroup> +</Project> diff --git a/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCodeEnums.il b/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCodeEnums.il new file mode 100644 index 00000000000..6a46fa0efec --- /dev/null +++ b/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCodeEnums.il @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) } + +.assembly TypeGetTypeCodeEnums { } + +.class public auto ansi sealed CharEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname char value__ +} // end of class CharEnum + +.class public auto ansi sealed BoolEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname bool value__ +} // end of class BoolEnum + +.class public auto ansi sealed FloatEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname float32 value__ +} // end of class FloatEnum + +.class public auto ansi sealed DoubleEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname float64 value__ +} // end of class DoubleEnum + +.class public auto ansi sealed IntPtrEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname native int value__ +} // end of class IntPtrEnum + +.class public auto ansi sealed UIntPtrEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname native uint value__ +} // end of class UIntPtrEnum diff --git a/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCodeEnums.ilproj b/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCodeEnums.ilproj new file mode 100644 index 00000000000..05fbf28a4e3 --- /dev/null +++ b/src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCodeEnums.ilproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk.IL"> + <PropertyGroup> + <OutputType>Library</OutputType> + <RestorePackages>true</RestorePackages> + <CLRTestKind>BuildOnly</CLRTestKind> + <GenerateRunScript>false</GenerateRunScript> + </PropertyGroup> + <ItemGroup> + <Compile Include="$(MSBuildProjectName).il" /> + </ItemGroup> +</Project> |