diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 271eb8492aef74..89c61ebeac690e 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2718,6 +2718,11 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE cls ) = 0; + // Returns whether a class handle represents a generic type, if that can be statically determined. + virtual TypeCompareState isGenericType( + CORINFO_CLASS_HANDLE cls + ) = 0; + // Returns whether a class handle represents a Nullable type, if that can be statically determined. virtual TypeCompareState isNullableType( CORINFO_CLASS_HANDLE cls diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 9567498e597683..38f9dac0e2e4d1 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -345,6 +345,9 @@ bool isMoreSpecificType( bool isExactType( CORINFO_CLASS_HANDLE cls) override; +TypeCompareState isGenericType( + CORINFO_CLASS_HANDLE cls) override; + TypeCompareState isNullableType( CORINFO_CLASS_HANDLE cls) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 6bcb13b5a92656..76a1bbc466d790 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 = { /* de0cd36d-3094-4110-af7d-31eb36234e46 */ - 0xde0cd36d, - 0x3094, - 0x4110, - {0xaf, 0x7d, 0x31, 0xeb, 0x36, 0x23, 0x4e, 0x46} +constexpr GUID JITEEVersionIdentifier = { /* e428e66d-5e0e-4320-ad8a-fa5a50f6da07 */ + 0xe428e66d, + 0x5e0e, + 0x4320, + {0xad, 0x8a, 0xfa, 0x5a, 0x50, 0xf6, 0xda, 0x07} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index c1c21429e05a2c..a2bfe1de9c80cc 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -86,6 +86,7 @@ DEF_CLR_API(compareTypesForCast) DEF_CLR_API(compareTypesForEquality) DEF_CLR_API(isMoreSpecificType) DEF_CLR_API(isExactType) +DEF_CLR_API(isGenericType) DEF_CLR_API(isNullableType) DEF_CLR_API(isEnum) DEF_CLR_API(getParentType) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index ec77bd3eed0a32..ff54b778f2a2cd 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -811,6 +811,15 @@ bool WrapICorJitInfo::isExactType( return temp; } +TypeCompareState WrapICorJitInfo::isGenericType( + CORINFO_CLASS_HANDLE cls) +{ + API_ENTER(isGenericType); + TypeCompareState temp = wrapHnd->isGenericType(cls); + API_LEAVE(isGenericType); + return temp; +} + TypeCompareState WrapICorJitInfo::isNullableType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 653ff015c32725..da31f325424e40 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -1382,6 +1382,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed case NI_System_Type_get_IsValueType: case NI_System_Type_get_IsPrimitive: case NI_System_Type_get_IsByRefLike: + case NI_System_Type_get_IsGenericType: case NI_System_Type_GetTypeFromHandle: case NI_System_String_get_Length: case NI_System_Buffers_Binary_BinaryPrimitives_ReverseEndianness: diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index c920ac70cfef56..d8041a548412c2 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3165,6 +3165,7 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, case NI_System_Type_get_IsByRefLike: case NI_System_Type_IsAssignableFrom: case NI_System_Type_IsAssignableTo: + case NI_System_Type_get_IsGenericType: // Lightweight intrinsics case NI_System_String_get_Chars: @@ -3785,6 +3786,7 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, case NI_System_Type_get_IsValueType: case NI_System_Type_get_IsPrimitive: case NI_System_Type_get_IsByRefLike: + case NI_System_Type_get_IsGenericType: { // Optimize // @@ -3831,7 +3833,17 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, retNode = gtNewFalse(); } break; - + case NI_System_Type_get_IsGenericType: + { + TypeCompareState state = info.compCompHnd->isGenericType(hClass); + if (state == TypeCompareState::May) + { + retNode = nullptr; + break; + } + retNode = state == TypeCompareState::Must ? gtNewTrue() : gtNewFalse(); + break; + } default: NO_WAY("Intrinsic not supported in this path."); } @@ -10015,6 +10027,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Type_get_IsPrimitive; } + else if (strcmp(methodName, "get_IsGenericType") == 0) + { + result = NI_System_Type_get_IsGenericType; + } else if (strcmp(methodName, "get_IsByRefLike") == 0) { result = NI_System_Type_get_IsByRefLike; diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index d7784144282722..0ec8fd2496ba38 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -81,6 +81,7 @@ enum NamedIntrinsic : unsigned short NI_System_Type_get_IsPrimitive, NI_System_Type_get_IsByRefLike, NI_System_Type_get_TypeHandle, + NI_System_Type_get_IsGenericType, NI_System_Type_IsAssignableFrom, NI_System_Type_IsAssignableTo, NI_System_Type_op_Equality, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index f39bafc4f3837e..a695d07be6fcf1 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2938,6 +2938,18 @@ private bool isExactType(CORINFO_CLASS_STRUCT_* cls) return _compilation.IsEffectivelySealed(type); } + private TypeCompareState isGenericType(CORINFO_CLASS_STRUCT_* cls) + { + TypeDesc type = HandleToObject(cls); + + if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) + { + return TypeCompareState.May; + } + + return type.HasInstantiation ? TypeCompareState.Must : TypeCompareState.MustNot; + } + private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) { TypeDesc type = HandleToObject(cls); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 0eaaf5a78dc7d9..950ce7f4a12232 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1225,6 +1225,21 @@ private static byte _isExactType(IntPtr thisHandle, IntPtr* ppException, CORINFO } } + [UnmanagedCallersOnly] + private static TypeCompareState _isGenericType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.isGenericType(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static TypeCompareState _isNullableType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) { @@ -2594,7 +2609,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 175); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 176); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2678,99 +2693,100 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[79] = (delegate* unmanaged)&_compareTypesForEquality; callbacks[80] = (delegate* unmanaged)&_isMoreSpecificType; callbacks[81] = (delegate* unmanaged)&_isExactType; - callbacks[82] = (delegate* unmanaged)&_isNullableType; - callbacks[83] = (delegate* unmanaged)&_isEnum; - callbacks[84] = (delegate* unmanaged)&_getParentType; - callbacks[85] = (delegate* unmanaged)&_getChildType; - callbacks[86] = (delegate* unmanaged)&_isSDArray; - callbacks[87] = (delegate* unmanaged)&_getArrayRank; - callbacks[88] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[89] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[90] = (delegate* unmanaged)&_canAccessClass; - callbacks[91] = (delegate* unmanaged)&_printFieldName; - callbacks[92] = (delegate* unmanaged)&_getFieldClass; - callbacks[93] = (delegate* unmanaged)&_getFieldType; - callbacks[94] = (delegate* unmanaged)&_getFieldOffset; - callbacks[95] = (delegate* unmanaged)&_getFieldInfo; - callbacks[96] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[97] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; - callbacks[99] = (delegate* unmanaged)&_isFieldStatic; - callbacks[100] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[101] = (delegate* unmanaged)&_getBoundaries; - callbacks[102] = (delegate* unmanaged)&_setBoundaries; - callbacks[103] = (delegate* unmanaged)&_getVars; - callbacks[104] = (delegate* unmanaged)&_setVars; - callbacks[105] = (delegate* unmanaged)&_reportRichMappings; - callbacks[106] = (delegate* unmanaged)&_reportMetadata; - callbacks[107] = (delegate* unmanaged)&_allocateArray; - callbacks[108] = (delegate* unmanaged)&_freeArray; - callbacks[109] = (delegate* unmanaged)&_getArgNext; - callbacks[110] = (delegate* unmanaged)&_getArgType; - callbacks[111] = (delegate* unmanaged)&_getExactClasses; - callbacks[112] = (delegate* unmanaged)&_getArgClass; - callbacks[113] = (delegate* unmanaged)&_getHFAType; - callbacks[114] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[115] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[116] = (delegate* unmanaged)&_getEEInfo; - callbacks[117] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[118] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[119] = (delegate* unmanaged)&_printMethodName; - callbacks[120] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[121] = (delegate* unmanaged)&_getMethodHash; - callbacks[122] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[123] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[124] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[125] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; - callbacks[126] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[127] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[128] = (delegate* unmanaged)&_getHelperFtn; - callbacks[129] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[130] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[131] = (delegate* unmanaged)&_getMethodSync; - callbacks[132] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[133] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[134] = (delegate* unmanaged)&_embedClassHandle; - callbacks[135] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[136] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[137] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[138] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[139] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[140] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[141] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[142] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[143] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[144] = (delegate* unmanaged)&_getCallInfo; - callbacks[145] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[146] = (delegate* unmanaged)&_getObjectContent; - callbacks[147] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[148] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[149] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[150] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[151] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[152] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[153] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[154] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[155] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[156] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[157] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[158] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[159] = (delegate* unmanaged)&_allocMem; - callbacks[160] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[161] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[162] = (delegate* unmanaged)&_allocGCInfo; - callbacks[163] = (delegate* unmanaged)&_setEHcount; - callbacks[164] = (delegate* unmanaged)&_setEHinfo; - callbacks[165] = (delegate* unmanaged)&_logMsg; - callbacks[166] = (delegate* unmanaged)&_doAssert; - callbacks[167] = (delegate* unmanaged)&_reportFatalError; - callbacks[168] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[169] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[170] = (delegate* unmanaged)&_recordCallSite; - callbacks[171] = (delegate* unmanaged)&_recordRelocation; - callbacks[172] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[173] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[174] = (delegate* unmanaged)&_getJitFlags; + callbacks[82] = (delegate* unmanaged)&_isGenericType; + callbacks[83] = (delegate* unmanaged)&_isNullableType; + callbacks[84] = (delegate* unmanaged)&_isEnum; + callbacks[85] = (delegate* unmanaged)&_getParentType; + callbacks[86] = (delegate* unmanaged)&_getChildType; + callbacks[87] = (delegate* unmanaged)&_isSDArray; + callbacks[88] = (delegate* unmanaged)&_getArrayRank; + callbacks[89] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[90] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[91] = (delegate* unmanaged)&_canAccessClass; + callbacks[92] = (delegate* unmanaged)&_printFieldName; + callbacks[93] = (delegate* unmanaged)&_getFieldClass; + callbacks[94] = (delegate* unmanaged)&_getFieldType; + callbacks[95] = (delegate* unmanaged)&_getFieldOffset; + callbacks[96] = (delegate* unmanaged)&_getFieldInfo; + callbacks[97] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[99] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; + callbacks[100] = (delegate* unmanaged)&_isFieldStatic; + callbacks[101] = (delegate* unmanaged)&_getArrayOrStringLength; + callbacks[102] = (delegate* unmanaged)&_getBoundaries; + callbacks[103] = (delegate* unmanaged)&_setBoundaries; + callbacks[104] = (delegate* unmanaged)&_getVars; + callbacks[105] = (delegate* unmanaged)&_setVars; + callbacks[106] = (delegate* unmanaged)&_reportRichMappings; + callbacks[107] = (delegate* unmanaged)&_reportMetadata; + callbacks[108] = (delegate* unmanaged)&_allocateArray; + callbacks[109] = (delegate* unmanaged)&_freeArray; + callbacks[110] = (delegate* unmanaged)&_getArgNext; + callbacks[111] = (delegate* unmanaged)&_getArgType; + callbacks[112] = (delegate* unmanaged)&_getExactClasses; + callbacks[113] = (delegate* unmanaged)&_getArgClass; + callbacks[114] = (delegate* unmanaged)&_getHFAType; + callbacks[115] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[116] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[117] = (delegate* unmanaged)&_getEEInfo; + callbacks[118] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[119] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[120] = (delegate* unmanaged)&_printMethodName; + callbacks[121] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[122] = (delegate* unmanaged)&_getMethodHash; + callbacks[123] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[124] = (delegate* unmanaged)&_getSwiftLowering; + callbacks[125] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[126] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; + callbacks[127] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[128] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[129] = (delegate* unmanaged)&_getHelperFtn; + callbacks[130] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[131] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[132] = (delegate* unmanaged)&_getMethodSync; + callbacks[133] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[134] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[135] = (delegate* unmanaged)&_embedClassHandle; + callbacks[136] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[137] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[138] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[139] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[140] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[141] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[142] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[143] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[144] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[145] = (delegate* unmanaged)&_getCallInfo; + callbacks[146] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[147] = (delegate* unmanaged)&_getObjectContent; + callbacks[148] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[149] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[150] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[151] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[152] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[153] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[154] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[155] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[156] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[157] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[158] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[159] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[160] = (delegate* unmanaged)&_allocMem; + callbacks[161] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[162] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[163] = (delegate* unmanaged)&_allocGCInfo; + callbacks[164] = (delegate* unmanaged)&_setEHcount; + callbacks[165] = (delegate* unmanaged)&_setEHinfo; + callbacks[166] = (delegate* unmanaged)&_logMsg; + callbacks[167] = (delegate* unmanaged)&_doAssert; + callbacks[168] = (delegate* unmanaged)&_reportFatalError; + callbacks[169] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[170] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[171] = (delegate* unmanaged)&_recordCallSite; + callbacks[172] = (delegate* unmanaged)&_recordRelocation; + callbacks[173] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[174] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[175] = (delegate* unmanaged)&_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 5cb584a948b5be..9fc314fe56a370 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -245,6 +245,7 @@ FUNCTIONS TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) bool isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) bool isExactType(CORINFO_CLASS_HANDLE cls) + TypeCompareState isGenericType(CORINFO_CLASS_HANDLE cls) TypeCompareState isNullableType(CORINFO_CLASS_HANDLE cls) TypeCompareState isEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) CORINFO_CLASS_HANDLE getParentType(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 0e266984cd88c5..75722274d9e9b6 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -93,6 +93,7 @@ struct JitInterfaceCallbacks TypeCompareState (* compareTypesForEquality)(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); bool (* isExactType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); + TypeCompareState (* isGenericType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); TypeCompareState (* isNullableType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); 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); @@ -1000,6 +1001,15 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual TypeCompareState isGenericType( + CORINFO_CLASS_HANDLE cls) +{ + CorInfoExceptionClass* pException = nullptr; + TypeCompareState temp = _callbacks->isGenericType(_thisHandle, &pException, cls); + if (pException != nullptr) throw pException; + return temp; +} + virtual TypeCompareState isNullableType( 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 0dcf59296462f5..fd85fdd97e892f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -159,6 +159,7 @@ LWM(PrintMethodName, DWORDLONG, Agnostic_PrintResult) LWM(IsValueClass, DWORDLONG, DWORD) LWM(IsMoreSpecificType, DLDL, DWORD) LWM(IsExactType, DWORDLONG, DWORD) +LWM(IsGenericType, DWORDLONG, DWORD) LWM(IsNullableType, DWORDLONG, DWORD) LWM(IsEnum, DWORDLONG, DLD) LWM(PInvokeMarshalingRequired, MethodOrSigInfoValue, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 98b76813d5ba43..0e0fa438e727a0 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -5926,6 +5926,28 @@ bool MethodContext::repIsExactType(CORINFO_CLASS_HANDLE cls) return value != 0; } +void MethodContext::recIsGenericType(CORINFO_CLASS_HANDLE cls, TypeCompareState result) +{ + if (IsGenericType == nullptr) + IsGenericType = new LightWeightMap(); + + DWORDLONG key = CastHandle(cls); + DWORD value = (DWORD)result; + IsGenericType->Add(key, value); + DEBUG_REC(dmpIsGenericType(key, value)); +} +void MethodContext::dmpIsGenericType(DWORDLONG key, DWORD value) +{ + printf("IsGenericType key cls-%016" PRIX64 ", value res-%d", key, value); +} +TypeCompareState MethodContext::repIsGenericType(CORINFO_CLASS_HANDLE cls) +{ + DWORDLONG key = CastHandle(cls); + DWORD value = LookupByKeyOrMiss(IsGenericType, key, ": key %016" PRIX64 "", key); + DEBUG_REP(dmpIsGenericType(key, value)); + return (TypeCompareState)value; +} + void MethodContext::recIsNullableType(CORINFO_CLASS_HANDLE cls, TypeCompareState result) { if (IsNullableType == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 807b2311a49e68..c970dd9a7b226c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -727,6 +727,10 @@ class MethodContext void dmpIsExactType(DWORDLONG key, DWORD value); bool repIsExactType(CORINFO_CLASS_HANDLE cls); + void recIsGenericType(CORINFO_CLASS_HANDLE cls, TypeCompareState result); + void dmpIsGenericType(DWORDLONG key, DWORD value); + TypeCompareState repIsGenericType(CORINFO_CLASS_HANDLE cls); + void recIsNullableType(CORINFO_CLASS_HANDLE cls, TypeCompareState result); void dmpIsNullableType(DWORDLONG key, DWORD value); TypeCompareState repIsNullableType(CORINFO_CLASS_HANDLE cls); @@ -1176,6 +1180,7 @@ enum mcPackets Packet_IsNullableType = 217, Packet_GetClassStaticDynamicInfo = 218, Packet_GetClassThreadStaticDynamicInfo = 219, + Packet_IsGenericType = 220, }; 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 ee43051dd1ce15..84ad616c28eb9c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -905,6 +905,15 @@ bool interceptor_ICJI::isExactType(CORINFO_CLASS_HANDLE cls) return temp; } +// Returns whether a class handle represents a generic type, if that can be statically determined. +TypeCompareState interceptor_ICJI::isGenericType(CORINFO_CLASS_HANDLE cls) +{ + mc->cr->AddCall("isGenericType"); + TypeCompareState temp = original_ICorJitInfo->isGenericType(cls); + mc->recIsGenericType(cls, temp); + return temp; +} + // Returns whether a class handle represents a Nullable type, if that can be statically determined. TypeCompareState interceptor_ICJI::isNullableType(CORINFO_CLASS_HANDLE cls) { 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 aa5ab8a37b7ba1..2d6faf2c657283 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -664,6 +664,13 @@ bool interceptor_ICJI::isExactType( return original_ICorJitInfo->isExactType(cls); } +TypeCompareState interceptor_ICJI::isGenericType( + CORINFO_CLASS_HANDLE cls) +{ + mcs->AddCall("isGenericType"); + return original_ICorJitInfo->isGenericType(cls); +} + TypeCompareState interceptor_ICJI::isNullableType( 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 7cfceafebcb55e..210485e727c9bf 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -582,6 +582,12 @@ bool interceptor_ICJI::isExactType( return original_ICorJitInfo->isExactType(cls); } +TypeCompareState interceptor_ICJI::isGenericType( + CORINFO_CLASS_HANDLE cls) +{ + return original_ICorJitInfo->isGenericType(cls); +} + TypeCompareState interceptor_ICJI::isNullableType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 0736fc8deee8a4..9e29f43e03ec38 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -768,6 +768,13 @@ bool MyICJI::isExactType(CORINFO_CLASS_HANDLE cls) return jitInstance->mc->repIsExactType(cls); } +// Returns true if a class handle represents a generic type. +TypeCompareState MyICJI::isGenericType(CORINFO_CLASS_HANDLE cls) +{ + jitInstance->mc->cr->AddCall("isGenericType"); + return jitInstance->mc->repIsGenericType(cls); +} + // Returns true if a class handle represents a Nullable type. TypeCompareState MyICJI::isNullableType(CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 2631fb927d5d8f..54ce75255eeaf6 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -4547,28 +4547,48 @@ bool CEEInfo::isExactType(CORINFO_CLASS_HANDLE cls) return result; } -// Returns whether a class handle represents a Nullable type, if that can be statically determined. -TypeCompareState CEEInfo::isNullableType(CORINFO_CLASS_HANDLE cls) +// Returns whether a class handle represents a generic type, if that can be statically determined. +TypeCompareState CEEInfo::isGenericType(CORINFO_CLASS_HANDLE cls) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_PREEMPTIVE; } CONTRACTL_END; - TypeHandle typeHandle = TypeHandle(); - TypeCompareState result = TypeCompareState::May; - JIT_TO_EE_TRANSITION(); + JIT_TO_EE_TRANSITION_LEAF(); + + TypeHandle typeHandle(cls); if (typeHandle != TypeHandle(g_pCanonMethodTableClass)) { - TypeHandle VMClsHnd(cls); - result = Nullable::IsNullableType(VMClsHnd) ? TypeCompareState::Must : TypeCompareState::MustNot; + result = typeHandle.HasInstantiation() ? TypeCompareState::Must : TypeCompareState::MustNot; } - EE_TO_JIT_TRANSITION(); + EE_TO_JIT_TRANSITION_LEAF(); + return result; +} + +// Returns whether a class handle represents a Nullable type, if that can be statically determined. +TypeCompareState CEEInfo::isNullableType(CORINFO_CLASS_HANDLE cls) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + TypeCompareState result; + + JIT_TO_EE_TRANSITION_LEAF(); + + TypeHandle typeHandle(cls); + + result = Nullable::IsNullableType(typeHandle) ? TypeCompareState::Must : TypeCompareState::MustNot; + + EE_TO_JIT_TRANSITION_LEAF(); return result; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index c93a158339a033..6c9185193dabf5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -57,7 +57,7 @@ public bool IsInterface public virtual bool IsGenericParameter => false; public virtual bool IsGenericTypeParameter => IsGenericParameter && DeclaringMethod is null; public virtual bool IsGenericMethodParameter => IsGenericParameter && DeclaringMethod != null; - public virtual bool IsGenericType => false; + public virtual bool IsGenericType { [Intrinsic] get => false; } public virtual bool IsGenericTypeDefinition => false; public virtual bool IsSZArray => throw NotImplemented.ByDesign; diff --git a/src/tests/JIT/Intrinsics/TypeIntrinsics.cs b/src/tests/JIT/Intrinsics/TypeIntrinsics.cs index 218f17e3d17932..3821f74bf18761 100644 --- a/src/tests/JIT/Intrinsics/TypeIntrinsics.cs +++ b/src/tests/JIT/Intrinsics/TypeIntrinsics.cs @@ -133,6 +133,7 @@ public static int TestEntryPoint() GetEnumUnderlyingType.TestGetEnumUnderlyingType(); IsPrimitiveTests(); + IsGenericTypeTests(); return 100 + _errors; } @@ -186,6 +187,95 @@ private static void IsPrimitiveTests() IsFalse(typeof(Dictionary<,>).IsPrimitive); } + private static void IsGenericTypeTests() + { + IsFalse(typeof(bool).IsGenericType); + IsFalse(typeof(char).IsGenericType); + IsFalse(typeof(sbyte).IsGenericType); + IsFalse(typeof(byte).IsGenericType); + IsFalse(typeof(short).IsGenericType); + IsFalse(typeof(ushort).IsGenericType); + IsFalse(typeof(int).IsGenericType); + IsFalse(typeof(uint).IsGenericType); + IsFalse(typeof(long).IsGenericType); + IsFalse(typeof(ulong).IsGenericType); + IsFalse(typeof(float).IsGenericType); + IsFalse(typeof(double).IsGenericType); + IsFalse(typeof(nint).IsGenericType); + IsFalse(typeof(nuint).IsGenericType); + IsFalse(typeof(IntPtr).IsGenericType); + IsFalse(typeof(UIntPtr).IsGenericType); + IsFalse(typeof(Enum).IsGenericType); + IsFalse(typeof(ValueType).IsGenericType); + IsFalse(typeof(SimpleEnum).IsGenericType); + IsFalse(typeof(IntPtrEnum).IsGenericType); + IsFalse(typeof(FloatEnum).IsGenericType); + IsFalse(typeof(decimal).IsGenericType); + IsFalse(typeof(TimeSpan).IsGenericType); + IsFalse(typeof(DateTime).IsGenericType); + IsFalse(typeof(DateTimeOffset).IsGenericType); + IsFalse(typeof(Guid).IsGenericType); + IsFalse(typeof(Half).IsGenericType); + IsFalse(typeof(DateOnly).IsGenericType); + IsFalse(typeof(TimeOnly).IsGenericType); + IsFalse(typeof(Int128).IsGenericType); + IsFalse(typeof(UInt128).IsGenericType); + IsFalse(typeof(string).IsGenericType); + IsFalse(typeof(object).IsGenericType); + IsFalse(typeof(RuntimeArgumentHandle).IsGenericType); + IsFalse(typeof(DerivedGenericSimpleClass).IsGenericType); + IsFalse(typeof(int[]).IsGenericType); + IsFalse(typeof(int[,]).IsGenericType); + IsFalse(typeof(int*).IsGenericType); + IsFalse(typeof(void*).IsGenericType); + IsFalse(typeof(delegate*).IsGenericType); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericType()); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericType()); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericType()); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericType()); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericType()); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericTypeFromArray()); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericTypeFromArray()); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericTypeFromArray()); + IsFalse(new ClassUsingIsGenericTypeOnT().IsGenericTypeFromArray()); + IsFalse(new ClassUsingIsGenericTypeOnT>().IsGenericTypeFromArray()); + IsFalse(new ClassUsingIsGenericTypeOnT>().IsGenericTypeFromArray()); + IsFalse(new ClassUsingIsGenericTypeOnT>().IsGenericTypeFromArray()); + IsFalse(new ClassUsingIsGenericTypeOnT>().IsGenericTypeFromArray()); + + IsTrue(typeof(GenericSimpleClass).IsGenericType); + IsTrue(typeof(GenericSimpleClass<>).IsGenericType); + IsTrue(typeof(GenericSimpleClass.Nested).IsGenericType); + IsTrue(typeof(GenericSimpleClass<>.Nested).IsGenericType); + IsTrue(typeof(GenericEnumClass).IsGenericType); + IsTrue(typeof(GenericEnumClass<>).IsGenericType); + IsTrue(typeof(IGenericInterface).IsGenericType); + IsTrue(typeof(IGenericInterface<>).IsGenericType); + IsTrue(typeof(GenericStruct).IsGenericType); + IsTrue(typeof(GenericStruct<>).IsGenericType); + IsTrue(typeof(SimpleEnum?).IsGenericType); + IsTrue(typeof(int?).IsGenericType); + IsTrue(typeof(IntPtr?).IsGenericType); + IsTrue(typeof(Nullable<>).IsGenericType); + IsTrue(typeof(Dictionary).IsGenericType); + IsTrue(typeof(Dictionary<,>).IsGenericType); + IsTrue(typeof(List).IsGenericType); + IsTrue(typeof(List<>).IsGenericType); + IsTrue(typeof(Action<>).IsGenericType); + IsTrue(typeof(Action).IsGenericType); + IsTrue(typeof(Func).IsGenericType); + IsTrue(typeof(Func<,>).IsGenericType); + IsTrue(new ClassUsingIsGenericTypeOnT>().IsGenericType()); + IsTrue(new ClassUsingIsGenericTypeOnT>().IsGenericType()); + IsTrue(new ClassUsingIsGenericTypeOnT>().IsGenericType()); + IsTrue(new ClassUsingIsGenericTypeOnT().IsGenericType()); + IsTrue(new ClassUsingIsGenericTypeOnT>().IsGenericType()); + IsTrue(new ClassUsingIsGenericTypeOnT().IsGenericTypeFromOtherGenericType()); + IsTrue(new ClassUsingIsGenericTypeOnT().IsGenericTypeFromOtherGenericType()); + IsTrue(new ClassUsingIsGenericTypeOnT().IsGenericTypeFromOtherGenericType()); + IsTrue(new ClassUsingIsGenericTypeOnT().IsGenericTypeFromOtherGenericType()); + } + private static int _varInt = 42; private static int? _varNullableInt = 42; private static decimal _varDecimal = 42M; @@ -258,6 +348,29 @@ static void ThrowsNRE(Action action, [CallerLineNumber] int line = 0, [CallerFil } } +public class ClassUsingIsGenericTypeOnT +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public bool IsGenericType() => typeof(T).IsGenericType; + + [MethodImpl(MethodImplOptions.NoInlining)] + public bool IsGenericTypeFromArray() => typeof(T[]).IsGenericType; + + [MethodImpl(MethodImplOptions.NoInlining)] + public bool IsGenericTypeFromOtherGenericType() => typeof(GenericSimpleClass).IsGenericType; +} + +public class GenericSimpleClass +{ + public class Nested + { + } +} + +public class DerivedGenericSimpleClass : GenericSimpleClass +{ +} + public class GenericEnumClass where T : Enum { public T field;