diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 5e97c53adb2ff..91ae75acc4f00 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2790,6 +2790,15 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE *vcTypeRet /* OUT */ ) = 0; + // 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( + CORINFO_CLASS_HANDLE baseType, /* IN */ + int maxExactClasses, /* IN */ + CORINFO_CLASS_HANDLE* exactClsRet /* OUT */ + ) = 0; + // If the Arg is a CORINFO_TYPE_CLASS fetch the class handle associated with it virtual CORINFO_CLASS_HANDLE getArgClass ( CORINFO_SIG_INFO* sig, /* IN */ diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 986a95c51eb22..3a5a164e9aa71 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -430,6 +430,11 @@ CorInfoTypeWithMod getArgType( CORINFO_ARG_LIST_HANDLE args, CORINFO_CLASS_HANDLE* vcTypeRet) override; +int getExactClasses( + CORINFO_CLASS_HANDLE baseType, + int maxExactClasses, + CORINFO_CLASS_HANDLE* exactClsRet) override; + CORINFO_CLASS_HANDLE getArgClass( CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index dedd71fc3ea13..c003b6be776b2 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 = { /* 4efa8fe2-8489-4b61-aac9-b4df74af15b7 */ - 0x4efa8fe2, - 0x8489, - 0x4b61, - {0xaa, 0xc9, 0xb4, 0xdf, 0x74, 0xaf, 0x15, 0xb7} +constexpr GUID JITEEVersionIdentifier = { /* 1b9551b8-21f4-4233-9c90-f3eabd6a322b */ + 0x1b9551b8, + 0x21f4, + 0x4233, + {0x9c, 0x90, 0xf3, 0xea, 0xbd, 0x6a, 0x32, 0x2b} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h index d63a33685fa5f..0c5af5b9e802a 100644 --- a/src/coreclr/jit/ICorJitInfo_API_names.h +++ b/src/coreclr/jit/ICorJitInfo_API_names.h @@ -107,6 +107,7 @@ DEF_CLR_API(allocateArray) DEF_CLR_API(freeArray) DEF_CLR_API(getArgNext) DEF_CLR_API(getArgType) +DEF_CLR_API(getExactClasses) DEF_CLR_API(getArgClass) DEF_CLR_API(getHFAType) DEF_CLR_API(GetErrorHRESULT) diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp index 6490669dc3d04..96139cc6cd4ef 100644 --- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp @@ -1015,6 +1015,17 @@ CorInfoTypeWithMod WrapICorJitInfo::getArgType( return temp; } +int WrapICorJitInfo::getExactClasses( + CORINFO_CLASS_HANDLE baseType, + int maxExactClasses, + CORINFO_CLASS_HANDLE* exactClsRet) +{ + API_ENTER(getExactClasses); + int temp = wrapHnd->getExactClasses(baseType, maxExactClasses, exactClsRet); + API_LEAVE(getExactClasses); + return temp; +} + CORINFO_CLASS_HANDLE WrapICorJitInfo::getArgClass( CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index c43f473553309..3b7c12f25ccb1 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17773,6 +17773,16 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b } } + if ((objClass != NO_CLASS_HANDLE) && !*pIsExact && JitConfig.JitEnableExactDevirtualization()) + { + CORINFO_CLASS_HANDLE exactClass; + if (info.compCompHnd->getExactClasses(objClass, 1, &exactClass) == 1) + { + *pIsExact = true; + objClass = exactClass; + } + } + return objClass; } diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index db46ca0257c91..3e6df61b1f71f 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -565,6 +565,9 @@ CONFIG_INTEGER(JitCrossCheckDevirtualizationAndPGO, W("JitCrossCheckDevirtualiza CONFIG_INTEGER(JitNoteFailedExactDevirtualization, W("JitNoteFailedExactDevirtualization"), 0) #endif // debug +// Devirtualize virtual calls with getExactClasses (NativeAOT only for now) +CONFIG_INTEGER(JitEnableExactDevirtualization, W("JitEnableExactDevirtualization"), 1) + // Control when Virtual Calls are expanded CONFIG_INTEGER(JitExpandCallsEarly, W("JitExpandCallsEarly"), 1) // Expand Call targets early (in the global morph // phase) diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 79ca2c954bfa6..4aa1b1e4d9865 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -3174,6 +3174,16 @@ void Compiler::lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool is return; } + if (clsHnd != NO_CLASS_HANDLE && !isExact && JitConfig.JitEnableExactDevirtualization()) + { + CORINFO_CLASS_HANDLE exactClass; + if (info.compCompHnd->getExactClasses(clsHnd, 1, &exactClass) == 1) + { + isExact = true; + clsHnd = exactClass; + } + } + // Else we should have a type handle. assert(clsHnd != nullptr); diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs index f95fc7c04f435..2fb34cede261f 100644 --- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs +++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs @@ -211,6 +211,8 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType /// so it can answer this question. /// public virtual bool CanConstructType(TypeDesc type) => true; + + public virtual TypeDesc[] GetImplementingClasses(TypeDesc type) => null; #endif } } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs index 036a2497e9953..541c0dc424c55 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs @@ -1533,6 +1533,21 @@ static CorInfoTypeWithMod _getArgType(IntPtr thisHandle, IntPtr* ppException, CO } } + [UnmanagedCallersOnly] + static int _getExactClasses(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) + { + var _this = GetThis(thisHandle); + try + { + return _this.getExactClasses(baseType, maxExactClasses, exactClsRet); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] static CORINFO_CLASS_STRUCT_* _getArgClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) { @@ -2580,7 +2595,7 @@ static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_FLAGS* f static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 174); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 175); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2685,77 +2700,78 @@ static IntPtr GetUnmanagedCallbacks() callbacks[100] = (delegate* unmanaged)&_freeArray; callbacks[101] = (delegate* unmanaged)&_getArgNext; callbacks[102] = (delegate* unmanaged)&_getArgType; - callbacks[103] = (delegate* unmanaged)&_getArgClass; - callbacks[104] = (delegate* unmanaged)&_getHFAType; - callbacks[105] = (delegate* unmanaged)&_GetErrorHRESULT; - callbacks[106] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[107] = (delegate* unmanaged)&_FilterException; - callbacks[108] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[109] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[110] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[111] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[112] = (delegate* unmanaged)&_getEEInfo; - callbacks[113] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[114] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[115] = (delegate* unmanaged)&_getMethodName; - callbacks[116] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[117] = (delegate* unmanaged)&_getMethodHash; - callbacks[118] = (delegate* unmanaged)&_findNameOfToken; - callbacks[119] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[120] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[121] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[122] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[123] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[124] = (delegate* unmanaged)&_getHelperFtn; - callbacks[125] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[126] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[127] = (delegate* unmanaged)&_getMethodSync; - callbacks[128] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[129] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[130] = (delegate* unmanaged)&_embedClassHandle; - callbacks[131] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[132] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[133] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[134] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[135] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[136] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[137] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[138] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[139] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[140] = (delegate* unmanaged)&_getCallInfo; - callbacks[141] = (delegate* unmanaged)&_canAccessFamily; - callbacks[142] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[143] = (delegate* unmanaged)&_getClassDomainID; - callbacks[144] = (delegate* unmanaged)&_getFieldAddress; - callbacks[145] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[146] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[147] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[148] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[149] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[150] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[151] = (delegate* unmanaged)&_addActiveDependency; - callbacks[152] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[153] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[154] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[155] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[156] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[157] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[158] = (delegate* unmanaged)&_allocMem; - callbacks[159] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[160] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[161] = (delegate* unmanaged)&_allocGCInfo; - callbacks[162] = (delegate* unmanaged)&_setEHcount; - callbacks[163] = (delegate* unmanaged)&_setEHinfo; - callbacks[164] = (delegate* unmanaged)&_logMsg; - callbacks[165] = (delegate* unmanaged)&_doAssert; - callbacks[166] = (delegate* unmanaged)&_reportFatalError; - callbacks[167] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[168] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[169] = (delegate* unmanaged)&_recordCallSite; - callbacks[170] = (delegate* unmanaged)&_recordRelocation; - callbacks[171] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[172] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[173] = (delegate* unmanaged)&_getJitFlags; + callbacks[103] = (delegate* unmanaged)&_getExactClasses; + callbacks[104] = (delegate* unmanaged)&_getArgClass; + callbacks[105] = (delegate* unmanaged)&_getHFAType; + callbacks[106] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[107] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[108] = (delegate* unmanaged)&_FilterException; + callbacks[109] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[110] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[111] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[112] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[113] = (delegate* unmanaged)&_getEEInfo; + callbacks[114] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[115] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[116] = (delegate* unmanaged)&_getMethodName; + callbacks[117] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[118] = (delegate* unmanaged)&_getMethodHash; + callbacks[119] = (delegate* unmanaged)&_findNameOfToken; + callbacks[120] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[121] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[122] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[123] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[124] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[125] = (delegate* unmanaged)&_getHelperFtn; + callbacks[126] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[127] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[128] = (delegate* unmanaged)&_getMethodSync; + callbacks[129] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[130] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[131] = (delegate* unmanaged)&_embedClassHandle; + callbacks[132] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[133] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[134] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[135] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[136] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[137] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[138] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[139] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[140] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[141] = (delegate* unmanaged)&_getCallInfo; + callbacks[142] = (delegate* unmanaged)&_canAccessFamily; + callbacks[143] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[144] = (delegate* unmanaged)&_getClassDomainID; + callbacks[145] = (delegate* unmanaged)&_getFieldAddress; + callbacks[146] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[147] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[148] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[149] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[150] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[151] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[152] = (delegate* unmanaged)&_addActiveDependency; + 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; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 2a2d068c6e5c2..b69ab664bd483 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -258,6 +258,7 @@ FUNCTIONS void freeArray(void*array); CORINFO_ARG_LIST_HANDLE getArgNext(CORINFO_ARG_LIST_HANDLE args); CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args, CORINFO_CLASS_HANDLE* vcTypeRet); + int getExactClasses(CORINFO_CLASS_HANDLE baseType, int maxExactClasses, CORINFO_CLASS_HANDLE* exactClsRet); CORINFO_CLASS_HANDLE getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args); CorInfoHFAElemType getHFAType(CORINFO_CLASS_HANDLE hClass); JITINTERFACE_HRESULT GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs index d4492d2323690..018226ef84270 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs @@ -219,6 +219,11 @@ public bool IsEffectivelySealed(TypeDesc type) return _devirtualizationManager.IsEffectivelySealed(type); } + public TypeDesc[] GetImplementingClasses(TypeDesc type) + { + return _devirtualizationManager.GetImplementingClasses(type); + } + public bool IsEffectivelySealed(MethodDesc method) { return _devirtualizationManager.IsEffectivelySealed(method); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs index da72ea35cb05b..7c6d2ab6431d6 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs @@ -367,6 +367,8 @@ private class ScannedDevirtualizationManager : DevirtualizationManager private HashSet _constructedTypes = new HashSet(); private HashSet _canonConstructedTypes = new HashSet(); private HashSet _unsealedTypes = new HashSet(); + private Dictionary> _interfaceImplementators = new(); + private HashSet _disqualifiedInterfaces = new(); public ScannedDevirtualizationManager(ImmutableArray> markedNodes) { @@ -381,7 +383,32 @@ public ScannedDevirtualizationManager(ImmutableArray : IFooable { } + // class Doer : IFooable { } + // And we instantiated Fooer, but not Doer. But we do have code for Doer<__Canon>. + // We might think we can devirtualize IFooable to Fooer, but someone could + // typeof(Doer<>).MakeGenericType(typeof(string)) and break our whole program view. + // This is only a problem if canonical form of the interface exists. + return false; + } + + return true; + } + + private void RecordImplementation(TypeDesc type, TypeDesc implType) + { + Debug.Assert(!implType.IsInterface); + + HashSet implList; + if (!_interfaceImplementators.TryGetValue(type, out implList)) + { + implList = new(); + _interfaceImplementators[type] = implList; + } + implList.Add(implType); + } + public override bool IsEffectivelySealed(TypeDesc type) { // If we know we scanned a type that derives from this one, this for sure can't be reported as sealed. @@ -456,6 +551,24 @@ protected override MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefTyp } public override bool CanConstructType(TypeDesc type) => _constructedTypes.Contains(type); + + public override TypeDesc[] GetImplementingClasses(TypeDesc type) + { + if (_disqualifiedInterfaces.Contains(type)) + return null; + + if (type.IsInterface && _interfaceImplementators.TryGetValue(type, out HashSet implementations)) + { + var types = new TypeDesc[implementations.Count]; + int index = 0; + foreach (TypeDesc implementation in implementations) + { + types[index++] = implementation; + } + return types; + } + return null; + } } private class ScannedInliningPolicy : IInliningPolicy diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index fbfd523856625..906d6761ec7aa 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -2969,5 +2969,11 @@ private void updateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) entryPoint = CreateConstLookupToSymbol(newEntryPoint); } + + private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) + { + // Not implemented for R2R yet + return 0; + } } } diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index e54366f91906f..b29b104f41d70 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2154,5 +2154,43 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET // TODO: We need to implement access checks for fields and methods. See JitInterface.cpp in mrtjit // and STS::AccessCheck::CanAccess. } + + private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) + { + MetadataType type = HandleToObject(baseType) as MetadataType; + if (type == null) + { + return 0; + } + + // type is already sealed, return it + if (_compilation.IsEffectivelySealed(type)) + { + *exactClsRet = baseType; + return 1; + } + + if (!type.IsInterface) + { + // TODO: handle classes + return 0; + } + + TypeDesc[] implClasses = _compilation.GetImplementingClasses(type); + if (implClasses == null || implClasses.Length > maxExactClasses) + { + return 0; + } + + int index = 0; + foreach (TypeDesc implClass in implClasses) + { + Debug.Assert(!implClass.IsCanonicalSubtype(CanonicalFormKind.Any)); + exactClsRet[index++] = ObjectToHandle(implClass); + } + + Debug.Assert(index <= maxExactClasses); + return index; + } } } diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h index 1bade9211b2d3..96cb5bbb40967 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h @@ -114,6 +114,7 @@ struct JitInterfaceCallbacks void (* freeArray)(void * thisHandle, CorInfoExceptionClass** ppException, void* array); CORINFO_ARG_LIST_HANDLE (* getArgNext)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_ARG_LIST_HANDLE args); CorInfoTypeWithMod (* getArgType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args, CORINFO_CLASS_HANDLE* vcTypeRet); + int (* getExactClasses)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE baseType, int maxExactClasses, CORINFO_CLASS_HANDLE* exactClsRet); CORINFO_CLASS_HANDLE (* getArgClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args); CorInfoHFAElemType (* getHFAType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE hClass); JITINTERFACE_HRESULT (* GetErrorHRESULT)(void * thisHandle, CorInfoExceptionClass** ppException, struct _EXCEPTION_POINTERS* pExceptionPointers); @@ -1203,6 +1204,17 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual int getExactClasses( + CORINFO_CLASS_HANDLE baseType, + int maxExactClasses, + CORINFO_CLASS_HANDLE* exactClsRet) +{ + CorInfoExceptionClass* pException = nullptr; + int temp = _callbacks->getExactClasses(_thisHandle, &pException, baseType, maxExactClasses, exactClsRet); + if (pException != nullptr) throw pException; + return temp; +} + virtual CORINFO_CLASS_HANDLE getArgClass( CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index b36dd82550753..503e2c42bcf1f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -51,6 +51,7 @@ LWM(GetAddrOfCaptureThreadGlobal, DWORD, DLDL) LWM(GetArgClass, Agnostic_GetArgClass_Key, Agnostic_GetArgClass_Value) LWM(GetArgNext, DWORDLONG, DWORDLONG) LWM(GetArgType, Agnostic_GetArgType_Key, Agnostic_GetArgType_Value) +LWM(GetExactClasses, DLD, DLD) LWM(GetArrayInitializationData, DLD, DWORDLONG) LWM(GetArrayRank, DWORDLONG, DWORD) LWM(GetArrayIntrinsicID, DWORDLONG, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 036433ea31a34..e8a883ed2d606 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -2703,6 +2703,37 @@ CorInfoTypeWithMod MethodContext::repGetArgType(CORINFO_SIG_INFO* sig, return temp; } +void MethodContext::recGetExactClasses(CORINFO_CLASS_HANDLE baseType, int maxExactClasses, CORINFO_CLASS_HANDLE* exactClsRet, int result) +{ + DLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(baseType); + key.B = maxExactClasses; + + DLD value; + ZeroMemory(&value, sizeof(value)); + value.A = CastHandle(*exactClsRet); + value.B = result; + + GetExactClasses->Add(key, value); +} +void MethodContext::dmpGetExactClasses(DLD key, DLD value) +{ + printf("GetExactClasses key baseType-%016llX, key maxExactCls %u, value exactCls %016llX, value exactClsCount %u", + key.A, key.B, value.A, value.B); +} +int MethodContext::repGetExactClasses(CORINFO_CLASS_HANDLE baseType, int maxExactClasses, CORINFO_CLASS_HANDLE* exactClsRet) +{ + DLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(baseType); + key.B = maxExactClasses; + + DLD value = GetExactClasses->Get(key); + *exactClsRet = (CORINFO_CLASS_HANDLE)value.A; + return value.B; +} + void MethodContext::recGetArgNext(CORINFO_ARG_LIST_HANDLE args, CORINFO_ARG_LIST_HANDLE result) { if (GetArgNext == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 5009d6b6a69c4..3fc5247ef66c2 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -375,6 +375,15 @@ class MethodContext CORINFO_CLASS_HANDLE* vcTypeRet, DWORD* exception); + void recGetExactClasses(CORINFO_CLASS_HANDLE baseType, + int maxExactClasses, + CORINFO_CLASS_HANDLE* exactClsRet, + int result); + void dmpGetExactClasses(DLD key, DLD value); + int repGetExactClasses(CORINFO_CLASS_HANDLE baseType, + int maxExactClasses, + CORINFO_CLASS_HANDLE* exactClsRet); + void recGetArgNext(CORINFO_ARG_LIST_HANDLE args, CORINFO_ARG_LIST_HANDLE result); void dmpGetArgNext(DWORDLONG key, DWORDLONG value); CORINFO_ARG_LIST_HANDLE repGetArgNext(CORINFO_ARG_LIST_HANDLE args); @@ -1118,6 +1127,7 @@ enum mcPackets Packet_IsIntrinsic = 192, Packet_UpdateEntryPointForTailCall = 193, Packet_GetLoongArch64PassStructInRegisterFlags = 194, + Packet_GetExactClasses = 195, }; 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 2df93cbf95a2f..5d146d2de2cd7 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1248,6 +1248,16 @@ CorInfoTypeWithMod interceptor_ICJI::getArgType(CORINFO_SIG_INFO* sig, return temp; } +int interceptor_ICJI::getExactClasses(CORINFO_CLASS_HANDLE baseType, /* IN */ + int maxExactClasses, /* IN */ + CORINFO_CLASS_HANDLE* exactClsRet) /* OUT */ +{ + mc->cr->AddCall("getExactClasses"); + int result = original_ICorJitInfo->getExactClasses(baseType, maxExactClasses, exactClsRet); + this->mc->recGetExactClasses(baseType, maxExactClasses, exactClsRet, result); + return result; +} + // If the Arg is a CORINFO_TYPE_CLASS fetch the class handle associated with it CORINFO_CLASS_HANDLE interceptor_ICJI::getArgClass(CORINFO_SIG_INFO* sig, /* IN */ CORINFO_ARG_LIST_HANDLE args /* IN */ diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 1f524f561da8e..4f8ed3ab023d6 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -833,6 +833,15 @@ CorInfoTypeWithMod interceptor_ICJI::getArgType( return original_ICorJitInfo->getArgType(sig, args, vcTypeRet); } +int interceptor_ICJI::getExactClasses( + CORINFO_CLASS_HANDLE baseType, + int maxExactClasses, + CORINFO_CLASS_HANDLE* exactClsRet) +{ + mcs->AddCall("getExactClasses"); + return original_ICorJitInfo->getExactClasses(baseType, maxExactClasses, exactClsRet); +} + CORINFO_CLASS_HANDLE interceptor_ICJI::getArgClass( CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp index acd860b915c6c..7da0d2ebb4a45 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -730,6 +730,14 @@ CorInfoTypeWithMod interceptor_ICJI::getArgType( return original_ICorJitInfo->getArgType(sig, args, vcTypeRet); } +int interceptor_ICJI::getExactClasses( + CORINFO_CLASS_HANDLE baseType, + int maxExactClasses, + CORINFO_CLASS_HANDLE* exactClsRet) +{ + return original_ICorJitInfo->getExactClasses(baseType, maxExactClasses, exactClsRet); +} + CORINFO_CLASS_HANDLE interceptor_ICJI::getArgClass( CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args) diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 2a8ee81757233..218123a05d891 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1086,6 +1086,15 @@ CorInfoTypeWithMod MyICJI::getArgType(CORINFO_SIG_INFO* sig, /* IN */ return value; } +int MyICJI::getExactClasses(CORINFO_CLASS_HANDLE baseType, /* IN */ + int maxExactClasses, /* IN */ + CORINFO_CLASS_HANDLE* exactClsRet /* OUT */ + ) +{ + jitInstance->mc->cr->AddCall("getExactClasses"); + return jitInstance->mc->repGetExactClasses(baseType, maxExactClasses, exactClsRet); +} + // If the Arg is a CORINFO_TYPE_CLASS fetch the class handle associated with it CORINFO_CLASS_HANDLE MyICJI::getArgClass(CORINFO_SIG_INFO* sig, /* IN */ CORINFO_ARG_LIST_HANDLE args /* IN */ diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index e43d31f630ad9..3163a59344008 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9458,6 +9458,32 @@ uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE c /*********************************************************************/ +int CEEInfo::getExactClasses ( + CORINFO_CLASS_HANDLE baseType, + int maxExactClasses, + CORINFO_CLASS_HANDLE* exactClsRet + ) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } CONTRACTL_END; + + int exactClassesCount = 0; + + JIT_TO_EE_TRANSITION(); + + // This function is currently implemented only on NativeAOT + // but can be implemented for CoreCLR as well (e.g. for internal types) + + EE_TO_JIT_TRANSITION(); + + return exactClassesCount; +} + +/*********************************************************************/ + CORINFO_CLASS_HANDLE CEEInfo::getArgClass ( CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args