Skip to content

Commit d9f2afd

Browse files
committed
avoid changing explicit tail call target to unboxed entry
1 parent e947422 commit d9f2afd

File tree

1 file changed

+83
-70
lines changed

1 file changed

+83
-70
lines changed

src/coreclr/jit/importer.cpp

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -21009,105 +21009,118 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
2100921009

2101021010
if (unboxedEntryMethod != nullptr)
2101121011
{
21012-
bool optimizedTheBox = false;
21012+
bool didOptimize = false;
21013+
bool canOptimize = false;
2101321014

2101421015
// If the 'this' object is a local box, see if we can revise things
2101521016
// to not require boxing.
2101621017
//
21017-
if (thisObj->IsBoxedValue() && !isExplicitTailCall)
21018+
if (thisObj->IsBoxedValue())
2101821019
{
21019-
// Since the call is the only consumer of the box, we know the box can't escape
21020-
// since it is being passed an interior pointer.
21021-
//
21022-
// So, revise the box to simply create a local copy, use the address of that copy
21023-
// as the this pointer, and update the entry point to the unboxed entry.
21024-
//
21025-
// Ideally, we then inline the boxed method and and if it turns out not to modify
21026-
// the copy, we can undo the copy too.
21027-
if (requiresInstMethodTableArg)
21020+
if (isExplicitTailCall)
2102821021
{
21029-
// Perform a trial box removal and ask for the type handle tree that fed the box.
21022+
// We won't optimize away boxes that feed explicit tail calls, as ensuring
21023+
// we get the right tail call info is tricky (we'd need to pass an updated
21024+
// sig and resolved token back to some callers).
2103021025
//
21031-
JITDUMP("Unboxed entry needs method table arg...\n");
21032-
GenTree* methodTableArg = gtTryRemoveBoxUpstreamEffects(thisObj, BR_DONT_REMOVE_WANT_TYPE_HANDLE);
21033-
21034-
if (methodTableArg != nullptr)
21026+
canOptimize = false;
21027+
}
21028+
else
21029+
{
21030+
// Since the call is the only consumer of the box, we know the box can't escape
21031+
// since it is being passed an interior pointer.
21032+
//
21033+
// So, revise the box to simply create a local copy, use the address of that copy
21034+
// as the this pointer, and update the entry point to the unboxed entry.
21035+
//
21036+
// Ideally, we then inline the boxed method and and if it turns out not to modify
21037+
// the copy, we can undo the copy too.
21038+
if (requiresInstMethodTableArg)
2103521039
{
21036-
// If that worked, turn the box into a copy to a local var
21040+
// Perform a trial box removal and ask for the type handle tree that fed the box.
2103721041
//
21038-
JITDUMP("Found suitable method table arg tree [%06u]\n", dspTreeID(methodTableArg));
21039-
GenTree* localCopyThis = gtTryRemoveBoxUpstreamEffects(thisObj, BR_MAKE_LOCAL_COPY);
21042+
JITDUMP("Unboxed entry needs method table arg...\n");
21043+
GenTree* methodTableArg =
21044+
gtTryRemoveBoxUpstreamEffects(thisObj, BR_DONT_REMOVE_WANT_TYPE_HANDLE);
2104021045

21041-
if (localCopyThis != nullptr)
21046+
if (methodTableArg != nullptr)
2104221047
{
21043-
// Pass the local var as this and the type handle as a new arg
21048+
// If that worked, turn the box into a copy to a local var
2104421049
//
21045-
JITDUMP(
21046-
"Success! invoking unboxed entry point on local copy, and passing method table arg\n");
21047-
call->gtCallThisArg = gtNewCallArgs(localCopyThis);
21048-
call->gtCallMoreFlags |= GTF_CALL_M_UNBOXED;
21050+
JITDUMP("Found suitable method table arg tree [%06u]\n", dspTreeID(methodTableArg));
21051+
GenTree* localCopyThis = gtTryRemoveBoxUpstreamEffects(thisObj, BR_MAKE_LOCAL_COPY);
2104921052

21050-
// Prepend for R2L arg passing or empty L2R passing
21051-
// Append for non-empty L2R
21052-
//
21053-
if ((Target::g_tgtArgOrder == Target::ARG_ORDER_R2L) || (call->gtCallArgs == nullptr))
21054-
{
21055-
call->gtCallArgs = gtPrependNewCallArg(methodTableArg, call->gtCallArgs);
21056-
}
21057-
else
21053+
if (localCopyThis != nullptr)
2105821054
{
21059-
GenTreeCall::Use* beforeArg = call->gtCallArgs;
21060-
while (beforeArg->GetNext() != nullptr)
21055+
// Pass the local var as this and the type handle as a new arg
21056+
//
21057+
JITDUMP("Success! invoking unboxed entry point on local copy, and passing method table "
21058+
"arg\n");
21059+
call->gtCallThisArg = gtNewCallArgs(localCopyThis);
21060+
call->gtCallMoreFlags |= GTF_CALL_M_UNBOXED;
21061+
21062+
// Prepend for R2L arg passing or empty L2R passing
21063+
// Append for non-empty L2R
21064+
//
21065+
if ((Target::g_tgtArgOrder == Target::ARG_ORDER_R2L) || (call->gtCallArgs == nullptr))
2106121066
{
21062-
beforeArg = beforeArg->GetNext();
21067+
call->gtCallArgs = gtPrependNewCallArg(methodTableArg, call->gtCallArgs);
2106321068
}
21069+
else
21070+
{
21071+
GenTreeCall::Use* beforeArg = call->gtCallArgs;
21072+
while (beforeArg->GetNext() != nullptr)
21073+
{
21074+
beforeArg = beforeArg->GetNext();
21075+
}
2106421076

21065-
beforeArg->SetNext(gtNewCallArgs(methodTableArg));
21066-
}
21077+
beforeArg->SetNext(gtNewCallArgs(methodTableArg));
21078+
}
2106721079

21068-
call->gtCallMethHnd = unboxedEntryMethod;
21069-
derivedMethod = unboxedEntryMethod;
21080+
call->gtCallMethHnd = unboxedEntryMethod;
21081+
derivedMethod = unboxedEntryMethod;
2107021082

21071-
// Method attributes will differ because unboxed entry point is shared
21072-
//
21073-
const DWORD unboxedMethodAttribs = info.compCompHnd->getMethodAttribs(unboxedEntryMethod);
21074-
JITDUMP("Updating method attribs from 0x%08x to 0x%08x\n", derivedMethodAttribs,
21075-
unboxedMethodAttribs);
21076-
derivedMethodAttribs = unboxedMethodAttribs;
21077-
optimizedTheBox = true;
21083+
// Method attributes will differ because unboxed entry point is shared
21084+
//
21085+
const DWORD unboxedMethodAttribs =
21086+
info.compCompHnd->getMethodAttribs(unboxedEntryMethod);
21087+
JITDUMP("Updating method attribs from 0x%08x to 0x%08x\n", derivedMethodAttribs,
21088+
unboxedMethodAttribs);
21089+
derivedMethodAttribs = unboxedMethodAttribs;
21090+
didOptimize = true;
21091+
}
21092+
else
21093+
{
21094+
JITDUMP("Sorry, failed to undo the box -- can't convert to local copy\n");
21095+
}
2107821096
}
2107921097
else
2108021098
{
21081-
JITDUMP("Sorry, failed to undo the box -- can't convert to local copy\n");
21099+
JITDUMP("Sorry, failed to undo the box -- can't find method table arg\n");
2108221100
}
2108321101
}
2108421102
else
2108521103
{
21086-
JITDUMP("Sorry, failed to undo the box -- can't find method table arg\n");
21087-
}
21088-
}
21089-
else
21090-
{
21091-
JITDUMP("Found unboxed entry point, trying to simplify box to a local copy\n");
21092-
GenTree* localCopyThis = gtTryRemoveBoxUpstreamEffects(thisObj, BR_MAKE_LOCAL_COPY);
21093-
21094-
if (localCopyThis != nullptr)
21095-
{
21096-
JITDUMP("Success! invoking unboxed entry point on local copy\n");
21097-
call->gtCallThisArg = gtNewCallArgs(localCopyThis);
21098-
call->gtCallMethHnd = unboxedEntryMethod;
21099-
call->gtCallMoreFlags |= GTF_CALL_M_UNBOXED;
21100-
derivedMethod = unboxedEntryMethod;
21104+
JITDUMP("Found unboxed entry point, trying to simplify box to a local copy\n");
21105+
GenTree* localCopyThis = gtTryRemoveBoxUpstreamEffects(thisObj, BR_MAKE_LOCAL_COPY);
2110121106

21102-
optimizedTheBox = true;
21103-
}
21104-
else
21105-
{
21106-
JITDUMP("Sorry, failed to undo the box\n");
21107+
if (localCopyThis != nullptr)
21108+
{
21109+
JITDUMP("Success! invoking unboxed entry point on local copy\n");
21110+
call->gtCallThisArg = gtNewCallArgs(localCopyThis);
21111+
call->gtCallMethHnd = unboxedEntryMethod;
21112+
call->gtCallMoreFlags |= GTF_CALL_M_UNBOXED;
21113+
derivedMethod = unboxedEntryMethod;
21114+
didOptimize = true;
21115+
}
21116+
else
21117+
{
21118+
JITDUMP("Sorry, failed to undo the box\n");
21119+
}
2110721120
}
2110821121
}
2110921122

21110-
if (optimizedTheBox)
21123+
if (didOptimize)
2111121124
{
2111221125

2111321126
#if FEATURE_TAILCALL_OPT
@@ -21124,7 +21137,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
2112421137
}
2112521138
}
2112621139

21127-
if (!optimizedTheBox)
21140+
if (canOptimize && !didOptimize)
2112821141
{
2112921142
// If we get here, we have a boxed value class that either wasn't boxed
2113021143
// locally, or was boxed locally but we were unable to remove the box for

0 commit comments

Comments
 (0)