info.compCallUnmanaged = 0;
info.compLvFrameListRoot = BAD_VAR_NUM;
- lvaGenericsContextUsed = false;
-
info.compInitMem = ((methodInfo->options & CORINFO_OPT_INIT_LOCALS) != 0);
/* Allocate the local variable table */
unsigned lvaCallEspCheck; // confirms ESP not corrupted after a call
#endif
- bool lvaGenericsContextUsed;
+ unsigned lvaGenericsContextUseCount;
bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
// CORINFO_GENERICS_CTXT_FROM_THIS?
GenTreePtr variableBeingDereferenced,
InlArgInfo* inlArgInfo);
- void impMarkInlineCandidate(GenTreePtr call, CORINFO_CONTEXT_HANDLE exactContextHnd, CORINFO_CALL_INFO* callInfo);
+ void impMarkInlineCandidate(GenTreePtr call,
+ CORINFO_CONTEXT_HANDLE exactContextHnd,
+ bool exactContextNeedsRuntimeLookup,
+ CORINFO_CALL_INFO* callInfo);
bool impTailCallRetTypeCompatible(var_types callerRetType,
CORINFO_CLASS_HANDLE callerRetTypeClass,
return false;
}
+ const bool genericsContextIsThis = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0;
+
#ifdef JIT32_GCENCODER
+
if (info.compFlags & CORINFO_FLG_SYNCH)
return true;
- if (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS)
+ if (genericsContextIsThis)
{
// TODO: Check if any of the exception clauses are
// typed using a generic type. Else, we do not need to report this.
if (opts.compDbgCode)
return true;
- if (lvaGenericsContextUsed)
+ if (lvaGenericsContextUseCount > 0)
+ {
+ JITDUMP("Reporting this as generic context: %u refs\n", lvaGenericsContextUseCount);
return true;
+ }
}
#else // !JIT32_GCENCODER
// If the generics context is the this pointer we need to report it if either
// the VM requires us to keep the generics context alive or it is used in a look-up.
- // We keep it alive in the lookup scenario, even when the VM didn't ask us too
+ // We keep it alive in the lookup scenario, even when the VM didn't ask us to,
// because collectible types need the generics context when gc-ing.
- if ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) &&
- (lvaGenericsContextUsed || (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE)))
+ if (genericsContextIsThis)
{
- return true;
+ const bool isUsed = lvaGenericsContextUseCount > 0;
+ const bool mustKeep = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE) != 0;
+
+ if (isUsed || mustKeep)
+ {
+ JITDUMP("Reporting this as generic context: %u refs%s\n", lvaGenericsContextUseCount,
+ mustKeep ? ", must keep" : "");
+
+ return true;
+ }
}
#endif
// Otherwise, if an exact type parameter is needed in the body, report the generics context.
// We do this because collectible types needs the generics context when gc-ing.
- if (lvaGenericsContextUsed)
+ if (lvaGenericsContextUseCount > 0)
{
return true;
}
// Collectible types requires that for shared generic code, if we use the generic context paramter
// that we report it. (This is a conservative approach, we could detect some cases particularly when the
// context parameter is this that we don't need the eager reporting logic.)
- lvaGenericsContextUsed = true;
+ lvaGenericsContextUseCount++;
switch (kind.runtimeLookupKind)
{
void Compiler::fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTreePtr stmtAfter)
{
+ // If this inlinee was passed a generic context but didn't look at
+ // it, we can decrement the "generic context was used" ref count.
+ if ((inlineInfo->inlineCandidateInfo->methInfo.args.callConv & CORINFO_CALLCONV_PARAMTYPE) != 0)
+ {
+ // Did the context require the caller to perform a runtime lookup?
+ if (inlineInfo->inlineCandidateInfo->exactContextNeedsRuntimeLookup)
+ {
+ // Fetch the temp for the generic context
+ const unsigned typeCtxtArg = inlineInfo->typeContextArg;
+ const unsigned tmpNum = inlineInfo->lclTmpNum[typeCtxtArg];
+
+ // Was it used in the inline body?
+ if (tmpNum == BAD_VAR_NUM)
+ {
+ // No, so the runtime lookup is not needed.
+ JITDUMP("Inlinee ignores runtime lookup generics context\n");
+ assert(lvaGenericsContextUseCount > 0);
+ lvaGenericsContextUseCount--;
+ }
+ }
+ }
+
// Null out any gc ref locals
if (!inlineInfo->HasGcRefLocals())
{
// Collectible types requires that for shared generic code, if we use the generic context parameter
// that we report it. (This is a conservative approach, we could detect some cases particularly when the
// context parameter is this that we don't need the eager reporting logic.)
- lvaGenericsContextUsed = true;
+ lvaGenericsContextUseCount++;
if (kind == CORINFO_LOOKUP_THISOBJ)
{
#endif // defined(DEBUG) || defined(INLINE_DATA)
// Is it an inline candidate?
- impMarkInlineCandidate(call, exactContextHnd, callInfo);
+ impMarkInlineCandidate(call, exactContextHnd, exactContextNeedsRuntimeLookup == TRUE, callInfo);
}
// append the call node.
#endif // defined(DEBUG) || defined(INLINE_DATA)
// Is it an inline candidate?
- impMarkInlineCandidate(call, exactContextHnd, callInfo);
+ impMarkInlineCandidate(call, exactContextHnd, exactContextNeedsRuntimeLookup == TRUE, callInfo);
}
DONE_CALL:
// Ignore the type context argument
if (hasTypeCtxtArg && (argCnt == typeCtxtArg))
{
- typeCtxtArg = 0xFFFFFFFF;
+ pInlineInfo->typeContextArg = typeCtxtArg;
+ typeCtxtArg = 0xFFFFFFFF;
continue;
}
void Compiler::impMarkInlineCandidate(GenTreePtr callNode,
CORINFO_CONTEXT_HANDLE exactContextHnd,
+ bool exactContextNeedsRuntimeLookup,
CORINFO_CALL_INFO* callInfo)
{
// Let the strategy know there's another call
// The old value should be NULL
assert(call->gtInlineCandidateInfo == nullptr);
+ // The new value should not be NULL.
+ assert(inlineCandidateInfo != nullptr);
+ inlineCandidateInfo->exactContextNeedsRuntimeLookup = exactContextNeedsRuntimeLookup;
+
call->gtInlineCandidateInfo = inlineCandidateInfo;
// Mark the call node as inline candidate.
var_types fncRetType;
CORINFO_METHOD_HANDLE ilCallerHandle; // the logical IL caller of this inlinee.
CORINFO_CONTEXT_HANDLE exactContextHnd;
+ bool exactContextNeedsRuntimeLookup;
CorInfoInitClassResult initClassResult;
};
return numberOfGcRefLocals > 0;
}
- bool thisDereferencedFirst;
+ bool thisDereferencedFirst;
+ unsigned typeContextArg;
#ifdef FEATURE_SIMD
bool hasSIMDTypeArgLocalOrReturn;
lvaRefCountingStarted = false;
lvaLocalVarRefCounted = false;
+ lvaGenericsContextUseCount = 0;
+
lvaSortAgain = false; // false: We don't need to call lvaSortOnly()
lvaTrackedFixed = false; // false: We can still add new tracked variables
// Collectible types requires that for shared generic code, if we use the generic context paramter
// that we report it. (This is a conservative approach, we could detect some cases particularly when the
// context parameter is this that we don't need the eager reporting logic.)
- lvaGenericsContextUsed = true;
+ lvaGenericsContextUseCount++;
switch (kind.runtimeLookupKind)
{