Skip to content

Commit

Permalink
JIT: devirtualization support for EqualityComparer<T>.Default
Browse files Browse the repository at this point in the history
Mark `EqualityComparer<T>.Default`'s getter as `[Intrinsic]` so
the jit knows there is something special about it. Extend the jit's
named intrinsic recognizer to recognize this method.

Add a new jit interface method to determine the exact type returned
by `EqualityComparer<T>.Default`, given `T`. Compute the return type by
mirroring the logic used in the actual implementation.

Invoke this interface method when trying to devirtualize calls where
the 'this' object in the call comes from `EqualityComparer<T>.Default`.
Handle both the early and late devirtualization possibilties.

The devirtualized method can then be inlined if devirtualization
happens early; inlining uses the normal jit heuristics here.

Closes #6688.
  • Loading branch information
AndyAyersMS committed Sep 24, 2017
1 parent bfaad96 commit d953528
Show file tree
Hide file tree
Showing 14 changed files with 335 additions and 52 deletions.
8 changes: 8 additions & 0 deletions src/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -2085,6 +2085,14 @@ class ICorStaticInfo
CORINFO_CONTEXT_HANDLE ownerType = NULL /* IN */
) = 0;

// Given T, return the type of the default EqualityComparer<T>.
// Returns null if the type can't be determined exactly.
virtual CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(
CORINFO_CLASS_HANDLE elemType
)
// Stub implementation to keep PREJIT/SPMI off our backs for now
{ return NULL; }

// Given resolved token that corresponds to an intrinsic classified as
// a CORINFO_INTRINSIC_GetRawHandle intrinsic, fetch the handle associated
// with the token. If this is not possible at compile-time (because the current method's
Expand Down
10 changes: 7 additions & 3 deletions src/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2075,7 +2075,9 @@ class Compiler

GenTreePtr gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
GenTreePtr gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate, var_types type);
GenTreePtr gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate,
var_types type,
CORINFO_METHOD_HANDLE calleeMethodHnd);

GenTreePtr gtNewCodeRef(BasicBlock* block);

Expand Down Expand Up @@ -2964,11 +2966,13 @@ class Compiler
IL_OFFSET rawILOffset);

void impDevirtualizeCall(GenTreeCall* call,
GenTreePtr thisObj,
CORINFO_METHOD_HANDLE* method,
unsigned* methodFlags,
CORINFO_CONTEXT_HANDLE* contextHandle,
CORINFO_CONTEXT_HANDLE* exactContextHandle);
CORINFO_CONTEXT_HANDLE* exactContextHandle,
CORINFO_METHOD_HANDLE specialIntrinsicHandle);

CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(CORINFO_METHOD_HANDLE specialIntrinsicHandle);

bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);

Expand Down
19 changes: 14 additions & 5 deletions src/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22157,9 +22157,10 @@ void Compiler::fgAttachStructInlineeToAsg(GenTreePtr tree, GenTreePtr child, COR

Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTreePtr* pTree, fgWalkData* data)
{
GenTreePtr tree = *pTree;
Compiler* comp = data->compiler;
CORINFO_CLASS_HANDLE retClsHnd = NO_CLASS_HANDLE;
GenTreePtr tree = *pTree;
Compiler* comp = data->compiler;
CORINFO_CLASS_HANDLE retClsHnd = NO_CLASS_HANDLE;
CORINFO_METHOD_HANDLE retCalleeHnd = nullptr;

if (tree->gtOper == GT_RET_EXPR)
{
Expand All @@ -22171,6 +22172,14 @@ Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTr
retClsHnd = tree->gtRetExpr.gtRetClsHnd;
}

// If the value is coming from a named intrinsic, remember the intrinsic handle
if (tree->gtRetExpr.gtRetCalleeHnd != nullptr)
{
// We should only see one such
assert(retCalleeHnd == nullptr);
retCalleeHnd = tree->gtRetExpr.gtRetCalleeHnd;
}

do
{
// Obtained the expanded inline candidate
Expand Down Expand Up @@ -22225,15 +22234,15 @@ Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTr
#ifdef DEBUG
if (comp->verbose)
{
printf("**** Late devirt opportunity\n");
printf("**** Late devirt opportunity%s\n", retCalleeHnd == nullptr ? "" : " with named intrinsic");
comp->gtDispTree(call);
}
#endif // DEBUG

CORINFO_METHOD_HANDLE method = call->gtCallMethHnd;
unsigned methodFlags = 0;
CORINFO_CONTEXT_HANDLE context = nullptr;
comp->impDevirtualizeCall(call, tree, &method, &methodFlags, &context, nullptr);
comp->impDevirtualizeCall(call, &method, &methodFlags, &context, nullptr, retCalleeHnd);
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions src/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6414,7 +6414,9 @@ GenTreeLclFld* Compiler::gtNewLclFldNode(unsigned lnum, var_types type, unsigned
return node;
}

GenTreePtr Compiler::gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate, var_types type)
GenTreePtr Compiler::gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate,
var_types type,
CORINFO_METHOD_HANDLE calleeHnd)
{
assert(GenTree::s_gtNodeSizes[GT_RET_EXPR] == TREE_NODE_SZ_LARGE);

Expand All @@ -6432,6 +6434,9 @@ GenTreePtr Compiler::gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate,
// For example, impImportLeave or CEE_POP need to spill GT_RET_EXPR before empty the evaluation stack.
node->gtFlags |= GTF_CALL;

// This will be non-null only if the return is from a special intrinsic method
node->gtRetExpr.gtRetCalleeHnd = calleeHnd;

return node;
}

Expand Down Expand Up @@ -7331,7 +7336,8 @@ GenTreePtr Compiler::gtCloneExpr(
goto DONE;

case GT_RET_EXPR:
copy = gtNewInlineCandidateReturnExpr(tree->gtRetExpr.gtInlineCandidate, tree->gtType);
copy = gtNewInlineCandidateReturnExpr(tree->gtRetExpr.gtInlineCandidate, tree->gtType,
tree->gtRetExpr.gtRetCalleeHnd);
goto DONE;

case GT_MEMORYBARRIER:
Expand Down
6 changes: 3 additions & 3 deletions src/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -4997,9 +4997,9 @@ struct GenTreeStoreInd : public GenTreeIndir

struct GenTreeRetExpr : public GenTree
{
GenTreePtr gtInlineCandidate;

CORINFO_CLASS_HANDLE gtRetClsHnd;
GenTreePtr gtInlineCandidate;
CORINFO_CLASS_HANDLE gtRetClsHnd;
CORINFO_METHOD_HANDLE gtRetCalleeHnd;

GenTreeRetExpr(var_types type) : GenTree(GT_RET_EXPR, type)
{
Expand Down
Loading

0 comments on commit d953528

Please sign in to comment.