Skip to content

Commit da98e91

Browse files
hez2010Copilot
andauthored
Support devirtualizing non-shared GVMs in R2R (#123183)
Implement the support for GVM devirtualization in managed type system. It shares the same issue in #122023 where we are still not able to devirt shared GVMs due to lacking a proper generic context, so let's do the non-shared case first. NativeAOT still not supported yet as it requires some work in the JIT to stop spilling the helper call for fat pointers. Contributes to #112596 /cc: @MichalStrehovsky @jakobbotsch --------- Co-authored-by: Copilot <[email protected]>
1 parent 1555505 commit da98e91

File tree

8 files changed

+57
-21
lines changed

8 files changed

+57
-21
lines changed

src/coreclr/inc/corinfo.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,6 @@ enum CORINFO_DEVIRTUALIZATION_DETAIL
15581558
CORINFO_DEVIRTUALIZATION_FAILED_DUPLICATE_INTERFACE, // crossgen2 virtual method algorithm and runtime algorithm differ in the presence of duplicate interface implementations
15591559
CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE, // Decl method cannot be represented in R2R image
15601560
CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE, // Support for type equivalence in devirtualization is not yet implemented in crossgen2
1561-
CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL, // Devirtualization of generic virtual methods is not yet implemented in crossgen2
15621561
CORINFO_DEVIRTUALIZATION_COUNT, // sentinel for maximum value
15631562
};
15641563

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737

3838
#include <minipal/guid.h>
3939

40-
constexpr GUID JITEEVersionIdentifier = { /* 9068c4e3-6a0a-4347-a754-9ff2d63a1207 */
41-
0x9068c4e3,
42-
0x6a0a,
43-
0x4347,
44-
{0xa7, 0x54, 0x9f, 0xf2, 0xd6, 0x3a, 0x12, 0x07}
40+
constexpr GUID JITEEVersionIdentifier = { /* c10e2acf-7c94-4c61-b895-5178602e0e1e */
41+
0xc10e2acf,
42+
0x7c94,
43+
0x4c61,
44+
{0xb8, 0x95, 0x51, 0x78, 0x60, 0x2e, 0x0e, 0x1e}
4545
};
4646

4747
#endif // JIT_EE_VERSIONING_GUID_H

src/coreclr/jit/compiler.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10482,7 +10482,7 @@ const char* Compiler::devirtualizationDetailToString(CORINFO_DEVIRTUALIZATION_DE
1048210482
case CORINFO_DEVIRTUALIZATION_SUCCESS:
1048310483
return "success";
1048410484
case CORINFO_DEVIRTUALIZATION_FAILED_CANON:
10485-
return "object class was canonical";
10485+
return "object class or method was canonical";
1048610486
case CORINFO_DEVIRTUALIZATION_FAILED_COM:
1048710487
return "object class was com";
1048810488
case CORINFO_DEVIRTUALIZATION_FAILED_CAST:
@@ -10516,8 +10516,6 @@ const char* Compiler::devirtualizationDetailToString(CORINFO_DEVIRTUALIZATION_DE
1051610516
return "Decl method cannot be represented in R2R image";
1051710517
case CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE:
1051810518
return "Support for type equivalence in devirtualization is not yet implemented in crossgen2";
10519-
case CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL:
10520-
return "Devirtualization of generic virtual methods is not yet implemented in crossgen2";
1052110519
default:
1052210520
return "undefined";
1052310521
}

src/coreclr/jit/gentree.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5275,8 +5275,13 @@ struct GenTreeCall final : public GenTree
52755275
}
52765276
bool IsGenericVirtual(Compiler* compiler) const
52775277
{
5278-
return (gtCallType == CT_INDIRECT && (gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_VIRTUAL_FUNC_PTR) ||
5279-
gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_GVMLOOKUP_FOR_SLOT)));
5278+
return (gtCallType == CT_INDIRECT &&
5279+
(gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_VIRTUAL_FUNC_PTR) ||
5280+
gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_GVMLOOKUP_FOR_SLOT)
5281+
#ifdef FEATURE_READYTORUN
5282+
|| gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR)
5283+
#endif
5284+
));
52805285
}
52815286

52825287
bool IsDevirtualizationCandidate(Compiler* compiler) const;

src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
6666
{
6767
devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_UNKNOWN;
6868

69+
MethodDesc originalDeclMethod = declMethod;
6970
MethodDesc impl;
7071

7172
if (declMethod.OwningType.IsInterface)
@@ -100,9 +101,19 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
100101
}
101102

102103
impl = implType.ResolveInterfaceMethodTargetWithVariance(declMethod);
104+
103105
if (impl != null)
104106
{
105107
impl = implType.FindVirtualFunctionTargetMethodOnObjectType(impl);
108+
109+
// We need to bring the original instantiation back so that we can still try devirtualizing
110+
// when the method is a generic virtual method
111+
if (impl != null && originalDeclMethod.HasInstantiation)
112+
{
113+
// We may end up with a method that has substituted type parameters, so we need to instantiate
114+
// on the method definition
115+
impl = impl.GetMethodDefinition().MakeInstantiatedMethod(originalDeclMethod.Instantiation);
116+
}
106117
}
107118
else
108119
{
@@ -178,9 +189,19 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
178189
}
179190

180191
impl = implType.FindVirtualFunctionTargetMethodOnObjectType(declMethod);
192+
193+
// We need to bring the original instantiation back so that we can still try devirtualizing
194+
// when the method is a generic virtual method
195+
if (impl != null && originalDeclMethod.HasInstantiation)
196+
{
197+
// We may end up with a method that has substituted type parameters, so we need to instantiate
198+
// on the method definition
199+
impl = impl.GetMethodDefinition().MakeInstantiatedMethod(originalDeclMethod.Instantiation);
200+
}
201+
181202
if (impl != null && (impl != declMethod))
182203
{
183-
MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl);
204+
MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl.GetMethodDefinition());
184205
MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod);
185206

186207
if (slotDefiningMethodImpl != slotDefiningMethodDecl)
@@ -198,6 +219,13 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
198219
}
199220
}
200221

222+
if (impl != null && impl.HasInstantiation && impl.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific))
223+
{
224+
// We don't support devirtualization of shared generic virtual methods yet.
225+
devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
226+
impl = null;
227+
}
228+
201229
return impl;
202230
}
203231

src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,13 +1340,6 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
13401340
// Transform from the unboxing thunk to the normal method
13411341
decl = decl.IsUnboxingThunk() ? decl.GetUnboxedMethod() : decl;
13421342

1343-
if (decl.HasInstantiation)
1344-
{
1345-
// We cannot devirtualize generic virtual methods in AOT yet
1346-
info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL;
1347-
return false;
1348-
}
1349-
13501343
if ((info->context != null) && decl.OwningType.IsInterface)
13511344
{
13521345
TypeDesc ownerTypeDesc = typeFromContext(info->context);

src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,7 @@ public enum CORINFO_DEVIRTUALIZATION_DETAIL
11261126
{
11271127
CORINFO_DEVIRTUALIZATION_UNKNOWN, // no details available
11281128
CORINFO_DEVIRTUALIZATION_SUCCESS, // devirtualization was successful
1129-
CORINFO_DEVIRTUALIZATION_FAILED_CANON, // object class was canonical
1129+
CORINFO_DEVIRTUALIZATION_FAILED_CANON, // object class or method was canonical
11301130
CORINFO_DEVIRTUALIZATION_FAILED_COM, // object class was com
11311131
CORINFO_DEVIRTUALIZATION_FAILED_CAST, // object class could not be cast to interface class
11321132
CORINFO_DEVIRTUALIZATION_FAILED_LOOKUP, // interface method could not be found
@@ -1142,7 +1142,6 @@ public enum CORINFO_DEVIRTUALIZATION_DETAIL
11421142
CORINFO_DEVIRTUALIZATION_FAILED_DUPLICATE_INTERFACE, // crossgen2 virtual method algorithm and runtime algorithm differ in the presence of duplicate interface implementations
11431143
CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE, // Decl method cannot be represented in R2R image
11441144
CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE, // Support for type equivalence in devirtualization is not yet implemented in crossgen2
1145-
CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL, // Devirtualization of generic virtual methods is not yet implemented in crossgen2
11461145
CORINFO_DEVIRTUALIZATION_COUNT, // sentinel for maximum value
11471146
}
11481147

src/coreclr/vm/jitinterface.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14298,6 +14298,20 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
1429814298
}
1429914299
}
1430014300

14301+
// Strip off method instantiation for comparison if the method is generic virtual.
14302+
if (pDeclMethod->HasMethodInstantiation())
14303+
{
14304+
if (pImplMethodRuntime != NULL)
14305+
{
14306+
pImplMethodRuntime = pImplMethodRuntime->StripMethodInstantiation();
14307+
}
14308+
14309+
if (pImplMethodCompiler != NULL)
14310+
{
14311+
pImplMethodCompiler = pImplMethodCompiler->StripMethodInstantiation();
14312+
}
14313+
}
14314+
1430114315
if (pImplMethodRuntime != pImplMethodCompiler)
1430214316
{
1430314317
if (kind == READYTORUN_FIXUP_Check_VirtualFunctionOverride)

0 commit comments

Comments
 (0)