Skip to content
1 change: 0 additions & 1 deletion src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@

#include <minipal/guid.h>

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
4 changes: 1 addition & 3 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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";
}
Expand Down
9 changes: 7 additions & 2 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
30 changes: 29 additions & 1 deletion src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
7 changes: 0 additions & 7 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}

Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading