Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7562,6 +7562,7 @@ class Compiler
unsigned likelihood,
bool arrayInterface,
bool instantiatingStub,
CORINFO_METHOD_HANDLE originalMethodHandle,
CORINFO_CONTEXT_HANDLE originalContextHandle);

int getGDVMaxTypeChecks()
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/fginline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,8 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitor<Substi

CORINFO_METHOD_HANDLE GetMethodHandle(GenTreeCall* call)
{
JITDUMP("GetMethodHandle: [%06u]\n", m_compiler->dspTreeID(call));

assert(call->IsDevirtualizationCandidate(m_compiler));
if (call->IsVirtual())
{
Expand All @@ -556,6 +558,9 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitor<Substi
GenTree* runtimeMethHndNode =
call->gtCallAddr->AsCall()->gtArgs.FindWellKnownArg(WellKnownArg::RuntimeMethodHandle)->GetNode();
assert(runtimeMethHndNode != nullptr);

JITDUMP(" ... via node [%06u]\n", m_compiler->dspTreeID(runtimeMethHndNode));

switch (runtimeMethHndNode->OperGet())
{
case GT_RUNTIMELOOKUP:
Expand Down
5 changes: 4 additions & 1 deletion src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6947,7 +6947,10 @@ void Compiler::impImportBlockCode(BasicBlock* block)
}
else if (call->IsGuardedDevirtualizationCandidate())
{
JITDUMP("No GDV IEnumerable<T> check for [%06u]\n", dspTreeID(call));
// Just check one of the GDV candidates (all should have the same original method handle)
//
InlineCandidateInfo* const info = call->GetGDVCandidateInfo(0);
ni = lookupNamedIntrinsic(info->originalMethodHandle);
}

if (ni == NI_System_Collections_Generic_IEnumerable_GetEnumerator)
Expand Down
32 changes: 24 additions & 8 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,14 +310,17 @@ var_types Compiler::impImportCall(OPCODE opcode,
// complex expression. As it is evaluated after the args,
// it may cause registered args to be spilled. Simply spill it.
//
unsigned const lclNum = lvaGrabTemp(true DEBUGARG("VirtualCall with runtime lookup"));
if (compDonotInline())
if (!stubAddr->OperIs(GT_LCL_VAR))
{
return TYP_UNDEF;
}
unsigned const lclNum = lvaGrabTemp(true DEBUGARG("VirtualCall with runtime lookup"));
if (compDonotInline())
{
return TYP_UNDEF;
}

impStoreToTemp(lclNum, stubAddr, CHECK_SPILL_NONE);
stubAddr = gtNewLclvNode(lclNum, TYP_I_IMPL);
impStoreToTemp(lclNum, stubAddr, CHECK_SPILL_NONE);
stubAddr = gtNewLclvNode(lclNum, TYP_I_IMPL);
}

// Create the actual call node

Expand Down Expand Up @@ -7212,7 +7215,7 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call,

addGuardedDevirtualizationCandidate(call, exactMethod, exactCls, exactContext, exactMethodAttrs,
clsAttrs, likelyHood, dvInfo.wasArrayInterfaceDevirt,
dvInfo.isInstantiatingStub, originalContext);
dvInfo.isInstantiatingStub, baseMethod, originalContext);
}

if (call->GetInlineCandidatesCount() == numExactClasses)
Expand Down Expand Up @@ -7361,7 +7364,7 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call,
//
addGuardedDevirtualizationCandidate(call, likelyMethod, likelyClass, likelyContext, likelyMethodAttribs,
likelyClassAttribs, likelihood, arrayInterface, instantiatingStub,
originalContext);
baseMethod, originalContext);
}
}

Expand All @@ -7388,6 +7391,7 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call,
// likelihood - odds that this class is the class seen at runtime
// arrayInterface - devirtualization of an array interface call
// instantiatingStub - devirtualized method in an instantiating stub
// originalMethodHandle - method handle of base method (before devirt)
// originalContextHandle - context for the original call
//
void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call,
Expand All @@ -7399,6 +7403,7 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call,
unsigned likelihood,
bool arrayInterface,
bool instantiatingStub,
CORINFO_METHOD_HANDLE originalMethodHandle,
CORINFO_CONTEXT_HANDLE originalContextHandle)
{
// This transformation only makes sense for delegate and virtual calls
Expand Down Expand Up @@ -7471,6 +7476,7 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call,
pInfo->guardedMethodUnboxedEntryHandle = nullptr;
pInfo->guardedMethodInstantiatedEntryHandle = nullptr;
pInfo->guardedClassHandle = classHandle;
pInfo->originalMethodHandle = originalMethodHandle;
pInfo->originalContextHandle = originalContextHandle;
pInfo->likelihood = likelihood;
pInfo->exactContextHandle = contextHandle;
Expand Down Expand Up @@ -8399,6 +8405,15 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
return;
}

// If we don't know the array type exactly we may have the wrong interface type here.
// Bail out.
//
if (!isExact)
{
JITDUMP("Array interface devirt: array type is inexact, sorry.\n");
return;
}

// We want to inline the instantiating stub. Fetch the relevant info.
//
CORINFO_CLASS_HANDLE ignored = NO_CLASS_HANDLE;
Expand Down Expand Up @@ -9371,6 +9386,7 @@ void Compiler::impCheckCanInline(GenTreeCall* call,
pInfo->guardedMethodHandle = nullptr;
pInfo->guardedMethodUnboxedEntryHandle = nullptr;
pInfo->guardedMethodInstantiatedEntryHandle = nullptr;
pInfo->originalMethodHandle = nullptr;
pInfo->originalContextHandle = nullptr;
pInfo->likelihood = 0;
pInfo->arrayInterface = false;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/indirectcalltransformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ class IndirectCallTransformer
//
if (inlineInfo->arrayInterface)
{
methodHnd = call->gtCallMethHnd;
methodHnd = inlineInfo->originalMethodHandle;
context = inlineInfo->originalContextHandle;
}

Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,10 @@ struct InlineCandidateInfo : public HandleHistogramProfileCandidateInfo
//
CORINFO_CONTEXT_HANDLE exactContextHandle;

// Context handle of the call before any
// Method and context handle of the call before any
// GDV/Inlining evaluation
//
CORINFO_METHOD_HANDLE originalMethodHandle;
CORINFO_CONTEXT_HANDLE originalContextHandle;

// The GT_RET_EXPR node linking back to the inline candidate.
Expand Down
25 changes: 17 additions & 8 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8621,18 +8621,15 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
//
if (pObjMT->IsArray())
{
// If we're in a shared context we'll devirt to a shared
// generic method and won't be able to inline, so just bail.
// See if this interface is one of the ones arrays implement.
//
if (pBaseMT->IsSharedByGenericInstantiations())
if (!pBaseMT->HasInstantiation())
{
info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST;
return false;
}

// Ensure we can cast the array to the interface type
//
if (!TypeHandle(pObjMT).CanCastTo(TypeHandle(pBaseMT)))
if (!IsImplicitInterfaceOfSZArray(pBaseMT))
{
info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST;
return false;
Expand All @@ -8650,7 +8647,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
{
MethodTable* interfaceMT = nullptr;

if (pObjMT->IsSharedByGenericInstantiations() || pBaseMT->IsSharedByGenericInstantiations())
if (!pObjMT->IsArray() && (pObjMT->IsSharedByGenericInstantiations() || pBaseMT->IsSharedByGenericInstantiations()))
{
MethodTable* pCanonBaseMT = pBaseMT->GetCanonicalMethodTable();

Expand Down Expand Up @@ -8687,6 +8684,18 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)

pDevirtMD = pObjMT->GetMethodDescForInterfaceMethod(TypeHandle(interfaceMT), pBaseMD, FALSE /* throwOnConflict */);
}
else if (pObjMT->IsArray())
{
// We cannot devirtualize unless we know the exact array element type
//
TypeHandle elemType = pObjMT->GetArrayElementTypeHandle();
if (elemType.IsCanonicalSubtype())
{
info->detail = CORINFO_DEVIRTUALIZATION_FAILED_LOOKUP;
return false;
}
pDevirtMD = GetActualImplementationForArrayGenericIListOrIReadOnlyListMethod(pBaseMD, elemType);
}
else
{
pDevirtMD = pObjMT->GetMethodDescForInterfaceMethod(TypeHandle(pBaseMT), pBaseMD, FALSE /* throwOnConflict */);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ internal sealed class SZGenericArrayEnumerator<T> : SZGenericArrayEnumeratorBase
/// </remarks>
internal static readonly SZGenericArrayEnumerator<T> Empty = new SZGenericArrayEnumerator<T>(null, 0);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal SZGenericArrayEnumerator(T[]? array, int endIndex)
: base(endIndex)
{
Expand Down
Loading