Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichaƂ Petryka <35800402+MichalPetryka@users.noreply.github.com>2022-11-11 07:50:14 +0300
committerGitHub <noreply@github.com>2022-11-11 07:50:14 +0300
commit16b28c704108c691c54a73ad845069aac2e3e282 (patch)
treefee9502f5ebb033771e81f040272b1a2a3505566
parent00e6482544b435c66279ffd7abf43e9a7ead0236 (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>
-rw-r--r--src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs1
-rw-r--r--src/coreclr/inc/corinfo.h14
-rw-r--r--src/coreclr/inc/icorjitinfoimpl_generated.h4
-rw-r--r--src/coreclr/inc/jiteeversionguid.h10
-rw-r--r--src/coreclr/jit/ICorJitInfo_names_generated.h1
-rw-r--r--src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp10
-rw-r--r--src/coreclr/jit/compiler.h2
-rw-r--r--src/coreclr/jit/fgbasic.cpp2
-rw-r--r--src/coreclr/jit/gentree.cpp36
-rw-r--r--src/coreclr/jit/importer.cpp52
-rw-r--r--src/coreclr/jit/importercalls.cpp77
-rw-r--r--src/coreclr/jit/morph.cpp2
-rw-r--r--src/coreclr/jit/namedintrinsiclist.h2
-rw-r--r--src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs30
-rw-r--r--src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs212
-rw-r--r--src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt1
-rw-r--r--src/coreclr/tools/aot/jitinterface/jitinterface_generated.h11
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h1
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp35
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h5
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp18
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp8
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp7
-rw-r--r--src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp11
-rw-r--r--src/coreclr/vm/jitinterface.cpp51
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs2
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs3
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs61
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Type.cs51
-rw-r--r--src/libraries/System.Runtime/tests/System/EnumTests.cs6
-rw-r--r--src/tests/JIT/Intrinsics/TypeIntrinsics.GetEnumUnderlyingType.cs111
-rw-r--r--src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableFrom.cs16
-rw-r--r--src/tests/JIT/Intrinsics/TypeIntrinsics.IsAssignableTo.cs16
-rw-r--r--src/tests/JIT/Intrinsics/TypeIntrinsics.cs43
-rw-r--r--src/tests/JIT/Intrinsics/TypeIntrinsicsEnums.il42
-rw-r--r--src/tests/JIT/Intrinsics/TypeIntrinsicsEnums.ilproj11
-rw-r--r--src/tests/JIT/Intrinsics/TypeIntrinsics_r.csproj4
-rw-r--r--src/tests/JIT/Intrinsics/TypeIntrinsics_ro.csproj4
-rw-r--r--src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCode.cs94
-rw-r--r--src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCode.csproj12
-rw-r--r--src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCodeEnums.il42
-rw-r--r--src/tests/JIT/opt/IsKnownConstant/TypeGetTypeCodeEnums.ilproj11
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>