return true; // default result: addr could be null
}
-/*****************************************************************************
- * Optimize the call to the delegate constructor.
- */
+//------------------------------------------------------------------------------
+// fgOptimizeDelegateConstructor: try and optimize construction of a delegate
+//
+// Arguments:
+// call -- call to original delegate constructor
+// exactContextHnd -- [out] context handle to update
+// ldftnToken -- [in] resolved token for the method the delegate will invoke,
+// if known, or nullptr if not known
+//
+// Return Value:
+// Original call tree if no optimization applies.
+// Updated call tree if optimized.
GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
CORINFO_CONTEXT_HANDLE* ExactContextHnd,
CORINFO_RESOLVED_TOKEN* ldftnToken)
{
+ JITDUMP("\nfgOptimizeDelegateConstructor: ");
noway_assert(call->gtCallType == CT_USER_FUNC);
CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd;
CORINFO_CLASS_HANDLE clsHnd = info.compCompHnd->getMethodClass(methHnd);
targetMethodHnd = CORINFO_METHOD_HANDLE(tokenNode->gtIntCon.gtCompileTimeHandle);
}
+ // Verify using the ldftnToken gives us all of what we used to get
+ // via the above pattern match, and more...
+ if (ldftnToken != nullptr)
+ {
+ assert(ldftnToken->hMethod != nullptr);
+
+ if (targetMethodHnd != nullptr)
+ {
+ assert(targetMethodHnd == ldftnToken->hMethod);
+ }
+
+ targetMethodHnd = ldftnToken->hMethod;
+ }
+ else
+ {
+ assert(targetMethodHnd == nullptr);
+ }
+
#ifdef FEATURE_READYTORUN_COMPILER
if (opts.IsReadyToRun())
{
{
if (ldftnToken != nullptr)
{
+ JITDUMP("optimized\n");
+
GenTree* thisPointer = call->gtCallObjp;
GenTree* targetObjPointers = call->gtCallArgs->Current();
GenTreeArgList* helperArgs = nullptr;
call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, helperArgs);
call->setEntryPoint(entryPoint);
}
+ else
+ {
+ JITDUMP("not optimized, CORERT no ldftnToken\n");
+ }
}
// ReadyToRun has this optimization for a non-virtual function pointers only for now.
else if (oper == GT_FTN_ADDR)
{
+ JITDUMP("optimized\n");
+
GenTree* thisPointer = call->gtCallObjp;
GenTree* targetObjPointers = call->gtCallArgs->Current();
GenTreeArgList* helperArgs = gtNewArgList(thisPointer, targetObjPointers);
assert(!entryPoint.lookupKind.needsRuntimeLookup);
call->setEntryPoint(entryPoint.constLookup);
}
+ else
+ {
+ JITDUMP("not optimized, R2R virtual case\n");
+ }
}
else
#endif
alternateCtor = info.compCompHnd->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, &ctorData);
if (alternateCtor != methHnd)
{
+ JITDUMP("optimized\n");
// we erase any inline info that may have been set for generics has it is not needed here,
// and in fact it will pass the wrong info to the inliner code
*ExactContextHnd = nullptr;
}
call->gtCallArgs->Rest()->Rest() = addArgs;
}
+ else
+ {
+ JITDUMP("not optimized, no alternate ctor\n");
+ }
+ }
+ else
+ {
+ JITDUMP("not optimized, no target method\n");
}
return call;
}
DO_LDFTN:
op1 = impMethodPointer(&resolvedToken, &callInfo);
+
if (compDonotInline())
{
return;
}
+ // Call info may have more precise information about the function than
+ // the resolved token.
CORINFO_RESOLVED_TOKEN* heapToken = impAllocateToken(resolvedToken);
+ assert(callInfo.hMethod != nullptr);
+ heapToken->hMethod = callInfo.hMethod;
impPushOnStack(op1, typeInfo(heapToken));
break;
}
CORINFO_RESOLVED_TOKEN* heapToken = impAllocateToken(resolvedToken);
+
assert(heapToken->tokenType == CORINFO_TOKENKIND_Method);
+ assert(callInfo.hMethod != nullptr);
+
heapToken->tokenType = CORINFO_TOKENKIND_Ldvirtftn;
+ heapToken->hMethod = callInfo.hMethod;
impPushOnStack(fptr, typeInfo(heapToken));
break;