diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 07c169161a1028..9f84c02eb97842 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1558,7 +1558,6 @@ enum CORINFO_DEVIRTUALIZATION_DETAIL CORINFO_DEVIRTUALIZATION_FAILED_DUPLICATE_INTERFACE, // crossgen2 virtual method algorithm and runtime algorithm differ in the presence of duplicate interface implementations CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE, // Decl method cannot be represented in R2R image CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE, // Support for type equivalence in devirtualization is not yet implemented in crossgen2 - CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL, // Devirtualization of generic virtual methods is not yet implemented in crossgen2 CORINFO_DEVIRTUALIZATION_COUNT, // sentinel for maximum value }; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 5b17e9c7ca5119..c0614ed35209d0 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -37,11 +37,11 @@ #include -constexpr GUID JITEEVersionIdentifier = { /* 9068c4e3-6a0a-4347-a754-9ff2d63a1207 */ - 0x9068c4e3, - 0x6a0a, - 0x4347, - {0xa7, 0x54, 0x9f, 0xf2, 0xd6, 0x3a, 0x12, 0x07} +constexpr GUID JITEEVersionIdentifier = { /* c10e2acf-7c94-4c61-b895-5178602e0e1e */ + 0xc10e2acf, + 0x7c94, + 0x4c61, + {0xb8, 0x95, 0x51, 0x78, 0x60, 0x2e, 0x0e, 0x1e} }; #endif // JIT_EE_VERSIONING_GUID_H diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index d3bc2641d63acd..8132be20d978a2 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -10486,7 +10486,7 @@ const char* Compiler::devirtualizationDetailToString(CORINFO_DEVIRTUALIZATION_DE case CORINFO_DEVIRTUALIZATION_SUCCESS: return "success"; case CORINFO_DEVIRTUALIZATION_FAILED_CANON: - return "object class was canonical"; + return "object class or method was canonical"; case CORINFO_DEVIRTUALIZATION_FAILED_COM: return "object class was com"; case CORINFO_DEVIRTUALIZATION_FAILED_CAST: @@ -10520,8 +10520,6 @@ const char* Compiler::devirtualizationDetailToString(CORINFO_DEVIRTUALIZATION_DE return "Decl method cannot be represented in R2R image"; case CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE: return "Support for type equivalence in devirtualization is not yet implemented in crossgen2"; - case CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL: - return "Devirtualization of generic virtual methods is not yet implemented in crossgen2"; default: return "undefined"; } diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 045505af84421b..7cad1de39e3f5b 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -5275,8 +5275,13 @@ struct GenTreeCall final : public GenTree } bool IsGenericVirtual(Compiler* compiler) const { - return (gtCallType == CT_INDIRECT && (gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_VIRTUAL_FUNC_PTR) || - gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_GVMLOOKUP_FOR_SLOT))); + return (gtCallType == CT_INDIRECT && + (gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_VIRTUAL_FUNC_PTR) || + gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_GVMLOOKUP_FOR_SLOT) +#ifdef FEATURE_READYTORUN + || gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR) +#endif + )); } bool IsDevirtualizationCandidate(Compiler* compiler) const; diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs index f704807c0c0841..ac544ed02e3fea 100644 --- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs +++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs @@ -66,6 +66,7 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType { devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_UNKNOWN; + MethodDesc originalDeclMethod = declMethod; MethodDesc impl; if (declMethod.OwningType.IsInterface) @@ -100,9 +101,19 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType } impl = implType.ResolveInterfaceMethodTargetWithVariance(declMethod); + if (impl != null) { impl = implType.FindVirtualFunctionTargetMethodOnObjectType(impl); + + // We need to bring the original instantiation back so that we can still try devirtualizing + // when the method is a generic virtual method + if (impl != null && originalDeclMethod.HasInstantiation) + { + // We may end up with a method that has substituted type parameters, so we need to instantiate + // on the method definition + impl = impl.GetMethodDefinition().MakeInstantiatedMethod(originalDeclMethod.Instantiation); + } } else { @@ -178,9 +189,19 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType } impl = implType.FindVirtualFunctionTargetMethodOnObjectType(declMethod); + + // We need to bring the original instantiation back so that we can still try devirtualizing + // when the method is a generic virtual method + if (impl != null && originalDeclMethod.HasInstantiation) + { + // We may end up with a method that has substituted type parameters, so we need to instantiate + // on the method definition + impl = impl.GetMethodDefinition().MakeInstantiatedMethod(originalDeclMethod.Instantiation); + } + if (impl != null && (impl != declMethod)) { - MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl); + MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl.GetMethodDefinition()); MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod); if (slotDefiningMethodImpl != slotDefiningMethodDecl) @@ -198,6 +219,13 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType } } + if (impl != null && impl.HasInstantiation && impl.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific)) + { + // We don't support devirtualization of shared generic virtual methods yet. + devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON; + impl = null; + } + return impl; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 7723e347baffeb..3bec9f58e1ced3 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1340,13 +1340,6 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) // Transform from the unboxing thunk to the normal method decl = decl.IsUnboxingThunk() ? decl.GetUnboxedMethod() : decl; - if (decl.HasInstantiation) - { - // We cannot devirtualize generic virtual methods in AOT yet - info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL; - return false; - } - if ((info->context != null) && decl.OwningType.IsInterface) { TypeDesc ownerTypeDesc = typeFromContext(info->context); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index edbcb331cf2058..1276cbf749c8ff 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1126,7 +1126,7 @@ public enum CORINFO_DEVIRTUALIZATION_DETAIL { CORINFO_DEVIRTUALIZATION_UNKNOWN, // no details available CORINFO_DEVIRTUALIZATION_SUCCESS, // devirtualization was successful - CORINFO_DEVIRTUALIZATION_FAILED_CANON, // object class was canonical + CORINFO_DEVIRTUALIZATION_FAILED_CANON, // object class or method was canonical CORINFO_DEVIRTUALIZATION_FAILED_COM, // object class was com CORINFO_DEVIRTUALIZATION_FAILED_CAST, // object class could not be cast to interface class CORINFO_DEVIRTUALIZATION_FAILED_LOOKUP, // interface method could not be found @@ -1142,7 +1142,6 @@ public enum CORINFO_DEVIRTUALIZATION_DETAIL CORINFO_DEVIRTUALIZATION_FAILED_DUPLICATE_INTERFACE, // crossgen2 virtual method algorithm and runtime algorithm differ in the presence of duplicate interface implementations CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE, // Decl method cannot be represented in R2R image CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE, // Support for type equivalence in devirtualization is not yet implemented in crossgen2 - CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL, // Devirtualization of generic virtual methods is not yet implemented in crossgen2 CORINFO_DEVIRTUALIZATION_COUNT, // sentinel for maximum value } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 8254617caef995..d93d1d588fcbf3 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -14298,6 +14298,20 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, } } + // Strip off method instantiation for comparison if the method is generic virtual. + if (pDeclMethod->HasMethodInstantiation()) + { + if (pImplMethodRuntime != NULL) + { + pImplMethodRuntime = pImplMethodRuntime->StripMethodInstantiation(); + } + + if (pImplMethodCompiler != NULL) + { + pImplMethodCompiler = pImplMethodCompiler->StripMethodInstantiation(); + } + } + if (pImplMethodRuntime != pImplMethodCompiler) { if (kind == READYTORUN_FIXUP_Check_VirtualFunctionOverride)